Outlook 的收件匣規則應該很多人用過,它能依據事先設定條件,將特定發信者寄來或主旨包含特定關鍵字的信件移到指定資料夾、自動轉寄,甚至直接刪除,當信如潮水般湧來時,至少有基本的分類,還可加上簡單的自動化處理,是常身陷 Email 地獄社畜們的一大救贖。

我有個困擾,信箱會收到大大小小系統自動寄發的通知,有些系統的做法非常簡單粗暴,一筆事件發一封,內容是近似原始 Log 的未排版文字,有些狀況一次會觸發數十上百個事件,於是 Outlook 就會迎來一波信件轟炸,因通知中可能包含重要訊息,不能置之不理,一封封看頗為煩人,也很沒效率。

當然,根本解決之道是從源頭下手,改變通知寄發頻率(例如:將五分鐘的事件彙整成一封)與訊息格式(例如:從 Log 文字擷取關鍵欄位重新排版),就能有效改善問題。不過,大家都知道,既然系統不歸自己管,這種「不方便但堪用」的小問題多半會被擺著,很難等到優化改善的一天,求人不如求己,還是想想如何自力救濟比較實際。

我先想到的做法是用寫個排程作業,定期讓 C# 程式存取 Outlook 掃收件匣(跑程式操作 Outlook 的概念可參考PowerShell 實用技巧 - 借用 Outlook 寄送電子郵件),挑出系統通知信進行彙整、取出關鍵資訊做成彙總表格另寄一封。定期輪詢簡單歸簡單,但沒啥效率,每次要重新掃瞄最近一段時間的所有來信,掃瞄頻率訂得低即時性不夠、掃瞄範圍太小怕遺漏,太頻繁範圍太大又浪費資源,很難做到優雅。

於是我想到,能不能在收件匣規則將動作設定執行 VBA 巨集?這樣就能加入天馬行空的自訂邏輯,擴充沒有極限! 查了一下,Outlook 的規則動作支援「執行指令碼」,可指定由巨集函數處理新信件。

但這個功能預設被停用,不會出現在動作清單,需加入 Registry HKCU\Software\Microsoft\Office\1x.0\Outlook\Security\EnableUnsafeClientMailRule DWORD 0x1 啟用:

至於 VBA 程式部分,則要宣告一個 Sub 方法接收 MailItem 物件參數,該物件即為新收到的信件,由 Subject、Body 可取得信件主旨、內文... 等,後續如果應用可自由發揮。

好久沒寫 VBA,想起它連 try ... catch 都沒有,流下兩行清淚,有穿越回石器時代的感覺。立即決定寫個 ASP.NET Core Minimal API 把主戰場拉回 21 世紀,在 VBA 設法組出 HTTP POST application/x-www-form-urlencoded 內容,將資料交給現代化科技後速速逃離。(VBA 甚至沒有現成程式庫可以 UrlEncode,我參考網路做法,借用 HTML DOM 跑 JavaScript encodeURIComponent(),又學到一招)

Sub ProcessQRNotify(item As Outlook.MailItem)
    On Error GoTo ErrHandle
    Dim mailBody As String
    Dim url As String
    url = "http://localhost:8888/new-event"
    mailBody = item.Body
    Dim xhr
    Set xhr = CreateObject("WinHttp.WinHttpRequest.5.1")
    xhr.Open "POST", url, False
    xhr.SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    Dim mailId As String
    xhr.Send "entryId=" & item.EntryID & "&alertContent=" & UrlEncode(mailBody)
    If (xhr.ResponseText = "OK") Then
        ''Success
    Else
        ''Fallback
    End If
    Exit Sub
ErrHandle:
    MsgBox Err.Description
End Sub

Function UrlEncode(t As String)
    Dim html
    Set html = CreateObject("htmlfile")
    With html.parentWindow
        .ExecScript "function encode(s) { return encodeURIComponent(s); }", "JScript"
    End With
    UrlEncode = html.parentWindow.encode(t)
End Function

簡單試出 PoC,看來是可行的。未來遇到雜亂的摻水的系統通知,都可以用這招提取信件內容上傳到 Web API 後製,提煉成高純度資訊,提高吸收效率,少傷一些眼睛。


Comments

Be the first to post a comment

Post a comment