Foxmail 作為國內早期最受歡迎的郵件客戶端,功能早已超越 Outlook,但在郵件備份與導出方面卻存在明顯短板:僅支援手動逐封導出。當郵件量達到成百上千封時,這種方式顯然無法滿足需求。本文將深入分析 Foxmail 郵件夾文件結構,並提供一套基於 VC++ 的自動化批量導出解決方案,可將指定郵件夾中所有郵件一次性導出為 .eml 格式,極大提升備份效率。
要實現程式化處理,首先必須掌握 Foxmail 的存儲機制。進入 Foxmail 安裝目錄,發送一封測試郵件給自己並接收後,觀察文件時間屬性變化。經分析發現:
fmnmtk.dat 雖更新但體積極小,非郵件主體存儲文件mail 子目錄對應各賬號in、out、send、trash 分別對應收件箱、發件箱、已發送、垃圾箱進一步以二進制編輯器打開郵件夾文件(如 in),發現文件開頭存在規律性的十六進制序列:
10 10 10 10 10 10 10 11 11 11 11 11 11 53 0D 0A 52 65 74 75 72 6E 2D 50 61 74 68 3A 20 3C 7A 68
在文件中搜尋前 13 個字節(7 個 0x10 + 6 個 0x11)可發現多處匹配,且緊隨其後的 53 0D 0A(即 "S\r\n")固定出現。經驗證,這 16 字節序列 「10 10 10 10 10 10 10 11 11 11 11 11 11 53 0D 0A」 正是單封郵件的格式頭,而非文件頭(文件頭僅出現一次)。搜尋該特徵碼出現次數與郵件夾實際郵件數完全吻合,增刪郵件後計數同步變化,確認該判斷準確。
掌握郵件邊界特徵後,提取邏輯變得清晰:掃描文件尋找格式頭,以此分割並導出各郵件。核心程式碼採用流式讀寫,避免大文件佔用過多記憶體:
// 從郵件夾文件讀取字符
c = fgetc(fp1);
while (!feof(fp1)) {
// 發現分隔特徵串開頭字符 0x10,進入 check() 驗證
if (c == 0x10) check();
// 生成導出文件名(遞增編號)
j++;
filename.Format("%d", j);
// 確定導出路徑:程式所在目錄下的 mail 子目錄
char exeFullPath[MAX_PATH];
CString strPath;
GetModuleFileName(NULL, exeFullPath, MAX_PATH);
strPath = CString(exeFullPath);
strPath = strPath.Left(strPath.ReverseFind('\\'));
strPath = strPath + "\\mail\\" + CString(filename) + ".eml";
strcpy(fullname, strPath);
// 以寫入方式開啟/建立導出文件
fp2 = fopen(fullname, "w");
// 非格式頭字符且未到文件末尾,寫入當前導出文件
while (!feof(fp1) && (c = fgetc(fp1)) != 0x10)
fputc(c, fp2);
}
check() 函數負責嚴格驗證後續 15 字節是否完全符合格式頭規範:
for (int i = 0; i < 6; i++) {
c = fgetc(fp1);
if (c != 0x10) return; // 不符合則視為郵件內容
}
for (i = 0; i < 6; i++) {
c = fgetc(fp1);
if (c != 0x11) return;
}
if ((c = fgetc(fp1)) == 0x53)
if ((c = fgetc(fp1)) == 0x0D)
if ((c = fgetc(fp1)) == 0x0A) {
c = fgetc(fp1);
// 完全匹配:關閉上一封郵件輸出文件
fclose(fp2);
}
考慮到批量處理數據量大,建議將此流程放入工作執行緒避免 UI 阻塞。實測導出的 .eml 文件可被 Outlook 完美識別並開啟,達到預期目標。
本方案通過底層文件結構分析實現 Foxmail 郵件批量導出,解決了官方客戶端無法批量備份的痛點。經測試支援 Foxmail 4.2 及更早版本,在 Windows 2000 Professional + Visual C++ 6.0 環境下編譯通過。該工具不僅適合個人郵件歸檔,亦可作為企業郵件合規歸檔的輕量級輔助方案。