由於最近公司業務需求,須要用到靜默方式發送郵件的功能,因此接觸到了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;
複製代碼
網上不少教程都是直接開啓多線程發送,但經我測試行不通,沒法鏈接服務器。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];
});
複製代碼
1.發送者郵箱須要開啓SMTP服務,否則郵件沒法從發送方郵箱發出。async
Msg.relayHost = @"smtp.126.com";
//發送郵件代理服務器(這裏我用的是126郵箱作的示範,若是你用的是公司郵箱那就填的公司的SMTP服務器地址)
複製代碼
2.目前廣泛的一些第三方郵箱(如QQ、163郵箱等)如今都須要設置受權碼才能正常發送郵件。oop
Msg.pass = @"受權碼";
複製代碼
這是126郵箱開啓受權碼的示範,在郵箱設置便可:測試
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這個錯誤的解釋:
由於咱們公司郵箱是用的本身的服務器,公司的服務器是沒有作相關證書驗證的,因此基本能肯定是是證書的緣由了。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郵箱作的收件郵箱)