IOS郵箱開發

(一) - 郵箱收發協議

什么是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免費郵箱相關服務器信息:

163免費郵客戶端設置的POP3、SMTP、IMAP地址

網易郵箱已經默認開啟POP3/SMTP/IMAP服務,方便你通過客戶端更好地收發郵件,如果關閉可以通過以下方式開啟:

請登錄163郵箱,點擊頁面正上方的“設置”,再點擊左側上“POP3/SMTP/IMAP”,其中“開啟SMTP服務”是系統默認勾選開啟的。您可勾選圖中另兩個選項,點擊確定,即可開啟成功。不勾選圖中兩個選項,點擊確定,可關閉成功。** **

什么是POP3、SMTP和IMAP?

(二) - 各大主流郵箱服務器信息和端口號

網易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郵件發送。
安裝

  1. 從github上拉取代碼
    git clone https://github.com/MailCore/mailcore2/

  2. 添加到項目中
    把build-mac/mailcore2.xcodeproj拖進工程

  3. 在項目中添加靜態庫鏈接
    選中工程--TARGETS--Build Phases
    在 Link Binary With Libraries 中添加:

libMailCore-ios.a  
CFNetwork.framework  
Security.framework  

在 Target Dependencies 中選擇:

static maincore2 ios

  1. 設置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)

  1. 先創建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);  
    }  
}];  
  1. 使用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];    //添加附件  
}  
  1. 將構建好的郵件發送出去
// 發送郵件  
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)
  1. 先創建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);  
    }  
}];  
  1. 獲取文件夾目錄
MCOIMAPFetchFoldersOperation *imapFetchFolderOp = [imapSession fetchAllFoldersOperation];  
[imapFetchFolderOp start:^(NSError * error, NSArray * folders) {  
    [_folderList addObjectsFromArray:folders];  
    [_folderTableView reloadData];  
}];  
  1. 獲取收件箱郵件
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];  
    }];  
}];  
  1. 獲取郵件頭
// 拿出一個郵件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為郵件的正文文本信息  
      
}];  
  1. 獲取郵件內容,用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)
  1. 先創建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);  
    }  
}];  
  1. 獲取郵件信息(同IMAP)
  2. 關于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];  
}  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容