[Postfix] SMTP Mail Server 架設教學指南 – Postfix with Ubuntu

Install | Authentication | DKIM | Relay Server | Maintenance | Mailtools

Intro

簡易郵件傳輸通訊協定 SMTP 是什麼? | Cloudflare

Postfix Wiki

Postfix 為目前 Linux 熱門郵件傳傳輸軟體 (MTA),可供如mail, sendmail (PHP mail底層)作為預設 MTA 以用來發信。 本篇為純送信 Mail Server 應用指南,OS 環境為 Ubuntu 16.04。

Postfix - Ubuntu (Dovecot SASL)

快速安裝檔


安裝

$ 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 的設定可以參考:

  1. 安裝

    $ sudo apt-get install opendkim
  2. 設定 /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

  3. 設定 Postfix /etc/postfix/main.cf 加入以下設定:

    # DKIM
    milter_default_action = accept
    milter_protocol = 2
    smtpd_milters = inet:localhost:8891
    non_smtpd_milters = inet:localhost:8891
  4. 設定 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"
  5. 重啟服務

    $ 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 的設定可以參考:

  1. 建立一個 SASL 的密碼檔案,內容設定 External SMTP 的 host 與 account 資訊:

    $ sudo vim /etc/postfix/sasl_passwd
    [mail.example.com]:587 username:password
  2. 使用 Postmap 將 SASL 檔案轉為二進制檔案以提供給 Postfix 使用,Postmap 會依照原檔新產生副檔名為.db的檔案:

    $ sudo postmap /etc/postfix/sasl_passwd
  3. 將兩種檔案設定權限保護:

    $ sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
  4. 回到 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
  5. 重啟或重新載入 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

Opportunistic TLS - Postfix TLS Support

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

References

Leave a Reply

Your email address will not be published. Required fields are marked *