4

使用 C# 讀取 Outlook .msg 檔

 3 years ago
source link: https://blog.darkthread.net/blog/convert-msg-2-html/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用 C# 讀取 Outlook .msg 檔

2020-12-15 11:30 PM 0 984

先前分享過透過 EWS 從 Exchange 收信接任務執行作業的定期排程,最近生出小副本。程式需從 Mail 取出 HTML 解析,因格式並不統一,解析邏輯需要有點彈性,以便從不同格式中取出所需資訊(類似爬網頁,考驗 HtmlAgilityPack 跟 Regular Expression 技巧)。為了確保解析結果正確,我需要大量樣本在每次調整後重新驗證,以免為了改 A 把 B 弄壞。現成樣本好找,使用者 Outlook 收件匣由就有一大堆實例,最笨但有效的做法是請使用者一封封轉寄到 Exchange 信箱,再跑程式收下來。不過,能自動化處理的事搞成手工藝不是我的風格。Outlook 裡的郵件拖到桌面或檔案總管會自動轉存成 .msg 檔,請使用者將樣本 Mail 存成 .msg 再壓成 ZIP 檔一次寄給我,不需做苦工,剩下我來處理。

Fig2_637436433773128909.gif

嘴上說得豪氣,我知道 .msg 可以用 Outlook 開啟,但要怎麼用程式讀取呀?以前沒玩過,直覺肯定有解,爬文也真找到不少選項:

由於屬一次性工作又在我的個人電腦執行就好,不想花時間研究新東西,我的電腦有現成的 Outlook,用 Outlook 解決最快。

第一步是在專案加入 COM 參照 - Microsoft Outlook 16.0 Object Library:

Fig1_637436433773984165.png

程式挺簡單,參考 MS Docs 上的範例,檢查 Outlook 是否已在執行中,若是就用現成的,否則 new Microsoft.Office.Interop.Outlook.Application() 建一個新的。 Application.Session 有個 OpenSharedItem() 方法,可用來開啟 .ics ( iCalendar 日曆數據交換約會資料)、.vcf (連絡人資訊) 或 .msg (電子郵件)。用 OpenSharedItem(.msg 路徑) 開啟 .msg 檔再轉型為 Microsoft.Office.Interop.Outlook.MailItem,接下來即可從 HtmlBody 屬性取得郵件 HTML 內容:

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace MiscTools
{
    /// <summary>
    /// 從 Outloook 郵件 .msg 檔擷取 HTML 內容
    /// </summary>
    public static class MsgHtmlExtrator
    {
        public static Dictionary<string, string> ConvToHtmls(string[] msgFilePaths)
        {
            //若 Outlook 已開啟,用現成的 Instance,否則新建
            var existing = Process.GetProcessesByName("OUTLOOK").Any();
            Outlook.Application outlookApp =
                existing ? 
                Marshal.GetActiveObject("Outlook.Application") as Outlook.Application:
                new Outlook.Application();
            var result = new Dictionary<string, string>();
            foreach (var msgFilePath in msgFilePaths)
            {
                var mail = (Outlook.MailItem)outlookApp.Session.OpenSharedItem(msgFilePath);
                result.Add(msgFilePath, mail.HTMLBody);
            }
            if (!existing) outlookApp.Quit();
            return result;
        }

        public static string ConvToHtml(string msgFilePath)
        {
            return ConvToHtmls(new string[] { msgFilePath }).First().Value;
        }

    }
}

由於啟動與執行 Outlook 成本較高,大量轉換時會採取一次傳入所有 .msg 路徑批次處理後傳回的策略,以減少資源損耗。搞定收工~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK