如何解析EML(郵件)格式的文件以及一款小巧的EML郵件閱讀工具

在理解EML格式的時候,先回顧一下歷史,這樣有助於理解郵件的格式,比如郵件傳輸時為何會有多種編碼方式。此外,理解EML格式也有助於理解HTTP協議。

歷史溯源

由於歷史原因,我們目前看到的大部分的網絡協議都是基於ASCII碼這種純文本方式,也就是基於字符串的命令行方式,比如HTTP、FTP、POP3、SMTP、TELNET等。

早期操作系統比如Unix或DOS沒有圖形界面,用戶與電腦之間隻能通過控制臺進行交互,也就是通過鍵盤將命令(或請求)輸入到電腦,當用戶回車換行(rn)時,表示命令輸入完畢。如果存在網絡通信,則該命令包括用戶敲擊的回車換行會一並發送到服務器端,服務器端接收數據時,就會以回車換行來界定一條完整的命令是否獲取完畢,否則會繼續等待直到接收到"rn"或超時,當請求接收完畢後,服務端會執行該請求並將響應結果返回給客戶端。

理解這一點非常重要,這就是為什麼很多網絡應用層協議都是以"rn"來作為結束標記。對於多行請求時,通常以兩個連續的回車換行表示請求結束,也就是"rnrn",直觀的用肉眼觀察就是存在一個空行。

比如HTTP協議,與主機建立連接後,輸入"GET / HTTP/1.1rnrn"即可獲取網站的主頁。

回到Email協議(SMTP和POP3),早期的電子郵件隻支持ASCII碼這種純文本傳輸方式,但隨著全世界人民對物質文化生活的不斷向往,這種落後的傳輸方式,已經無法滿足世界人民對美好生活的追求,比如圖像、視頻、音頻、Office文件如何在郵件中展現?不同國傢(非英語國傢)字符集該如何傳輸和展現?

換句話說,就是這種非ASCII的二進制富文本,該如何傳輸和呈現?

MIME的誕生

此時MIME標準誕生瞭,MIME的出現更多的是一種向下兼容的無奈,而不是革命。通過對二進制數據或非ASCII碼數據進行base64或quoted-printable編碼,來實現純ASCII碼的傳輸。顯然這種方式會讓你的郵件體變大,傳輸效率下降。尤其附件很多時,通過MIME的boundary來解析郵件的附件也是一筆額外的負擔。

同時MIME的標準也被HTTP協議所采用,我們可以通過content-type字段指定傳輸的內容是什麼類型,通過MIME的boundary來對Form-Data數據進行擴展,讓我們在POST數據時也能夠在“表格”數據中插入文件,從而達到上傳文件的效果。

下面是一個EML格式的文件截圖,該截圖是一個郵件頭,該郵件頭包含幾個重要字段,Subject(主題),From(發件人)To(接收人),Cc(抄送人),Date(發送日期)。

其中一個最重要的字段就是Content-Type。隻有解析瞭Content-type字段我們才能準確的將郵件體給解析並展現出來。

通過上圖我們可以觀察到該郵件的內容是一個混合類型,由多個部分組成,Content-type字段中的boundary被用來分割不同的部分。下圖顯示的是一個郵件的附件文件,該文件類型為pdf。

boundary的前綴加上"–"表示新的郵件內容的開始,緊接著為幾行MIME頭,仔細觀察MIME頭則會發現,這些字段其實和HTTP協議的頭的字段是相同的。空行後則是具體的郵件內容,這些郵件內容的傳輸編碼方式有兩種:一種是base64,一種是quoted-printale,當然也可能是未編碼。通常情況下,采用quoted-printable方式對HTML(郵件正文)進行編碼,而對於附件文件(比如二進制文件),則采用base64進行編碼。

郵件的正文可能有兩個:一個是HTML格式,一個是Plain格式。為什麼會有兩個格式的正文?其實這兩個格式展現出來的內容都是一樣的,這樣做的目的是為瞭客戶端的兼容,早期的的郵件客戶端可能無法顯示HTML格式,或者對HTML格式的兼容性不是很好,當然嘍這也是歷史原因造成的。現在的郵件客戶端都能顯示HTML的正文瞭。

當郵件結束時,是以"–"+boundary+"–"來標記,也就是給boundary加上前綴"–"和後綴"–"。

通過對MIME格式的分析我們可以看到解析Content-type字段很重要,通過提取boundary並循環查找,就可以解析出不同的郵件體,從而將一封EML格式的電子郵件展現出來。

最後註意一點: MIME頭中字符串采用特有的簡潔的編碼方式,將字符集和編碼方式集成到瞭一起,以”=?“開始,以”?=“結束。”=?“後為字符集,緊接著”?"後表示編碼方式。B(b)為base64編碼,Q(q)為quoted-printable編碼。如下圖:

附:一款小巧的EML郵件閱讀工具(不到300K)

赞(0)