跳到主要內容
節省工具箱Jason Tools
專案分享

jt_zmmsgtrace:Zimbra 郵件追蹤工具

Jason Cheng 發布 瀏覽 1 次
jt_zmmsgtrace:Zimbra 郵件追蹤工具
本文目錄
  1. 原版 zmmsgtrace 的限制
  2. 安裝
  3. 指令列模式
  4. 網頁介面
  5. 安全性
  6. 效能
  7. 結論
  8. 參考資料

維護 Zimbra 時最常被問的一句話是:「我有寄出去,對方說沒收到,信到底去哪了?」Zimbra 內建的 zmmsgtrace 可以從記錄檔追蹤郵件流向,但用久了會發現幾個限制:遇到通訊群組、郵件重複資料刪除時,部分收件者會找不到;只有指令列,對不熟 Linux 的管理者門檻很高;也沒辦法直接看郵件內容與驗證結果。

所以我把它用 Python 重寫成 jt_zmmsgtrace:指令列參數和原版相容,補上被去重的收件者,再加上一個網頁介面,可以搜尋、看郵件路由、DKIM/SPF/DMARC 結果,還能直接下載 .eml。以 GPL v2 授權公開,和原版相同。

原版 zmmsgtrace 的限制

項目原版 zmmsgtracejt_zmmsgtrace
解析 Postfix、Amavis 記錄支援支援
拆解 Amavis 的多收件者記錄不支援支援
補上沒有個別投遞記錄的收件者不支援支援,並標註可能被去重
顯示記錄來自哪個檔案不支援支援(Log: 欄位)
網頁介面無有,繁中與英文
檢視郵件內容、標頭、原始碼無有
DKIM、SPF、DMARC、垃圾郵件評分無有
壓縮的歷史記錄(.gz、.bz2)支援支援

找不到收件者的原因

一封信寄給多位收件者時,Amavis 的記錄會把收件者寫在同一行(<r1>,<r2>,<r3>),但 Postfix 不一定每一位都留下個別的投遞記錄,特別是遇到 Zimbra 的郵件重複資料刪除時。原版只看得到有 Postfix 投遞記錄的收件者,其他人就「消失」了,追蹤結果看起來像是信沒寄到。

jt_zmmsgtrace 會把 Amavis 記錄裡的每一位收件者拆開,和 Postfix 的資料整合,沒有個別投遞記錄的收件者也會列出來並加上標註:

Message ID 'abc123@example.com'
Log: /var/log/zimbra.log
sender@example.com -->
    user1@example.com
    user2@example.com [from Amavis - may be deduplicated]
    user3@example.com [from Amavis - may be deduplicated]
  Recipient user1@example.com
    Nov 14 18:30:02 - mail.example.com (192.168.1.10) --> relay.example.com status sent
  Recipient user2@example.com
    Processed by Amavis but no individual Postfix delivery record

郵件重複資料刪除本身是正常的功能,我在〈Zimbra 郵件重複資料刪除與停用風險〉有詳細說明。

安裝

只需要 Python 3.7 以上,不用安裝任何額外套件,全部使用標準函式庫:

mkdir -p /opt/jasontools
curl -o /opt/jasontools/jt_zmmsgtrace.py \
    https://raw.githubusercontent.com/jasoncheng7115/it-scripts/refs/heads/master/zimbra/jt_zmmsgtrace/jt_zmmsgtrace.py
chmod +x /opt/jasontools/jt_zmmsgtrace.py
/opt/jasontools/jt_zmmsgtrace.py --help

程式要以 root 執行才能讀取 Zimbra 的記錄檔;需要執行 zmprov、zmsoap、zmmailbox 這些 Zimbra 指令時,會自動切換成 zimbra 身分。

已測試的版本:Zimbra 開源版與商用版(NE),9.0.0 P38~P44、10.1.10~10.1.11。

指令列模式

參數和原版 zmmsgtrace 相容,原本的使用習慣不用改:

# 依寄件者
sudo /opt/jasontools/jt_zmmsgtrace.py -s "user@example.com"

# 依收件者(包含被去重的收件者)
sudo /opt/jasontools/jt_zmmsgtrace.py -r "user2@example.com"

# 依 Message-ID
sudo /opt/jasontools/jt_zmmsgtrace.py -i "abc123@example.com"

# 時間範圍
sudo /opt/jasontools/jt_zmmsgtrace.py -t 20251101,20251115

# 組合條件,支援正規表示式
sudo /opt/jasontools/jt_zmmsgtrace.py -s "^admin" -r "@example.org$" -t 202511

常用參數

參數說明
-i、--idMessage-ID
-s、--sender寄件者
-r、--recipient收件者
-F、--srchost來源主機名稱或 IP
-D、--desthost目標主機名稱或 IP
-t、--time時間範圍,格式 YYYYMM[DD[HH[MM[SS]]]],YYYYMM[DD...]
--year記錄檔所屬的年份
--all-logs載入所有 /var/log/zimbra*,包含輪替後的壓縮檔
--debug顯示處理過程,可重複使用增加詳細程度

