mailcore 2 iOS 之一 IMAP

公司开发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));

    }];
}
“就是这么不要脸”专用图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • (一) - 邮箱收发协议 什么是POP3、SMTP和IMAP协议 电子邮件工作原理 POP3 POP3是Post ...
    颜值不够才华来凑阅读 5,804评论 7 14
  • 1 小区门口新开了家原汤牛肉粉面店。 在我们大洞口,人们有个习惯,哪里开了家新店,都喜欢去吃个新鲜。吃完之后做一番...
    平溪江渔夫阅读 439评论 0 1
  • 不工作的日子,每天在家就是锁碎的日常,每天收拾卫生,伺候两个孩子的日常起居,还有鼓捣点自己喜欢的手工。每天大多数时...
    铜豌豆xyn阅读 171评论 1 1
  • 1 二年级时,教我们的是一个漂亮的插队知青——贾老师。两条长长的辫子垂在腰间,眉眼如画,笑靥如花。贾老师口中总有那...
    荆芥草阅读 976评论 7 8
  • 1. “我讲个哭话,你可别笑。” 唐恕和明鸢坐在电影院里拉着手,今天上映的这部电影叫《驴没水》,据说是一部黑色讽刺...
    骁儿阅读 664评论 2 1