美文网首页iOS开发
iOS - 第三方库SKPSMTPMessage的各种坑

iOS - 第三方库SKPSMTPMessage的各种坑

作者: KeepCuriosity | 来源:发表于2019-05-20 16:21 被阅读97次

    因为最近公司业务需求,需要用到静默方式发送邮件的功能,所以接触到了SKPSMTPMessage这个第三方库。话说iOS有关SMTP封装的第三方库真的好少惹,仅有的这么一个库还年久失修,网上的资料也较少而且很多有误的,导致使用过程中真的遇到了非常多的坑,所以在这里跟大家分享一下我使用过程中遇到的问题跟解决方案,希望对大家有所帮助,如有不对的地方欢迎指正哈。比心❤️😁

    基本使用:

     SKPSMTPMessage *Msg = [[SKPSMTPMessage alloc] init];
        Msg.fromEmail = @"发件人邮箱";
        Msg.toEmail = @"收件人邮箱";
        Msg.relayHost = @"smtp.126.com";//发送邮件代理服务器(这里我用的是126邮箱做的示范)
        Msg.requiresAuth = YES;//是否需要认证(登陆)
        Msg.login = @"发件人邮箱账号";
        Msg.pass = @"密码或者授权码";//
        Msg.delegate = self;
        Msg.wantsSecure = YES;//是否用ssl
        //Msg.validateSSLChain = NO;//是否验证SSL证书
        Msg.subject = @"邮件标题";//邮件标题
        
        //1.邮件内容: 正文文字
        NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:@"text/plain; charset=UTF-8",kSKPSMTPPartContentTypeKey,
                                   @"邮件由系统自动发送,请勿回复。",kSKPSMTPPartMessageKey,@"8bit",kSKPSMTPPartContentTransferEncodingKey,nil];
        dispatch_async(dispatch_get_main_queue(), ^{
            //发送邮件
            [Msg send];
        });
    
    
    发送之后,会调用delegate方法。
    //成功,调用:
    - (void)messageSent:(SKPSMTPMessage *)message;
    //失败,调用:
    - (void)messageFailed:(SKPSMTPMessage *)message error:(NSError *)error;
    

    一、SMTP服务器连接失败的问题

    网上很多教程都是开启多线程发送邮件,这样会导致发送失败

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     [Msg send];
    });
    
    

    提示错误:SMTP服务器连接失败

    C: Attempting to connect to server at:smtp.126.com:2025**

    解决方案:
    1.需要在后面再加一个运行循环: [[NSRunLoop currentRunLoop] run];
    因为如果创建新线程,runloop不会自动运行; 我们必须手动启动,要不然重试其他端口的操作不会进行。

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
     [Msg send];
     [[NSRunLoop currentRunLoop] run];
    
     });
    

    2.或者在主线程中发送邮件

     dispatch_async(dispatch_get_main_queue(), ^{
     [myMsg send];
     });
    

    二、开启 SMTP 服务与授权码的问题

    1.发送者邮箱需要开启SMTP服务,不然邮件无法从发送方邮箱发出。

     Msg.relayHost = @"smtp.126.com";
    //发送邮件代理服务器(这里我用的是126邮箱做的示范,如果你用的是公司邮箱那就填的公司的SMTP服务器地址)
    

    2.目前普遍的一些第三方邮箱(如QQ、163邮箱等)现在都需要设置授权码才能正常发送邮件。

     Msg.pass = @"授权码";
    
    这是126邮箱开启授权码的示范,在邮箱设置即可: 授权码.png
    1. 这里注意一下:像我使用的是公司服务器搭建的邮箱,我们公司并没有设置授权码,所以我这种情况填写邮箱密码即可。
     Msg.pass = @"邮箱密码";
    

    三、邮件中文乱码的问题

    1.标题中文乱码

    导致乱码的原因是因为SKPSMTPMessage库之前使用的是ASCII的编码,所以我们把它改为utf8即可。

      //我们只需要将SKPSMTPMessage.m里以下这句代码:
    NSData *messageData = [message dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    
     //改为这句代码就好了
    NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    
    

    2.附件中文标题乱码

    这里我用发送图片附件做的示范

    代码修改前:

    UIImage *image = [UIImage imageNamed:@"WechatIMG372"];
        //图片大于1M时建议做压缩处理
    NSData *imgData = UIImageJPEGRepresentation(image,1.0f);
       
    NSDictionary *imgPart = [NSDictionary dictionaryWithObjectsAndKeys:@"image/jpg;\r\n\tx-unix-mode=0644;\r\n\tname=\"图片附件名.jpg\"",kSKPSMTPPartContentTypeKey,
                                       @"attachment;\r\n\tfilename=\"图片附件名.jpg\"",kSKPSMTPPartContentDispositionKey,[imgData encodeBase64ForData],kSKPSMTPPartMessageKey,@"base64",kSKPSMTPPartContentTransferEncodingKey,nil];
        
    

    代码修改后:

    UIImage *image = [UIImage imageNamed:@"WechatIMG372"];
        //图片大于1M时建议做压缩处理
    NSData *imgData = UIImageJPEGRepresentation(image,1.0f);
    NSString *encodeFileName = [NSString stringWithFormat:@"=?UTF-8?B?%@?=",[[@"附件标题名" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]];
        
        //解决附件中文乱码的问题
    NSDictionary *imagePart = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithFormat:@"image/jpg;\r\n\tx-unix-mode=0644;\r\n\tname=\"%@.jpg\"",encodeFileName],kSKPSMTPPartContentTypeKey,
                                   [NSString stringWithFormat:@"attachment;\r\n\tfilename=\"%@\"",encodeFileName],kSKPSMTPPartContentDispositionKey,[imgData encodeBase64ForData],kSKPSMTPPartMessageKey,@"base64",kSKPSMTPPartContentTransferEncodingKey,nil];
    
    

    可以看到以上代码重点是修改了filename,对其进行处理。
    例如:这个是邮件头的编码格式,B表示是Base64编码,UTF-8表示字符集的编码。

    =?UTF-8?B?6ZmE5Lu25qCH6aKY5ZCN?=

    使用这个就可以使附件的中文名不再乱码。

    四、证书链验证失败的问题

    在我将上面的坑都填完之后,使用第三方邮箱来收发邮箱都是没有问题的,但是在我使用公司邮箱作为发件者邮箱的时候却报了这个错误:

    error - Error Domain=NSOSStatusErrorDomain Code=-9807 "(null)" UserInfo={_kCFStreamErrorCodeKey=-9807, _kCFStreamErrorDomainKey=3}

    网上没有找到这个问题的解决方法,只有有关于9807这个错误的解释:

    1. 客户端的https证书不对
    2. 客户端的时间不对

    因为我们公司邮箱是用的自己的服务器,公司的服务器是没有做相关证书验证的,所以基本能确定是是证书的原因了。SKPSMTPMessage库里有为我们提供一个BOOL值的属性:validateSSLChain,这个属性是用来验证证书链的,默认是YES;我将他改为NO邮件就顺利发送成功了。

      myMsg.validateSSLChain = NO;//关闭证书链的验证
    

    五、如何在邮件正文里插入图片

    废话不多说先上代码

        //4.正文插入图片
        //4.1图片转base64字符串
        NSString *baseStr = [imgData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
        
        //4.2 正文文本html
        NSString *str = @"<p style=\"color:black\">正文测试测试测试</p>";
        ///</p><img src=\"data:image/png;base64," ;
        
        //4.3 图片html
        NSString *str1 = @"<img src=\"data:image/png;base64,";
        NSString *str2 = @"\" />";
        //将图片base64字符串与html标签拼接
        NSString *imgHtml = [NSString stringWithFormat:@"%@%@%@",str1,baseStr,str2];
        
        //4.4 拼接出正文加图片的html字符串
        NSString *body = [NSString stringWithFormat:@"%@%@",str,imgHtml];
        
        NSDictionary *htmlPart = [NSDictionary dictionaryWithObjectsAndKeys:@"text/html;charset=UTF-8",kSKPSMTPPartContentTypeKey,
                                  body,kSKPSMTPPartMessageKey,@"8bit",kSKPSMTPPartContentTransferEncodingKey,nil];
        Msg.parts = [NSArray arrayWithObjects:htmlPart,nil];
    

    这个问题我网上找了很久都没有找到解决方案,因为SKPSMTPMessage库part的元素字典一个key只能单独设置一种格式,像 text/plain或者image/jpg等;同时设置2个格式的话会报错,试了很多方法都不行,最后换了个思路使用text/html格式解决了这个问题。

    1.我们要把text/plain这个key替换成text / html

    //body: html文本
    NSDictionary *htmlPart = [NSDictionary dictionaryWithObjectsAndKeys:@"text/html;charset=UTF-8",kSKPSMTPPartContentTypeKey,
                              body,kSKPSMTPPartMessageKey,@"8bit",kSKPSMTPPartContentTransferEncodingKey,nil];
    
    

    2.使用html标签拼接出正文跟图片

    起初我是用富文本生成html字符串的,但是这种方式生成的html字符串发送过去显示一堆乱码,后来就直接改用html标签来实现了,实现过程有点low,大家如果有更好的实现方法也可以在评论下方告诉我。

    //1.文本html标签
    "<p style=\"color:black\">正文文本文字</p>";
    
    //2.图片html标签
    <img src="data:image/png;base64,图片base64字符串" />
    
    //3.把文本html跟图片html按照你的需求拼接即可
    
    

    3.上面代码最终实现效果:(我使用的QQ邮箱做的收件邮箱)

    邮件嵌入图片.jpeg

    参考链接:
    http://jeffssss.github.io/ios/2016/01/09/iOS-Email-chinese-character-encoding-solution.html

    相关文章

      网友评论

        本文标题:iOS - 第三方库SKPSMTPMessage的各种坑

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