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…

相關文章
相關標籤/搜索