設定 postfix 為轉信主機

情境說明

需求:需要一部 SMTP 寄信主機可供論壇網站寄信,免費的 Gmail 或 ISP 提供的 SMTP 主機都會有寄送數量的限制,而其他提供可大量寄信的雲端服務商,例如 Mailchimp、Sendgrid 等收費都不便宜。

目的:使用 postfix 架設一部自有的 SMTP 寄信主機。

說明:

  • 採用 docker 佈署方式
  • 為了降低寄出的郵件被其他郵件平台視為垃圾郵件而遭阻擋,主機在寄信時所提供的「寄件者」郵件位址的網域,需要包含一些安全設定:
    NOTE:建議至少要完成最簡單的 SPF Record;不然透過主機寄信到 Gmail 會收不到。
    • SPF Record
    • DKIM
    • DMARC
  • 為了要完成上述設定,必須擁有網域的控制權。
  • 網域內至少需有一個有效的郵件信箱,作為論壇系統管理後台認証與主機設定過程驗證用。

關鍵參數定義:

  • 網域內的有效信箱:[email protected]
  • 網域:mydomain.com
  • 寄信主機的 FQDN:smtp.mydomain.com
  • 透過主機發信時的「寄件者」郵件位址:[email protected]
安裝設定 container
git clone https://github.com/a-lang/docker-postfix-smtp.git 
docker pull alangtw/postfix-smtp:trusty

修改啟動參數

run.sh:

  • maildomain: 你的網域名
  • smtp_user: 外寄郵件的連線帳號與密碼,中間用:隔開
-e maildomain=mydomain.com -e [email protected]:thispassword \
建立 SSL 自我簽署憑證

為了要新增 SSL 憑證,必須先將 container 啟動。

注意:此時 container 雖然啟動,但缺少一些需要的憑證與金鑰檔,所以系統還無法正常運作。

啟動 container

chmod 0755 *.sh
./run.sh

建立 SSL 憑證檔
NOTE: 在 Host 執行以下指令

docker exec -it postfix openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout  /etc/postfix/certs/smtp-mydomain-com.key \
-out /etc/postfix/certs/smtp-mydomain-com.crt

Tip:

憑證檔 .crt 與 .key 會儲存在以下路徑:
- Host OS: data/certs
- Container OS: /etc/postfix/certs

SSL 憑證是用在 SMTP 主機與發信電腦或發信系統加密連線。

建立 DKIM 金鑰

在 Host 執行以下指令

docker exec -it postfix sh -c "cd /etc/opendkim/domainkeys && opendkim-genkey -t -s mail -d mydomain.com"

Tip:

私鑰檔 .private 與公鑰檔 .txt 會儲存在以下路徑:
- Host OS: data/domainkeys
- Container OS: /etc/postfix/domainkeys

.txt 內有公鑰字串,這要設定在 DNS Zone。

重啟 container

有了 SSL 憑證與 DKIM 金鑰,需重啟 container 以套用這些設定。

./stop.sh
./run.sh

到這裡,主機設定都已完成。

檢查幾個 container 的服務
postfix:

#> docker exec -it postfix ps -ef | grep postfix
root        54    51  0 07:11 ?        00:00:00 /bin/bash /opt/postfix.sh
root       125     1  0 07:11 ?        00:00:00 /usr/lib/postfix/master
postfix    127   125  0 07:11 ?        00:00:00 pickup -l -t unix -u
postfix    128   125  0 07:11 ?        00:00:00 qmgr -l -t unix -u

opendkim:

#> docker exec -it postfix ps -ef | grep opendkim
opendkim    55    51  0 07:11 ?        00:00:00 /usr/sbin/opendkim -f
opendkim    66    55  0 07:11 ?        00:00:00 /usr/sbin/opendkim -f

/var/log/mail.log:

