維護 Zimbra 時最常被問的一句話是:「我有寄出去,對方說沒收到,信到底去哪了?」Zimbra 內建的 zmmsgtrace 可以從記錄檔追蹤郵件流向,但用久了會發現幾個限制:遇到通訊群組、郵件重複資料刪除時,部分收件者會找不到;只有指令列,對不熟 Linux 的管理者門檻很高;也沒辦法直接看郵件內容與驗證結果。
所以我把它用 Python 重寫成 jt_zmmsgtrace:指令列參數和原版相容,補上被去重的收件者,再加上一個網頁介面,可以搜尋、看郵件路由、DKIM/SPF/DMARC 結果,還能直接下載 .eml。以 GPL v2 授權公開,和原版相同。
原版 zmmsgtrace 的限制
| 項目 | 原版 zmmsgtrace | jt_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、--id | Message-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。

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

郵件本文與下載
下方可以切換「渲染內容」與「原始內容」,也可以展開完整郵件標頭,或直接下載 .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 回報。
參考資料
- jt_zmmsgtrace(GitHub)
https://github.com/jasoncheng7115/it-scripts/tree/master/zimbra/jt_zmmsgtrace - Zimbra Wiki:CLI zmmsgtrace
https://wiki.zimbra.com/wiki/CLI_zmmsgtrace - Zimbra 郵件重複資料刪除與停用風險
https://blog.jason.tools/2025/11/zimbra-message-dedupe.html - Zimbra 以指令取得郵件原始內容
https://blog.jason.tools/2025/11/zimbra-raw-message.html



