需求:
最近專案裡遇到了個問題,對方沒有提供直接獲取資料來源的api介面,而是通過郵件發資料的。這就需要接收郵件後解析郵件內容獲得資料。
分析:
想在程式碼裡實時獲取郵件,可以通過郵件的幾個協議來實現,常用的幾個協議有POP3協議,SMTP協議,IAMP協議。
1. pop3:(Post Office Protocal 3),3是版本,是目前使用的主流版本。POP3是客戶-伺服器協議,其中電子郵件的接收需要一個收件伺服器,郵件下載到本地計算機上所有一次,從而使離線閱讀更輕鬆,可以指定是否保留副本的郵件在伺服器上。
2. SMTP(Simple Mail Transfer Protocal):簡單Mail傳輸協議,是個請求/響應協議,它監聽25號埠,用於接收使用者的Mail請求,並與遠端Mail伺服器建立SMTP連線。 獨立於特定的傳輸子系統,它可以是電子郵件從客戶機傳輸到伺服器;也可以是從某一個伺服器傳輸到另一個伺服器;且只需要可靠有序的資料流通道支援。SMTP 重要特性之一是其能跨越網路傳輸郵件,即SMTP 郵件中繼。通常,一個網路可以由公用網際網路上 TCP 可相互訪問的主機、防火牆分隔的 TCP/IP 網路上 TCP 可相互訪問的主機,及其它 LAN/WAN 中的主機利用非 TCP 傳輸層協議組成。使用 SMTP,可實現相同網路上處理機之間的郵件傳輸,也可通過中繼器或閘道器實現某處理機與其它網路之間的郵件傳輸。
3. IMAP ( Internet訊息訪問協議)是一種標準協議,用於訪問電子郵件從您的本地伺服器。的IMAP (最新版本的IMAP第4版)是一個客戶機/伺服器協議在電子郵件收到併為您舉行的由您的因特網伺服器。您(或您的電子郵件客戶端)可以檢視剛才的標題和發件人的信件,然後決定是否下載該郵件。您還可以建立和操縱多個資料夾或郵箱的伺服器上,刪除郵件,或尋找某些地區或整個說明。
imap協議可以實現獲取郵件狀態,並且操作伺服器上的郵件,而POP3不能,
程式設計思路是:
1 從郵件伺服器上獲取未讀郵件,
2 進行解析操作,
3 標記郵件為已讀。
4 將郵件資料推送到訊息佇列中
5 部署多個訊息佇列的消費者元件,對郵件內容進行二次處理,進行業務邏輯處理。
郵件接收的元件其實在前三步就已經結束了。 業務處理的服務可以部署多個,但是接收郵件的元件相當於一個客戶端,只作為郵件的接收和轉發資料,這裡部署了一個,屬於單點的,鑑於服務暫時沒多少壓力,先只做了異常報警通知,沒有去部署多個。
實現:
.net下有現成的開源元件LumiSoft.Net.IMAP
開源元件下載地址 http://www.lumisoft.ee/lswww/download/downloads/
整理後的主要程式碼 public void imapdemo()
{ var mailServer = "imap.exmail.qq.com";//也可以使用其他郵箱伺服器 var username = "登入賬號"; var password = "登入密碼"; using (IMAP_Client client = new IMAP_Client()) { client.Connect(mailServer, 993, true); client.Login(username, password); client.SelectFolder("INBOX");//開啟收件箱 int[] unseen_ids = client.Search(false, Encoding.UTF8, new IMAP_Search_Key_Unseen()); if (unseen_ids.Count() == 0) { return; } IMAP_t_SeqSet sequence = IMAP_t_SeqSet.Parse(string.Join(",", unseen_ids)); var items = new IMAP_t_Fetch_i[] { new IMAP_t_Fetch_i_Envelope(), new IMAP_t_Fetch_i_Uid(), new IMAP_t_Fetch_i_Flags(), new IMAP_t_Fetch_i_Flags(), new IMAP_t_Fetch_i_InternalDate(), new IMAP_t_Fetch_i_Rfc822(), new IMAP_t_Fetch_i_BodyStructure() }; client.Fetch(false, sequence, items, (s, e) => { try { var email = e.Value as IMAP_r_u_Fetch; if (email.Rfc822 != null) { email.Rfc822.Stream.Position = 0; var mine = Mail_Message.ParseFromStream(email.Rfc822.Stream); email.Rfc822.Stream.Close(); var files = mine.Attachments; var fileurls = new List<KeyValuePair<string, string>>(); foreach (var item in files) { var name = item.ContentType.Param_Name; using (MemoryStream stream = new MemoryStream(item.DataToByte())) { //附件可以上傳到阿里雲上或者其他地方 var key = "";// AliOss.Upload(stream); fileurls.Add(new KeyValuePair<string, string>(name, key));//檔名,地址 } }
//處理自定義業務邏輯 var Title = email.Envelope.Subject; var CreateTime = email.InternalDate.Date; var BodyText = mine.BodyText; var BodyHtmlText = mine.BodyHtmlText; var File = string.Join(",", fileurls.Select(x => x.Value));
//處理完的郵件標記為已讀 var sequenceSet = new IMAP_SequenceSet(); sequenceSet.Parse(string.Join(",", email.SeqNo)); client.StoreMessageFlags(false, sequenceSet, IMAP_Flags_SetType.Add, IMAP_MessageFlags.Seen);
//-------郵件內容入訊息佇列------------ } } catch (Exception ex) { throw ex; } }); } }