#> docker exec -it postfix tail -20 /var/log/mail.log
Jan  2 07:11:14 a037fd779eaa opendkim[66]: OpenDKIM Filter v2.9.1 starting (args: -f)
Jan  2 07:11:15 a037fd779eaa postfix/master[125]: daemon started -- version 2.11.0, configuration /etc/postfix

雖然系統會用 sasl 作郵件認証,不過 saslauthd 服務可以不用啟動。

Tip: mail.log 如服務正常運作,不應該出現錯誤訊息;用戶端在寄信後,這裡如果顯示 ... doesn't resolve to XXX.XXX.XXX.XXX 的錯誤,這是正常的,原因是主機所在的網路無法反查用戶端的FQDN,這不會影響寄信功能。

防止寄出信件成為垃圾信而遭阻擋
  • 避免外寄郵件遭到假冒
  • 降低外寄郵件被辨識為垃圾郵件
  • 避免有心人士以郵件工具作為釣魚攻擊

關於 SPF、DKIM 與 DMARC 的運作原理,以及如何保護郵件被假冒或竄改,參閱下述連結

新增 SPF 記錄

SPF 記錄的工作原理是,在「寄件者」郵件位址所在的網域設定裡,新增一筆 SMTP 主機 IP,用途是允許該 IP 使用這網域作為發信時的「寄件者」。

在 DNS Zone 新增一筆 TXT 記錄,內容為:

  • Type: TXT
  • Name: mydomain.com 或者 @
  • Value: v=spf1 a mx ip4:123.123.123.123 ~all

Tip:

123.123.123.123 是 SMTP 主機位址

如果有多個 IP 位址,要用空格隔開,例如 ip4:123.123.123.123 ip4:111.111.111.111

關於 SPF 更多的說明,請參閱 Google: 使用 SPF 對電子郵件寄件者進行授權

新增 DKIM 記錄

採用 DomainKeys Identified Mail (DKIM) 標準有助於防止外寄電子郵件遭到假冒。

「假冒電子郵件」意指變更電子郵件內容,讓郵件顯示非真實寄件來源的寄件者或寄件地址。假冒是在未經授權的情況下使用電子郵件,這種情形十分常見,因此部分電子郵件伺服器會要求設定 DKIM,以免電子郵件遭到假冒。

DKIM 會在所有外寄郵件的標頭加上加密簽名,收到這些郵件的電子郵件伺服器則會使用 DKIM 來解密郵件標頭,並將它與 DNS 上的公鑰做匹配,以確認郵件寄出後並未遭人竄改。

DKIM 有一組配對的公、私鑰,私鑰設定在 SMTP 主機上,公鑰則設定在公開的 DNS Zone 上。

在 DNS Zone 新增一筆 TXT 記錄,內容為:

  • Type: TXT
  • Name: mail._domainkey
  • Value: v=DKIM1; k=rsa; t=y; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAraC3pqvqTkAfXhUn7Kn3JUNMwDkZ65ftwXH58anno/bElnTDAd/idk8kWpslrQIMsvVKAe+mvmBEnpXzJL+0LgTNVTQctUujyilWvcONRd/z37I34y6WUIbFn4ytkzkdoVmeTt32f5LxegfYP4P/w7QGN1mOcnE2Qd5SKIZv3Ia1p9d6uCaVGI8brE/7zM5c

Tip:

Value 的值與 p=公鑰,內容都在建立金鑰步驟時產生的檔案 mail.txt 裡。

關於 DKIM 更多的說明,請參閱 Google: 使用 DKIM 驗證電子郵件

新增 DMARC 記錄

垃圾郵件發佈者可能會假造電子郵件的「寄件者」地址,讓人誤以為這些郵件是您網域中某位使用者所寄送。如果這類發佈者冒用您網域的名義傳送垃圾郵件,不僅會損害網域的聲譽,收件者也可能將假造郵件連同真正從您網域寄出的郵件一併標示為垃圾內容。

