(一) - 郵箱收發協議
什么是POP3、SMTP和IMAP協議
電子郵件工作原理
POP3
POP3是Post Office Protocol 3的簡稱,即郵局協議的第3個版本,它規定怎樣將個人計算機連接到Internet的郵件服務器和下載電子郵件的電子協議。它是因特網電子郵件的第一個離線協議標準,POP3允許用戶從服務器上把郵件存儲到本地主機(即自己的計算機)上,同時刪除保存在郵件服務器上的郵件,而POP3服務器則是遵循POP3協議的接收郵件服務器,用來接收電子郵件的。(與IMAP有什么區別?)
SMTP
SMTP 的全稱是“Simple Mail Transfer Protocol”,即簡單郵件傳輸協議。它是一組用于從源地址到目的地址傳輸郵件的規范,通過它來控制郵件的中轉方式。SMTP 協議屬于 TCP/IP 協議簇,它幫助每臺計算機在發送或中轉信件時找到下一個目的地。SMTP 服務器就是遵循 SMTP 協議的發送郵件服務器。 SMTP 認證,簡單地說就是要求必須在提供了賬戶名和密碼之后才可以登錄 SMTP 服務器,這就使得那些垃圾郵件的散播者無可乘之機。 增加 SMTP 認證的目的是為了使用戶避免受到垃圾郵件的侵擾。
IMAP
IMAP全稱是Internet Mail Access Protocol,即交互式郵件存取協議,它是跟POP3類似郵件訪問標準協議之一。不同的是,開啟了IMAP后,您在電子郵件客戶端收取的郵件仍然保留在服務器上,同時在客戶端上的操作都會反饋到服務器上,如:刪除郵件,標記已讀等,服務器上的郵件也會做相應的動作。所以無論從瀏覽器登錄郵箱或者客戶端軟件登錄郵箱,看到的郵件以及狀態都是一致的。(與POP3有什么區別?)
網易163免費郵箱相關服務器信息:
網易郵箱已經默認開啟POP3/SMTP/IMAP服務,方便你通過客戶端更好地收發郵件,如果關閉可以通過以下方式開啟:
請登錄163郵箱,點擊頁面正上方的“設置”,再點擊左側上“POP3/SMTP/IMAP”,其中“開啟SMTP服務”是系統默認勾選開啟的。您可勾選圖中另兩個選項,點擊確定,即可開啟成功。不勾選圖中兩個選項,點擊確定,可關閉成功。** **
(二) - 各大主流郵箱服務器信息和端口號
網易163免費郵箱相關服務器信息:
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.163.com 993 143
SMTP smtp.163.com 465/994 25
POP3 pop.163.com 995 110
網易163企業郵箱相關服務器信息:(免費企業郵箱的smtp服務器名及端口號為:smtp.ym.163.com / 25)
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.qiye.163.com 993 143
SMTP smtp.qiye.163.com 994 25
POP3 pop.qiye.163.com 995 110
網易126免費郵箱相關服務器信息:
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.126.com 993 143
SMTP smtp.126.com 465/994 25
POP3 pop.126.com 995 110
騰訊QQ免費郵箱相關服務器信息:
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.qq.com 993 143
SMTP smtp.qq.com 465/587 25
POP3 pop.qq.com 995 110
騰訊QQ企業郵箱相關服務器信息:
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.exmail.qq.com 993 143
SMTP smtp.exmail.qq.com 465/587 25
POP3 pop.exmail.qq.com 995 110
谷歌Gmail郵箱相關服務器信息:
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.gmail.com 993 143
SMTP smtp.gmail.com 465 25
POP3 pop.gmail.com 995 110
Exchange郵箱相關服務器信息:(待確定)
服務器名稱 服務器地址 域 SSL
Exchange ex.xx.com xx.com
郵箱默認配置:
服務器名稱 服務器地址 SSL協議端口號 非SSL協議端口號
IMAP imap.xx.com 993 143
SMTP smtp.xx.com 465 25
POP3 pop.xx.com 995 110
(三) - MailCore2 詳細使用
簡介
MailCore是一個第三方的郵件SDK,支持POP和IMAP 方式接收郵件,以及smtp郵件發送。
安裝
從github上拉取代碼
git clone https://github.com/MailCore/mailcore2/添加到項目中
把build-mac/mailcore2.xcodeproj拖進工程在項目中添加靜態庫鏈接
選中工程--TARGETS--Build Phases
在 Link Binary With Libraries 中添加:
libMailCore-ios.a
CFNetwork.framework
Security.framework
在 Target Dependencies 中選擇:
static maincore2 ios
- 設置Flags
選中工程--TARGETS--Build Setting
在 Other Linker Flags 中設置
-lctemplate-ios -letpan-ios -lxml2 -lsasl2 -liconv -ltidy -lz -lc++ -stdlib=libc++ -ObjC -lresolv
在 C++ Standard Library 中設置
libc++
然后選擇相應 Target 編譯。
SMTP(Simple Mail Transfer Protocol)
- 先創建MCOSMTPSession,配置smtp郵箱參數
MCOSMTPSession *smtpSession = [[MCOSMTPSession alloc] init];
smtpSession.hostname = @"smtp.exmail.qq.com";
smtpSession.port = 587;
smtpSession.username = @"hello@qq.com";
smtpSession.password = @"passward";
smtpSession.connectionType = MCOConnectionTypeStartTLS;
MCOSMTPOperation *smtpOperation = [self.smtpSession loginOperation];
[smtpOperation start:^(NSError * error) {
if (error == nil) {
NSLog(@"login account successed");
} else {
NSLog(@"login account failure: %@", error);
}
}];
- 使用MCOMessageBuilder構建郵件體的發送內容
// 構建郵件體的發送內容
MCOMessageBuilder *messageBuilder = [[MCOMessageBuilder alloc] init];
messageBuilder.header.from = [MCOAddress addressWithDisplayName:@"張三" mailbox:@"111111@qq.com"]; // 發送人
messageBuilder.header.to = @[[MCOAddress addressWithMailbox:@"222222@qq.com"]]; // 收件人(多人)
messageBuilder.header.cc = @[[MCOAddress addressWithMailbox:@"@333333qq.com"]]; // 抄送(多人)
messageBuilder.header.bcc = @[[MCOAddress addressWithMailbox:@"444444@qq.com"]]; // 密送(多人)
messageBuilder.header.subject = @"測試郵件"; // 郵件標題
messageBuilder.textBody = @"hello world"; // 郵件正文
/*
如果郵件是回復或者轉發,原郵件中往往有附件以及正文中有其他圖片資源,
如果有需要你可將原文原封不動的也帶過去,這里發送的正文就可以如下配置
*/
NSString * bodyHtml = @"<p>我是原郵件正文</p>";
NSString *body = @"我是郵件回復的內容";
NSMutableString*fullBodyHtml = [NSMutableString stringWithFormat:@"%@<br/>-------------原始郵件-------------<br/>%@",[body stringByReplacingOccurrencesOfString:@"\n"withString:@"<br/>"],bodyHtml];
[messageBuilder setHTMLBody:fullBodyHtml];
// 添加正文里的附加資源
NSArray *inattachments = msgPaser.htmlInlineAttachments;
for (MCOAttachment*attachmentininattachments) {
[messageBuilder addRelatedAttachment:attachment]; //添加html正文里的附加資源(圖片)
}
// 添加郵件附件
for (MCOAttachment*attachmentinattachments) {
[builder addAttachment:attachment]; //添加附件
}
- 將構建好的郵件發送出去
// 發送郵件
NSData * rfc822Data =[messageBuilder data];
MCOSMTPSendOperation *sendOperation = [self.smtpSession sendOperationWithData:rfc822Data];
[sendOperation start:^(NSError *error) {
if (error == nil) {
NSLog(@"send message successed");
} else {
NSLog(@"send message failure: %@", error);
}
}];
IMAP(Internet Mail Access Protocol)
- 先創建MCOIMAPSession,配置imap郵箱參數
MCOIMAPSession *imapSession = [[MCOIMAPSession alloc] init];
imapSession.hostname = hostname;
imapSession.port = port;
imapSession.username = username;
imapSession.password = passward;
imapSession.connectionType = MCOConnectionTypeTLS;
MCOIMAPOperation *imapOperation = [imapSession checkAccountOperation];
[imapOperation start:^(NSError * __nullable error) {
if (error == nil) {
NSLog(@"login account successed\n");
// 在這里獲取郵件,獲取文件夾信息
[self loadIMAPFolder];
} else {
NSLog(@"login account failure: %@\n", error);
}
}];
- 獲取文件夾目錄
MCOIMAPFetchFoldersOperation *imapFetchFolderOp = [imapSession fetchAllFoldersOperation];
[imapFetchFolderOp start:^(NSError * error, NSArray * folders) {
[_folderList addObjectsFromArray:folders];
[_folderTableView reloadData];
}];
- 獲取收件箱郵件
MCOIMAPMessagesRequestKind requestKind = (MCOIMAPMessagesRequestKind)
(MCOIMAPMessagesRequestKindHeaders | MCOIMAPMessagesRequestKindStructure |
MCOIMAPMessagesRequestKindInternalDate | MCOIMAPMessagesRequestKindHeaderSubject |
MCOIMAPMessagesRequestKindFlags);
// 獲取收件箱信息(包含郵件總數等信息)
NSString *folderName = @"INBOX";
MCOIMAPFolderInfoOperation * folderInfoOperation = [imapSession folderInfoOperation:folderName];
[folderInfoOperation start:^(NSError *error, MCOIMAPFolderInfo * info) {
NSLog(@"total number: %d", info.messageCount);
NSInteger numberOfMessages = 10;
numberOfMessages -= 1;
MCOIndexSet *numbers = [MCOIndexSet indexSetWithRange:MCORangeMake([info messageCount] - numberOfMessages, numberOfMessages)];
MCOIMAPFetchMessagesOperation *imapMessagesFetchOp = [imapSession fetchMessagesByNumberOperationWithFolder:folderName
requestKind:requestKind
numbers:numbers];
// 異步獲取郵件
[imapMessagesFetchOp start:^(NSError *error, NSArray *messages, MCOIndexSet *vanishedMessages) {
[_messageList addObjectsFromArray:messages];
[_messageTableView reloadData];
}];
}];
- 獲取郵件頭
// 拿出一個郵件MCOIMAPMessage(里面包含郵件頭等信息)
MCOIMAPMessage *message = _messageList [0];
// 使用MCOIMAPMessageRenderingOperation來獲得郵件概要信息
NSString *uidKey = [NSString stringWithFormat:@"%d", message.uid];
MCOIMAPMessageRenderingOperation *messageRenderingOperation = [imapSession plainTextBodyRenderingOperationWithMessage:message folder:@"INBOX"];
[messageRenderingOperation start:^(NSString * plainTextBodyString,NSError * error) {
// plainTextBodyString為郵件的正文文本信息
}];
- 獲取郵件內容,用MCOMessageParser解析郵件
MCOIMAPFetchContentOperation * fetchContentOp = [self.imapSession fetchMessageOperationWithFolder:@"INBOX" uid:[message uid]];
[fetchContentOp start:^(NSError * error, NSData * data) {
if ([error code] != MCOErrorNone) {
return;
}
// 解析郵件內容
MCOMessageParser * msgPareser = [MCOMessageParser messageParserWithData:data];
NSString *content = [msgPareser htmlRenderingWithDelegate:self];
POP(Post Office Protocol)
- 先創建MCOIMAPSession,配置imap郵箱參數
MCOPOPSession *popSession = [[MCOPOPSession alloc] init];
popSession.hostname = @"smtp.exmail.qq.com";
popSession.port = 995;
popSession.username = @"hello@qq.com";
popSession.password = @"passward";
popSession.connectionType = MCOConnectionTypeTLS;
// 登錄郵箱
MCOPOPOperation *popOperation = [popSession checkAccountOperation];
[popOperation start:^(NSError * __nullable error) {
if (error == nil) {
NSLog(@"login account successed");
} else {
NSLog(@"login account failure: %@", error);
}
}];
- 獲取郵件信息(同IMAP)
- 關于MCOMessageParser
不管是pop還是IMAP獲取的郵件,最后都要得到MCOMessageParser來操作郵件內容。
// MCOMessageHeader包含了郵件標題,時間等頭信息
MCOMessageHeader *header = msgPaser.header;
// 獲得郵件正文的HTML內容,一般使用webView加載
NSString * bodyHtml = [msgPaser htmlBodyRendering];
// 獲取附件(多個)
NSMutableArray *attachments = [[NSMutableArray alloc] initWithArray:_msgPaser.attachments];
// 拿到一個附件MCOAttachment,可從中得到文件名,文件內容data
MCOAttachment *attachment = attachments[0];
將附件寫入本地
// 獲取文件路徑
NSString *tmpDirectory = NSTemporaryDirectory();
NSString *filePath = [tmpDirectorystringByAppendingPathComponent : attachment.filename ];
[attachmentData writeToFile:filePathatomically:YES];
當郵件正文有圖片,在webview中如何加載圖片,可通過注入js的方式修改html
定義腳本:
static NSString * mainJavascript = @"\
var imageElements = function() {\
var imageNodes = document.getElementsByTagName('img');\
return [].slice.call(imageNodes);\
};\
\
var findCIDImageURL = function() {\
var images = imageElements();\
\
var imgLinks = [];\
for (var i = 0; i < images.length; i++) {\
var url = images[i].getAttribute('src');\
if (url.indexOf('cid:') == 0 || url.indexOf('x-mailcore-image:') == 0)\
imgLinks.push(url);\
}\
return JSON.stringify(imgLinks);\
};\
\
var replaceImageSrc = function(info) {\
var images = imageElements();\
\
for (var i = 0; i < images.length; i++) {\
var url = images[i].getAttribute('src');\
if (url.indexOf(info.URLKey) == 0) {\
images[i].setAttribute('src', info.LocalPathKey);\
break;\
}\
}\
};\
";
修改剛才獲取的html內容
MCOMessageParser * msgPareser = [MCOMessageParser messageParserWithData:data];
NSString *content = [msgPareser htmlRenderingWithDelegate:self];
NSMutableString * html = [NSMutableString string];
[html appendFormat:@"<html><head><script>%@</script></head>"
@"<body>%@</body><iframe src='x-mailcore-msgviewloaded:' style='width: 0px; height: 0px; border: none;'>"
@"</iframe></html>", mainJavascript, content];
[_webView loadHTMLString:content baseURL:nil];
設置webView代理
#pragma mark - webview
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURLRequest *responseRequest = [self webView:webView resource:nil willSendRequest:request redirectResponse:nil fromDataSource:nil];
if(responseRequest == request) {
return YES;
} else {
[webView loadRequest:responseRequest];
return NO;
}
}
- (NSURLRequest *)webView:(UIWebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(id)dataSource {
if ([[[request URL] scheme] isEqualToString:@"x-mailcore-msgviewloaded"]) {
[self _loadImages];
}
return request;
}
// 加載網頁中的圖片
- (void) _loadImages {
NSString * result = [webView stringByEvaluatingJavaScriptFromString:@"findCIDImageURL()"];
NSLog(@"-----加載網頁中的圖片-----");
NSLog(@"%@", result);
if (result == nil || [result isEqualToString:@""]) {
return;
}
NSData * data = [result dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSArray * imagesURLStrings = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
for (NSString * urlString in imagesURLStrings) {
MCOAbstractPart * part = nil;
NSURL *url = [NSURL URLWithString:urlString];
if ([MCOCIDURLProtocol isCID:url]) {
part = [self _partForCIDURL:url];
}
else if ([MCOCIDURLProtocol isXMailcoreImage:url]) {
NSString * specifier = [url resourceSpecifier];
NSString * partUniqueID = specifier;
part = [self _partForUniqueID:partUniqueID];
}
if (part == nil) {
continue;
}
NSString * partUniqueID = [part uniqueID];
MCOAttachment * attachment = (MCOAttachment *) [msgPaser partForUniqueID:partUniqueID];
NSData * data =[attachment data];
if (data!=nil) {
//獲取文件路徑
NSString *tmpDirectory =NSTemporaryDirectory();
NSString *filePath=[tmpDirectory stringByAppendingPathComponent : attachment.filename ];
NSFileManager *fileManger=[NSFileManager defaultManager];
if (![fileManger fileExistsAtPath:filePath]) {
//不存在就去請求加載
NSData *attachmentData=[attachment data];
[attachmentData writeToFile:filePath atomically:YES];
NSLog(@"資源:%@已經下載至%@", attachment.filename,filePath);
}
NSURL * cacheURL = [NSURL fileURLWithPath:filePath];
NSDictionary * args =@{@"URLKey": urlString,@"LocalPathKey": cacheURL.absoluteString};
NSString * jsonString = [self _jsonEscapedStringFromDictionary:args];
NSString * replaceScript = [NSString stringWithFormat:@"replaceImageSrc(%@)", jsonString];
[webView stringByEvaluatingJavaScriptFromString:replaceScript];
}
}
}
- (NSString *)_jsonEscapedStringFromDictionary:(NSDictionary *)dictionary {
NSData * json = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil];
NSString * jsonString = [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding];
return jsonString;
}
- (NSURL *) _cacheJPEGImageData:(NSData *)imageData withFilename:(NSString *)filename {
NSString * path = [[NSTemporaryDirectory()stringByAppendingPathComponent:filename]stringByAppendingPathExtension:@"jpg"];
[imageData writeToFile:path atomically:YES];
return [NSURL fileURLWithPath:path];
}
- (MCOAbstractPart *) _partForCIDURL:(NSURL *)url {
return [_message partForContentID:[url resourceSpecifier]];
}
- (MCOAbstractPart *) _partForUniqueID:(NSString *)partUniqueID {
return [_message partForUniqueID:partUniqueID];
}