美文网首页MailCore 2
mailcore 2 iOS 之一 IMAP

mailcore 2 iOS 之一 IMAP

作者: YYLittleCat | 来源:发表于2018-02-02 13:57 被阅读526次

    公司开发oa中的邮箱,资源限制,最后iOS开发采用的mailcore2-ios框架。研究的不深,只当做个分享,口条不好,凑合看吧。

    安装

    我直接用的cocoapods,非常方便,只是资源包大了一点,耐心等待就好了,其他方式没试过。
    pod 'mailcore2-ios'

    https://github.com/MailCore/mailcore2 官方,有问题提issue,开发者会很热心回答的。

    更新/纠错日志
    • 2018-12-11 纠错:IMAP-4.单封邮件获取和处理.根据uid获取单封邮件 有误,range的范围应该是(uid, 0),而不是(uid, 1),这样获取到的是两封,脑子秀逗了。
    • 2018-12-11 更新:创建草稿邮件
    • 2018-12-12 更新:SMTP协议
    开发

    个人比较喜欢imap协议,功能比较丰富,不过用mailcore搞起来似乎费劲了一点,我也只是实现了一些基本功能,高级的还在研究。

    计划分享一下下面几项🤗🤗🤗🤗🤗

    • IMAP
      • 登录
      • 文件夹列表、命名空间
      • 邮件列表拉取
      • 邮件列表中单封邮件内容获取和处理
      • 邮件的各种标记添加
      • 删除邮件
      • 附件和html内容解析
      • 草稿箱邮件创建
    • POP
    • SMTP
    IMAP

    1.登录

    首先设置账号信息,也就是创建session;然后校验;

    self.imapSession.hostname = session.imapHost; //imap.xxx.com.cn
    self.imapSession.username = session.username; //littlecat@xxx.com.cn
    self.imapSession.password = session.password; //password
    self.imapSession.port     = (unsigned int)session.imapPort;//143、993
    self.imapSession.connectionType = session.imapIsSSL ? MCOConnectionTypeTLS: MCOConnectionTypeClear;//取决于你的邮件服务器是不是SSL的;
    

    校验信息:

    MCOIMAPOperation *checkOp = [session checkAccountOperation];//这里的session就是配置帐号信息的session
    [checkOp start:^(NSError *error) {
         NSLog(@"finished checking account.");
         if (error == nil) {
             complete(nil);
         } else {
             err(error);
             NSLog(@"error loading account: %@", [error userInfo][@"NSLocalizedDescription"]);
        }
    }];
    

    2.获取文件夹目录
    命名空间:它这里有个namespace,对于中文名称的📂名称,需要通过命名空间来解析,不然很可能是👇这种乱码

    //这是当时解析网易邮箱的乱码,找原因找了好久😭😭😭,在一篇博客上看到的解决办法。
    INBOX
    &g0l6P3ux-
    &XfJT0ZAB-
    &XfJSIJZk-
    &V4NXPpCuTvY-
    &dcVr0mWHTvZZOQ-
    &Xn9USpCuTvY-
    &i6KWBZCuTvY-
    Deleted Messages
    Archive
    Junk
    

    先把正确的放出来,找回点走下去的信心💔💔💗💖...

    INBOX
    草稿箱
    已发送
    已删除
    垃圾邮件
    病毒文件夹
    广告邮件
    订阅邮件
    Deleted Messages
    Archive
    Junk
    

    因为某些邮箱的session莫名其妙没有自带默认的命名空间,我采取的笨办法是先去获取一下namespace,不过嘛,,,居然获取到的也时有时无😱😱😱😱😱

    MCOIMAPSession *session = [MMIMAPTool getSession];
    MCOIMAPFetchNamespaceOperation * op = [session fetchNamespaceOperation];
    [op start:^(NSError * __nullable error, NSDictionary * namespaces) {
         MCOIMAPNamespace * namespace = (session.defaultNamespace != nil) ? session.defaultNamespace : [namespaces objectForKey:MCOIMAPNamespacePersonal];
        if (!namespace) {
            //没有命名空间,很可能文件夹的名字解析出来是乱码,这个看个人怎么处理吧;
            return ;
        }
        //如果拿到了namespace,可以安心获取folderlist了
    }];
    

    关键的一句:NSString *folername = [namespace componentsFromPath:f.path][0];

    MCOIMAPFetchFoldersOperation * ops = [session fetchAllFoldersOperation];
    [ops start:^(NSError * error,NSArray *folders) {
       if (error) {
          return ;
       }
       NSMutableDictionary *dic = [NSMutableDictionary dictionary];
       for (MCOIMAPFolder *f in folders) {
          NSString *folername = [namespace componentsFromPath:f.path][0];
          [dic setValue:f.path forKey:folername];
       }
      //继续其他处理;
    }];
    

    获取某个文件夹的mail数目等信息

    MCOIMAPFolderInfoOperation *folderInfo = [session folderInfoOperation:foldername];
    
    [folderInfo start:^(NSError *error, MCOIMAPFolderInfo *info) {
        if (error) {    
            return ;
         }
        complete(info.messageCount);
    }];
    

    3.拉取某个文件夹邮件列表

        //这里的kind我觉得是需要拉取的内容们,我是几乎大部分都down了,可以看情况自己选择;
        //拉取范围,(0,UINT64_MAX)就是都拉取了,我是10条10条的来的。
        MCOIMAPMessagesRequestKind requestKind = (MCOIMAPMessagesRequestKind)
        (MCOIMAPMessagesRequestKindHeaders |
         MCOIMAPMessagesRequestKindStructure |
         MCOIMAPMessagesRequestKindInternalDate|
         MCOIMAPMessagesRequestKindHeaderSubject |
         MCOIMAPMessagesRequestKindFlags);
    
        MCOIndexSet *uids = [MCOIndexSet indexSetWithRange:MCORangeMake(range.location, range.length)];//range控制拉取的邮件的范围,UINT64_MAX
        MCOIMAPFetchMessagesOperation *op = [session fetchMessagesOperationWithFolder:foldername requestKind:requestKind uids:uids];
        [op start:^(NSError * _Nullable error, NSArray * _Nullable messages, MCOIndexSet * _Nullable vanishedMessages) {
             NSMutableArray *listArr = [NSMutableArray array];
             NSInteger count = messages.count;
             for (int i = 0; i < count; i ++) {
                    MCOIMAPMessage *msg = messages[i];
                    //一堆属性,自己摘取吧,大多是header里的,为了显示邮件列表,邮件内容是另外单独获取的,存储也只是存储了列表;
            }
    
            //又拍了一次顺序,好像有点蠢🙄🙄🙄🙄🙄。。。我是根据uid排序的,目前还没发现乱序什么的
            NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"uid" ascending:NO];
            [listArr sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
        }];
    

    还有另外一个方法,但是实在没太搞懂里面的number参数,文档里说sequence number不能排序用,所以我没选择这个方法,主要是没懂👺👺👺👺👺👺👺

    //Returns an operation to fetch messages by (sequence) number.
    - (MCOIMAPFetchMessagesOperation *) fetchMessagesByNumberOperationWithFolder:(NSString *)folder
                                                                     requestKind:(MCOIMAPMessagesRequestKind)requestKind
                                                                         numbers:(MCOIndexSet *)numbers;
    

    4.单封邮件获取和处理

    • 根据uid获取单封邮件
    //和获取邮件列表一样,不过range的长度是0;
    MCOIndexSet *uids = [MCOIndexSet indexSetWithRange:MCORangeMake(uid, 0)];
    //之前写错了,range长度应该是0,而不是1;
    //MCOIndexSet *uids = [MCOIndexSet indexSetWithRange:MCORangeMake(uid, 1)];
    
    • 获取邮件纯文本内容(不包括html样式等)
    {
         //这里是在上一步获取单个邮件的回调内进行的
         //这个方法是自动把文本中的空行之类的去掉了,也有不去掉和可选是否去掉的方法
            MCOIMAPMessage *msg = [//上一步的message];
            MCOIMAPMessageRenderingOperation *  messageRenderingOperation = [session plainTextBodyRenderingOperationWithMessage:msg folder:foldername];
            [messageRenderingOperation start:^(NSString * plainTextBodyString,NSError * error) {
                if (error == nil) {
                    complete(plainTextBodyString, msg);
                }else{
                    NSLog(@"fetch plain text error:%@",error);
                }
            }];
    }
    
    文档里注释的不能再清楚了,自己查阅吧😈😈😈😈😈
    //Returns an operation to render the plain text version of a message.
    - (MCOIMAPMessageRenderingOperation *) plainTextRenderingOperationWithMessage:(MCOIMAPMessage *)message
                                                                           folder:(NSString *)folder;
    // All end of line will be removed and white spaces cleaned up if requested.
    - (MCOIMAPMessageRenderingOperation *) plainTextBodyRenderingOperationWithMessage:(MCOIMAPMessage *)message
                                                                               folder:(NSString *)folder
                                                                      stripWhitespace:(BOOL)stripWhitespace;
    
    • 获取html内容,放在一个webview中显示基本内容应该没问题了
    MCOIMAPMessage *msg = [同样是上一步的message];
    MCOIMAPMessageRenderingOperation *  messageRenderingOperation = [session htmlBodyRenderingOperationWithMessage:msg folder:foldername];
    [messageRenderingOperation start:^(NSString * _Nullable htmlString, NSError * _Nullable error) {
         if (error == nil) {
             complete(htmlString, msg);
         }else{
             NSLog(@"fetch plain text error:%@",error);
         }
    }];
    

    5.添加各种标记
    已读未读,小红旗标记等等。需要注意的是,“kind”区分是添加标记还是移除标记,例如已读“MCOMessageFlagSeen”标记,移除就成了未读,没有“unseen”之类的。。。

    - (void)setFlagged:(BOOL)flagged message:(NSInteger)uid folder:(NSString *)folder {
        MCOIMAPSession *session = //imap session;
        MCOIndexSet *uids = [MCOIndexSet indexSetWithIndex:uid];
        MCOIMAPOperation *op = [session storeFlagsOperationWithFolder:folder
                                                                 uids:uids
                                                                 kind:(flagged ? MCOIMAPStoreFlagsRequestKindSet : MCOIMAPStoreFlagsRequestKindRemove)
                                                                flags:MCOMessageFlagFlagged];
        [op start:^(NSError * _Nullable error) {
            NSLog(@"store star flag 's error: %@",error);
        }];
    }
    
    //如果要批量设置标记,uids可以通过range来创建
        MCOIndexSet *uids = [MCOIndexSet indexSetWithRange:MCORangeMake(range.location, range.length)];
    
    

    6.删除邮件
    为什么先说的标记那部分,因为删除邮件也是添加“delete”标记。这里需要做一个区分,要删除的邮件是不是在 “已删除/草稿箱” 这两个文件夹

    主要操作有三个:

    • 1、copy一份到“已删除”
    • 2、设置删除标记
    • 3、执行擦除expunge操作
    //**如果是不在已删除,草稿箱,执行1、2、3
    //**如果在,只执行2、3
        if (![folder isEqualToString:deleteFolder] && ![folder isEqualToString:draftFolder]) {
            //copy 一份到已删除
            MCOIMAPCopyMessagesOperation *op = [imapSession copyMessagesOperationWithFolder:folder
                                                                                                        uids:[MCOIndexSet indexSetWithIndex:uid]
                                                                                                  destFolder:deleteFolder];
            [op start:^(NSError *error, NSDictionary *uidMapping) {
                NSLog(@"Error copy message to folder:%@", error);
                [self unturnedDelete:uid folder:folder];
            }];
        }else {
            [self unturnedDelete:uid folder:folder];
        }
    
    - (void)unturnedDelete:(NSInteger)uid folder:(NSString *)folder 
    {
        //先添加删除flags
        MCOIMAPOperation * op2 = [imapSession storeFlagsOperationWithFolder:folder
                                                                                        uids:[MCOIndexSet indexSetWithIndex:uid]
                                                                                        kind:MCOIMAPStoreFlagsRequestKindSet
                                                                                       flags:MCOMessageFlagDeleted];
        [op2 start:^(NSError * error) {
            //添加成功之后对当前文件夹进行expunge操作
            MCOIMAPOperation *deleteOp = [imapSession expungeOperation:folder];
            [deleteOp start:^(NSError *error) {
                if(error) {
                    NSLog(@"Error expunging folder:%@", error);
                } else {
                    NSLog(@"Successfully expunged folder");
                }
            }];
        }];
    }
    

    7.附件处理和html内容解析

    8.创建草稿箱邮件
    “append” 拼接的概念,往一个文件夹内添加邮件;

    • 1、新建一封新邮件(SMTP中讲创建邮件)
    • 2、获取你的草稿箱文件夹名称
    • 3、执行append操作
    //这里的data就是新建的邮件;
    - (void)createDraft:(NSData *)data block:(void(^)(bool success, uint32_t uid, NSString *folder))block
    {
        if (!imapSession ) {
            return;
        }
        NSString *folder = @"Drafts" //草稿箱 ,或者是你邮箱服务器解析到的草稿箱文件夹名称;
    
        MCOIMAPAppendMessageOperation *op = [imapSession appendMessageOperationWithFolder:folder messageData:data flags:MCOMessageFlagDraft];
        [op start:^(NSError *error, uint32_t createdUID) {
            //do your operation;
            NSLog(@"create Draft message :%@",@(createdUID));
    
        }];
    }
    
    “就是这么不要脸”专用图

    相关文章

      网友评论

        本文标题:mailcore 2 iOS 之一 IMAP

        本文链接:https://www.haomeiwen.com/subject/jqifoxtx.html