查歷史記錄要指定年份

/var/log/zimbra.log 的時間戳記是 Nov 15 10:30:00 這種格式,沒有年份。查去年的舊記錄時一定要加 --year,否則會被當成今年的資料,時間比對就全錯了:

sudo /opt/jasontools/jt_zmmsgtrace.py --year 2024 /var/log/zimbra.log.2024.gz -s "user@example.com"

也可以直接指定多個記錄檔,包含壓縮檔:

sudo /opt/jasontools/jt_zmmsgtrace.py /var/log/zimbra.log.1.gz /var/log/zimbra.log

網頁介面

sudo /opt/jasontools/jt_zmmsgtrace.py --web

預設在 8989 通訊埠,用瀏覽器開啟 http://<Zimbra 主機 IP>:8989/,以 Zimbra 管理者帳號登入。介面會依瀏覽器語言自動選擇繁體中文或英文,也可以手動切換。

搜尋

左側可以依寄件者、收件者、Message-ID、來源主機、時間範圍搜尋,勾選「查詢歷史記錄檔案」就會連輪替後的壓縮檔一起找。結果會列出每一位收件者的投遞過程與狀態。

搜尋結果:列出每位收件者經過的主機與投遞狀態
搜尋結果:列出每位收件者經過的主機與投遞狀態

郵件內容與安全性檢查

點「檢視郵件」可以看到郵件的主要表頭,以及整理好的安全性檢查:DKIM、SPF 的結果,垃圾郵件總分與每一項規則的分數。不用再從一大串表頭裡自己找 Authentication-Results。

郵件內容:主要表頭、DKIM/SPF 結果與垃圾郵件評分明細
郵件內容:主要表頭、DKIM/SPF 結果與垃圾郵件評分明細

郵件路由

把 Received 表頭由上到下整理成時間軸,每一站從哪台主機到哪台主機、用什麼協定、什麼時間,一目了然,要判斷信卡在哪一站很方便。

郵件路由:依 Received 表頭整理出每一站的傳遞路徑
郵件路由:依 Received 表頭整理出每一站的傳遞路徑

郵件本文與下載

下方可以切換「渲染內容」與「原始內容」,也可以展開完整郵件標頭,或直接下載 .eml 交給資安單位分析。

郵件本文:可切換渲染內容與原始內容,並下載 .eml
郵件本文:可切換渲染內容與原始內容,並下載 .eml

網頁介面的參數

參數說明預設
--port網頁介面的通訊埠8989
--login-attempts最多允許的登入失敗次數5
--login-timeout登入失敗的計算時間範圍(分鐘)10
--all-logs啟動時載入所有記錄檔只載入 zimbra.log

注意:登入失敗保護的設計比較嚴格,是所有來源 IP 合計在時間範圍內超過次數,整個網頁服務就會自動關閉,必須由管理者手動重新啟動。這是刻意的設計,用來擋暴力破解;多人共用的環境可以把 --login-attempts 調高一點,避免有人打錯幾次密碼就讓服務停掉。

安全性

程式本身做了這些防護:

  • 正規表示式長度限制(最多 500 字元),避免惡意的運算式拖垮主機
  • 所有輸出都經過 HTML 跳脫,防止 XSS
  • 記錄檔路徑寫死在程式裡,防止路徑穿越
  • 所有輸入欄位與分頁參數都有長度與範圍限制
  • 錯誤訊息不外洩系統資訊

部署上請務必注意:

注意:請勿把網頁介面直接開放到網際網路。它能讀取所有人的郵件內容,只允許內部網段或透過 VPN 存取,用防火牆限制來源 IP;需要從外部使用的話,前面放反向代理並啟用 HTTPS 與額外的身分驗證。

另外,網頁介面本身是 HTTP,瀏覽器會顯示「不安全」,內部使用時也建議透過 Nginx 之類的反向代理加上 HTTPS。

效能

和原版一樣,記錄資料會載入記憶體。網頁模式會在啟動時解析記錄檔,之後的查詢就很快;記錄檔很大、又加上 --all-logs 的話,啟動會比較久,也需要足夠的記憶體。

結論

jt_zmmsgtrace 一開始只是想解決「去重的收件者找不到」這個問題,後來發現每次追信都要再另外撈原始郵件、看表頭、算評分,乾脆一起做進網頁介面。現在我處理「信去哪了」這類問題,基本上都先開它。

有在維護 Zimbra 的朋友歡迎試用,有問題或建議可以到 GitHub 回報。

參考資料

Jason Cheng

Jason Cheng

企業開源技術顧問,專注架構規劃與實務導入

關於作者 →

延伸閱讀