【Mail Server 系列文:第 8 篇】
在前幾篇文章中,我們已完成:
- Postfix(SMTP 中繼、收信)
- Dovecot(IMAP/POP3)
- Amavis / ClamAV / SpamAssassin(安全防護)
- MariaDB + PostfixAdmin(虛擬網域管理)
本篇要介紹整個企業郵件架構中非常關鍵的一塊:
郵件歸檔系統(Mail Archiving System)—— Piler
企業級郵件架構中,郵件保留、查詢、法遵稽核、主管審閱,是一定會遇到的需求。
但一般 Webmail(Roundcube)或 IMAP 伺服器並不適合承擔這類任務,因此需要專門的「郵件歸檔系統」。
在本篇中,你將學到:
- 為何企業需要郵件歸檔?
- Piler 架構與其在 Docker 中的部署方式
- 如何整合 Postfix → Piler → Manticore (全文檢索)
- 中文全文檢索的處理方式(ICU Chinese + Ngram)
- 如何利用 PMilter 注入 X-Envelope-To 標頭,做收件人權限控管
- 完整的 docker-compose 與設定範例
1. 為什麼企業一定要有郵件歸檔系統?
企業不只是要「能收信」,更要「能查信」。
常見需求包括:
| 需求 | 說明 |
|---|---|
| 員工離職資料保留 | 使用者離職後仍需查閱歷史郵件 |
| 法規遵循 | 財務、人資、業務郵件需保存多年 |
| 稽核需求 | 主管可查詢特定員工或部門郵件 |
| 大量搜尋 | 需快速搜尋 所有郵件的全文 |
| 不可被使用者任意刪除 | 使用者刪除 IMAP 信件,仍保留歸檔 |
Piler 完美地提供以上所有機制:
- 將所有郵件額外備份 1 份
- 支援 全文搜尋
- 使用者只能查到「自己收到或寄出的信」
- 系統管理員可做更高層級審閱(配合審核流程)
2. Piler 的架構
Postfix (always_bcc/piler@archive.local)
↓
Piler (Port 25)
↓ → Store (原始信件儲存於 /var/piler/store)
↓ → MySQL (索引用 metadata)
↓ → Manticore (全文檢索:subject/body/attachments)
↓ → Web Dashboard(使用者查詢)
Piler 常用元件:
| 元件 | 功能 |
|---|---|
| Piler Daemon | 接收所有信件並建立 metadata |
| MySQL | 儲存信件屬性(寄件人/收件人/大小/時間) |
| Manticore Search | 用於全文搜尋(支援中文需額外設定) |
| Web(php) | 提供使用者登入查詢 |
| Memcached | cache index,提高搜尋速度 |
| PMilter(自建) | 注入 X-Envelope-To 標頭 → 用於權限控管 |
3. 為什麼需要 PMilter?沒有也能用嗎?
答案是:
❌ Piler 沒有 X-Envelope-To 時,可以運作,但使用者「無法看到正確收件者清單」。
這會造成:
- 使用者 A 可能查不到自己收過的某封信
- 主管查詢時權限判斷不完整
- 同群組收件信件可能只顯示其中一個收件者
因此我們需要:
自建 PMilter:在信件投遞時,解析封包 envelope RCPT → 注入標頭 X-Envelope-To
Postfix master.cf:
smtpd_milters = inet:pilermilter:33333
non_smtpd_milters = inet:pilermilter:33333
PMilter 解析:
- Envelope From → X-Envelope-From
- Envelope RCPTs → 多筆 X-Envelope-To
Piler 的 piler.conf 中需要設定:
extra_to_field=X-Envelope-To:
如此一來,Piler 才能判斷:
- 哪些使用者有權查這封信
- 哪些是寄件人/收件人
- 使用者是否應能看到此封信的內容
4. 中文全文檢索問題:為什麼 Manticore 是關鍵?
預設的 Sphinx/Manticore 不支援中文分詞。
我們使用:
ngram_len = 2
morphology = icu_chinese
也就是支援:
- 中文單字分詞(ICU Chinese)
- N-gram 2字長度細分
- 能搜尋中文主旨、內文甚至附件 OCR 內容
建表語法:
CREATE TABLE piler1 (
id bigint,
sender text indexed,
rcpt text indexed,
subject text indexed,
body text indexed,
...
) ngram_len='2' ngram_chars='cjk' morphology='icu_chinese';
這是實務企業環境必須的,否則搜尋「請款」、「採購」、「公告」等中文字會完全失敗。
5. Docker 建置架構
(1) Manticore Search 容器
Dockerfile 支援:
- 中文語系 zh_TW.UTF-8
- Manticore Search
- 初始化 schema
- 中文分詞設定
啟動後:
- 提供 9306(SQL)供 Piler 查詢
- 提供 9307(readonly SQL)
(2) Piler 容器
docker-compose.yml:
piler:
image: sutoj/piler:1.4.8
environment:
- MANTICORE_HOSTNAME=manticore
- MYSQL_HOSTNAME=maildb
- MYSQL_DATABASE=piler
- MYSQL_USER=piler
- MYSQL_PASSWORD=piler8409
儲存空間:
/var/piler/store→ 需大量磁碟/etc/piler→ 放設定與金鑰(重要)
(3) Postfix → Piler 整合
Postfix 的 main.cf:
always_bcc = piler@archive.local
transport:
archive.local smtp:[172.18.0.1]:2525
Piler 在 port 25 接收信件,因此 Postfix 必須從 2525 送到 Piler。
6. Piler config-site.php 關鍵調整
登入驗證使用 IMAP:
$config['ENABLE_IMAP_AUTH'] = 1;
$config['IMAP_HOST'] = 'dovecot';
$config['IMAP_PORT'] = 993;
$config['IMAP_SSL'] = 'SSL';
全文搜尋設定:
$config['SPHINX_MAIN_INDEX'] = 'piler1';
$config['SPHINX_HOSTNAME'] = 'manticore:9306';
收件者權限控管設定(依賴 PMilter):
$extra_to_field = 'X-Envelope-To:';
7. Piler.conf 重要設定
開啟接收中文:
enable_cjk=0 ← 建議保持為 0(因為我們改用 Manticore 處理中文)
設定投遞來源:
listen_port=25
listen_addr=0.0.0.0
檔案儲存:
queuedir=/var/piler/store
8. Web 入口整合(Apache Reverse Proxy)
例:
https://archive.it.demo.tw/
Apache 設定:
ProxyPass / http://piler:80/
ProxyPassReverse / http://piler:80/
ProxyPassReverseCookieDomain piler archive.it.demo.tw
9. 測試與驗證
✔️ 測試信件是否進入歸檔
登入 Piler Web → 搜尋新郵件
✔️ 中文搜尋功能
搜尋:
- 請款
- 合約
- 帳號
- 出貨
- 會議
若能搜尋即代表 ICU Chinese 分詞成功。
✔️ 權限控管驗證
登入不同使用者:
- userA:只能看到寄件人或收件人是 userA 的郵件
- admin:可看到全部郵件
10. 本篇總結:完整企業郵件歸檔系統現已完成
你的架構現在具備:
✔ 所有進出郵件的完整備份(不可由使用者刪除)
✔ 中文全文搜尋(ICU + Ngram)
✔ 依 envelope 收件人拆分的權限控管
✔ 高效能搜尋引擎(Manticore Search)
✔ 與 Postfix 完整整合(always_bcc)
✔ 主管稽核、使用者查詢等企業級功能
這是一套比許多商用方案更完整、自由度更高的企業郵件歸檔解決方案。