.msg 檔是什麼?格式解析
從技術角度解析 Outlook 的 .msg 格式:OLE2 容器、MAPI 屬性資料流、內文的儲存方式,以及為什麼其他軟體讀不了它。
.msg 是 Microsoft Outlook 用來把單一項目存成獨立檔案的格式。雖然名字 叫 msg,它裝的不只是郵件 —— 從 Outlook 存出的約會、聯絡人、工作、記事與會議邀請, 產生的都是 .msg 檔。
外層容器:Compound File Binary Format
.msg 本質上是一個 OLE2 複合文件 —— 等於在單一檔案 裡塞了一套小型檔案系統,有目錄(storage)也有檔案(stream)。這類檔案開頭一定 是同樣的八個簽章位元組 D0 CF 11 E0 A1 B1 1A E1,因此就算副檔名被改過, 解析器依然認得出來。
舊版的 .doc、.xls、.ppt 用的是同一種容器, 差別在於內部資料流的命名與意義 —— .msg 的部分由 [MS-OXMSG] 規格定義。
裡面存了什麼
每個郵件屬性各自存成一個資料流,名稱就是 MAPI 屬性標籤(16 位元屬性編號 + 16 位元 型別)。例如:
| 屬性 | 標籤 | 內容 |
|---|---|---|
| PidTagSubject | 0037001F | 主旨 |
| PidTagBody | 1000001F | 純文字內文 |
| PidTagHtml | 10130102 | HTML 內文(原始位元組) |
| PidTagRtfCompressed | 10090102 | 壓縮過的 RTF 內文 |
| PidTagSenderEmailAddress | 0C1F001F | 寄件者位址 |
收件者與附件則不是屬性,而是子儲存區 —— 例如 __recip_version1.0_#00000000 與 __attach_version1.0_#00000000 —— 各自內部再放自己的屬性資料流。
內文的三種存法
這正是多數簡易檢視器出錯的地方,也是同一個檔案在某個工具裡完美、在另一個工具裡 卻空白的原因。Outlook 可能把內文存成:
- 純文字,放在
PidTagBody。 - HTML,放在
PidTagHtml,是必須依PidTagInternetCodepage指定的字碼頁去解碼的原始位元組。 一律當成 UTF-8 解碼,正是中文、日文、韓文、西里爾文與希臘文郵件變成亂碼的主因。 - 壓縮 RTF,放在
PidTagRtfCompressed。當原始郵件 是 HTML 時,Outlook 會依 [MS-OXRTFEX] 規格把 HTML 封裝進 RTF 裡。要還原就得先解壓縮,再處理\htmltag與\htmlrtf控制字進行反封裝。跳過這一步的檢視器,在相當比例的真實 Outlook 郵件上都會顯示 空白內文。
內嵌圖片與 cid: 參照
出現在內文中的圖片,其實是帶有 PidTagAttachContentId 的一般附件, HTML 內文再以 <img src="cid:image001.png@01D9…"> 參照它們。 檢視器必須把每個 cid: 對應回附件並換成可用的網址,否則簽名檔與 公司 logo 的位置就只會剩下破圖圖示。
為什麼其他軟體不支援
微軟雖然公開了規格,卻從未把它推為交換標準;而且格式中編入了大量 Exchange 專屬 概念 —— legacy DN、投票按鈕、委派資訊、訊息類別 —— 在標準網際網路郵件中根本沒有 對應物。要支援它就等於實作一份微軟規格,對競爭者自家格式毫無好處,所以幾乎沒人做。
標準的替代方案是純文字的 .eml。可以 比較兩種格式,看看轉檔會得到什麼、失去什麼。