iOS - 第三方库SKPSMTPMessage的各类坑

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

基本使用:ios

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;
复制代码

1、SMTP服务器链接失败的问题

网上不少教程都是直接开启多线程发送,但经我测试行不通,没法链接服务器。git

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

复制代码

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

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

解决方法: 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];
 });
复制代码

2、开启 SMTP 服务与受权码的问题

1.发送者邮箱须要开启SMTP服务,否则邮件没法从发送方邮箱发出。async

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

2.目前广泛的一些第三方邮箱(如QQ、163邮箱等)如今都须要设置受权码才能正常发送邮件。oop

Msg.pass = @"受权码";
复制代码

这是126邮箱开启受权码的示范,在邮箱设置便可:测试

受权码.png

  1. 这里注意一下:像我使用的是公司服务器搭建的邮箱,咱们公司并无设置受权码,因此我这种状况填写邮箱密码便可。
Msg.pass = @"邮箱密码";
复制代码

3、邮件中文乱码的问题

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?=

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

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

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

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

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

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

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

myMsg.validateSSLChain = NO;//关闭证书链的验证
复制代码

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

废话很少说先上代码

//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

参考连接: jeffssss.github.io/ios/2016/01…

相关文章
相关标签/搜索