為了防堵這種濫發垃圾郵件的情形,許多郵件系統例如Gmail 現在支援「網域型郵件驗證、報告與一致性」(DMARC) 機制。您可以使用 DMARC 定義政策,決定 Gmail 如何處理以您網域名義寄出的垃圾電子郵件。

注意:必須先完成 SPF 與 DKIM 設定,才能再設置 DMARC。

在 DNS Zone 新增一筆 TXT 記錄,內容為:

Tip:

p=none,對於可疑郵件,不採取任何處置
rua,回報 DMARC 的活動報告至該郵件位址

關於 DMARC 更多的說明,請參閱 Google: 使用 DMARC 管理可疑電子郵件

驗證與測試寄信

如何驗證寄信功能與每個安全協議是否生效,大概是文章中最困難以及最花時間的步驟。

驗證寄信功能

1. 用 openssl 測試 SMTP 帳號認證,將帳號密碼轉換成 base64 編碼

user: [email protected]
pass: yourpass

$> echo -ne '\[email protected]\000yourpass' | openssl base64
AGFsYW5nQG15ZG9tYWluLmNvbQB5b3VycGFzcw==

# 另一個 perl 的方法
# 帳密如有包含 @ 字元,必須加上 \
$> perl -MMIME::Base64 -e \ 'print encode_base64("\0alang\@mydomain.com\0yourpass");' 
AGFsYW5nQG15ZG9tYWluLmNvbQB5b3VycGFzcw==

連線 smtp 主機

  • SMTP 主機位址:smtp.mydomain.com
  • submission 服務:587
$> openssl s_client -quiet -starttls smtp -connect smtp.mydomain.com:587
depth=0 C = TW, ST = TY, L = TaoYuan, O = RAIDA, OU = Admin, CN = smtp.osslab.tw
verify error:num=18:self signed certificate
verify return:1
depth=0 C = TW, ST = TY, L = TaoYuan, O = RAIDA, OU = Admin, CN = smtp.osslab.tw
verify return:1
250 DSN

輸入帳號密碼的 base64編碼

AUTH PLAIN AGFsYW5nQG15ZG9tYWluLmNvbQB5b3VycGFzcw==

如果通過認証,會出現

235 2.7.0 Authentication successful

離開,輸入 quit。

2. 寄測試信到 Gmail 信箱

為何要用 Gmail 作測試信的收信位址?因為 Gmail 郵件系統已經整合了 SPF/DKIM/DMARC 郵件安全協議檢查,而且很容易得知檢查的結果。

  • 郵件用戶端軟體:必須使用有支援 STARTTLS 加密連線的郵件用戶端軟體,本例使用 Mozilla Thunderbird。
  • Gmail 信箱一個
  • 網域的有效信箱一個:設定郵件用戶端軟體時,需要提供一個「寄件者」的信箱,本例使用 [email protected]
    NOTE:如果是無效信箱位址,可能無法順利設定 Thunderbird 軟體。

Thunderbird SMTP 設定:

  • Port: 587
  • SMTP 主機:smtp.mydomain.com
  • 連線安全性:STARTTLS
  • 使用者名稱:這裡必須與 container 啟動參數裡的帳號相同,本例是 [email protected]

Tip:

連線安全性若使用 SSL/TLS,會無法成功連線主機。

如果連線成功,Thunderbird 會彈出密碼輸入的視窗,密碼必須與 container 啟動參數裡的相同。

因為使用 self-signed 憑證,所以必須檢驗憑證時,需要加入例外名單,參閱附圖 thunderbird-smtp.png 。

驗證 DNS 記錄

從 DNS 管理控制台新增完 TXT 記錄後,要驗證是否生效很簡單。

找一部可以上網的 Linux 桌機,分別執行

# SPF record
$> dig +short TXT mydomain.com

# DKIM key
$> dig +short TXT mail._domainkey.mydomain.com

# DMARC
$> dig +short TXT _dmarc.mydomain.com