Install | Authentication | DKIM | Relay Server | Maintenance | Mailtools
Intro
簡易郵件傳輸通訊協定 SMTP 是什麼? | Cloudflare
Postfix 為目前 Linux 熱門郵件傳傳輸軟體 (MTA),可供如mail
, sendmail (PHP mail底層)
作為預設 MTA 以用來發信。 本篇為純送信 Mail Server 應用指南,OS 環境為 Ubuntu 16.04。
安裝
$ sudo apt install postfix
設定 (Interactive)
$ sudo dpkg-reconfigure postfix
或者直接對應設定檔:/etc/postfix/main.cf
基本設定完後,就已經完成 localhost MTA service,預設無驗證僅採用mynetworks
allowed host。
另外可以安裝 mailutils 以使用 mail 等指令工具發信:
$ sudo apt install mailutils
身份驗證
Postfix 可以搭配 SASL (Simple Authentication and Security Layer) 作為身份驗證 (對應OS系統使用者帳密),預設使用 Cyrus SASL、可選用 Dovecot SASL,雖然本篇是純粹寄信(SMTP)不做收信(POP3/IMAP)理當用 Dovecot 有點多餘,但 Dovecot SASL 整合個人覺得較方便。
Dovecot SASL 整合
1. 安裝Dovecot Core:
$ sudo apt install dovecot-core
2. 設定Postfix指定SASL使用Dovecot SASL /etc/postfix/main.cf
加入:
# Dovecot SASL
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_local_domain =
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
3. 設定Dovecot本身,/etc/dovecot/conf.d/10-master.conf
開啟註解:
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
}
或者 mode = 0660 設 user & group = postfix
4. 設定Dovecot Auth Mechanism /etc/dovecot/conf.d/10-auth.conf
:
auth_mechanisms = plain login
5. 兩者皆做重啟後即可依照系統使用者帳密做 SMTP 客戶端身份驗證:
sudo systemctl restart dovecot.service
sudo systemctl restart postfix.service
DKIM 設定
Postfix 使用 DKIM 的設定可以參考:
-
安裝
$ sudo apt-get install opendkim
-
設定
/etc/opendkim.conf
:Domain example.com KeyFile /etc/dkimkeys/dkim.key Selector your-selector SOCKET inet:8891@localhost
設定
/etc/default/opendkim
以免設定被複寫:SOCKET="inet:8891@localhost"
Socket 若要使用預設的 socket file 模式,設定可參考 Postfix for opendkim.sock - StackExchange
-
設定 Postfix
/etc/postfix/main.cf
加入以下設定:# DKIM milter_default_action = accept milter_protocol = 2 smtpd_milters = inet:localhost:8891 non_smtpd_milters = inet:localhost:8891
-
設定 Private key,以下用 opendkim-tools 新建 key 舉例:
$ apt-get install opendkim-tools $ opendkim-genkey -t -s mail -d example.com $ cp mail.private /etc/dkimkeys/dkim.key $ chown opendkim:opendkim /etc/dkimkeys/dkim.key
並設定 Public key (
mail.txt
) 於 DNS record:your-selector._domainkey IN TXT "v=DKIM1; k=rsa; t=y; p=MIGf...AB"
-
重啟服務
$ service opendkim restart $ service postfix restart
錯誤偵查
-
opendkim service 啟動錯誤可以透過設定檔測試除錯:
$ sudo opendkim -t /etc/opendkim.conf
-
使用 Postfix 寄信後可以透過
mail.log
確認是否有正確連接 OpenDKIM Filter (Milter):$ sudo tail /var/log/mail.log
-
若 Opendkim socket 使用 TCP:8891,可以利用 localhost netstat 驗證:
$ sudo netstat -tuln | grep 8891
-
正確寄出 mail 後,可於收件者檢視 Original message 找出 DKIM 驗證訊息:
# Sender's header DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=example.com; s=your-selector; t=1697443282; bh=lBFPQM+Co+tNLmBxzfXGr+cYkpDQjnYPaHJUazOv7VU=; h=Subject:To:Date:From:From; b=AX....== # Receiver's authentication result dkim=pass header.i=@example.com header.s=your-selector header.b=FfOLSax0;
Relay Server 設定
Postfix 可以搭配 SASL (Simple Authentication and Security Layer) 作為 Relay Server 身份驗證,作為 Relay Server 的設定可以參考:
-
建立一個 SASL 的密碼檔案,內容設定 External SMTP 的 host 與 account 資訊:
$ sudo vim /etc/postfix/sasl_passwd
[mail.example.com]:587 username:password
-
使用 Postmap 將 SASL 檔案轉為二進制檔案以提供給 Postfix 使用,Postmap 會依照原檔新產生副檔名為
.db
的檔案:$ sudo postmap /etc/postfix/sasl_passwd
-
將兩種檔案設定權限保護:
$ sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
-
回到 Postfix 的設定檔進行 relayhost, SASL 身份驗證以及其他 client 設定,
/etc/postfix/main.cf
:# Relay Host relayhost = [mail.isp.example]:587 # Enable SASL authentication smtp_sasl_auth_enable = yes # Disallow methods that allow anonymous authentication. smtp_sasl_security_options = noanonymous # Hash filepath of sasl_passwd smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd # Enable STARTTLS encryption smtp_use_tls = yes # where to find CA certificates smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
-
重啟或重新載入 Postfix:
$ sudo service postfix restart
relayhost 的驗證可以寄信後檢驗
/var/log/mail.log
歷程
維護
Version
Interface有點弱,只能:
$ postconf -d | grep mail_version
Log
/var/log/mail.log
檢查Mail Queue
$ mailq
OR:
$ postqueue -p
執行Mail Queue
$ postqueue -f
OR
$ postfix flush
基本上被對方卡住的就是繼續卡,無效用。
刪除Mail Queue
$ postsuper -d ALL
郵件差異刪除
$ postsuper -d ALL deferred
進階設定
SMTPD server port change
情境如GCE要連過來relay的client,設定上增加或修改 /etc/postfix/master.cf
再重啟服務:
2525 inet n - n - - smtpd
第一個參數為port,原設定皆常數化,可自訂port
mydestination 驗證檢查
只要寄件者Domain包含在mydestination
都會允許不過SMTP驗證,要特別注意。/etc/postfix/main.cf
:
mydestination = $myhostname, smtp, localhost.localdomain, localhost
TLS設定或關閉
SMTP TLS (Outgoing)
Outgoing TLS 預設為關,會需要自行添加設定,/etc/postfix/main.cf
加入以下設定:
# Opportunistic TLS for Outgoing
smtp_tls_security_level = may
SMTPD Server TLS (Incoming)
Incoming TLS 預設是開,通常 Client 能走就會走 SSL/TLS,如要關閉,/etc/postfix/main.cf
:
smtpd_use_tls=no
關閉是為了防止 Client 自動偵測 STARTTLS 支援進而使用 TLS 連線
如要完整安裝TLS,除了憑證Key與Cert,另外還得增加CA以確保Client最大支援度,/etc/postfix/main.cf
:
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_CAfile = /etc/ssl/certs/CA.pem
以上憑證還得搭配匹配的domain連入才達成完整的TLS傳輸。
若想並存TLS協定,例如25 port不認證、587 port走STARTTLS,則反註解/etc/postfix/master.cf
:
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
SSL(465)模式設定
承上,別於STARTTLS(587),若想支援舊標準SSL/TLS(465)認證,可以額外開啟465 port設定,反註解/etc/postfix/master.cf
:
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
但與STARTTLS一樣就是需要憑證完整性,否則一般Client在建SSL Socket時一樣會失敗。
mydestination 設定
(收件人 User unknown 問題)
設定值mydestination
會將 domain 符合 value 的收件人排除 mail forward,若主機只做 MTA 而不做 MX 則可以刪掉 domain value:
# Default
mydestination = $mydomain, localhost.$mydomain, localhost
# MTA only
mydestination = localhost
email - Postfix: Recipient address rejected: User unknown in local recipient table - Server Fault
寄信問題
Return-Path 更換
寄件者若不設定 Return-Path 的情況下,送出郵件的 Return-Path (MAIL From
) 預設即會使用系統用戶名加上Hostname:linux-user@myhostname
。
此情況下若寄件人為 service@myhostname 而因由linux-user執行發信而 Return-Path 為 linux-user@myhostname,恐會造成收信伺服器驗證問題 (連 Domain 都不同就不用期待正常的收信伺服器會接收了)。
PHP 解決方法
PHP 使用 sendmail 底層來送信,可以使用$additional_params
直接透過-f
指令指定Mail From
:
mail('name@recipient.com', 'the subject', 'the message', 'From: name@sender.com ...',
'-f name@sender.com');
Reference: PHP Mail() additional_parameters Return-Path問題詳細測試文:Setting Return-Path in PHP mail()
送信阻擋不順疑難排除
IPv6 ReverseDNS:
如果機器IPv6開啟但沒有作ReverseDNS,像GMail就可能因此阻擋退信。
以Ubuntu(16.04)為例:
sudo vim /etc/sysctl.conf
// 底部加入以下設定值
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
重啟套用設定
sudo sysctl -p
檢查是否生效,沒出現文字就是已經關了 ipv6 了。
ip a | grep inet6
AWS EC2 送信過慢問題:
AWS EC2有對SMTP服務(似乎是封包)進行節流阻擋,目前可以透過特殊表單申請開通即可!
GCP目前全阻擋,無法使用SMTP網路服務,僅提供465/587對gmail server。
寄信驗證
寄信工具 - Mailutils
Mailutils (Mail / Mailx)
如上面介紹安裝部分,
$ sudo apt install mailutils
# Upgrade
$ sudo apt upgrade mailutils
寄信指令範例:
$ mail -s "Mail Title" -a "From: name@sender.com" name@recipient.com, name2@recipient.com <<< "Mail body"
# Mail body 使用 ECHO 帶入以支援換行
$ echo -e "Line 1\nLine 2\nLine 3" | mail -s "Mail Title" -a "From: name@sender.com" name@recipient.com
# 分開指定 SMTP MAIL From: 與 header From:
$ mail -r name@sender.com -s "Mail Title" -a "From: name@sender.com" name@recipient.com <<< "Mail body"
如 Tool debug 不便,要使用封包 debug 可以搭配本篇 Postfix Outgoing TLS關閉 及開啟 tcpdump 封包解析
Sendmail
$ sudo apt install sendmail
# Upgrade
$ sudo apt upgrade sendmail
寄信指令範例:
# 分開指定 SMTP MAIL From: 與 header From:
$ echo -e "Subject: Mail Subject\nTo: name@recipient.com\nFrom: name@sender.com\n\nMail body" | sendmail -f name@recipient.com name@sender.com