Postfix

Postfix 是一種電子郵件伺服器,它是由任職於IBM華生研究中心(T.J. Watson Research Center)的荷蘭籍研究員Wietse Venema為了改良sendmail郵件伺服器而產生的。最早在1990年代晚期出現,是一個開放原始碼的軟體。

Postfix: Tips

postfix

服務啟動/停止/重新載入

postfix check
postfix start
postfix stop
postfix reload
postfix flush
postconf - 不用編輯 main.cf 的設定方法

列出設定參數

postconf -n

修改參數
*不需要重啟服務*

postconf -e "relayhost = [192.168.10.10]:587" \
"smtp_sasl_auth_enable = yes" \
"smtp_sasl_security_options = noanonymous" \
"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd" \
"smtp_use_tls = yes" \
"smtp_tls_security_level = encrypt" \
"smtp_tls_note_starttls_offer = yes"

移除參數

postconf -# smtp_use_tls
Test SMTP

Swaks is a featureful, flexible, scriptable, transaction-oriented SMTP test tool written and maintained by John Jetmore. It is free to use and licensed under the GNU GPLv2.

外部網站

Postfix Installation

With Docker

Mailu

Mailu is a simple yet full-featured mail server as a set of Docker images. It is free software (both as in free beer and as in free speech), open to suggestions and external contributions. The project aims at providing people with an easily setup, easily maintained and full-featured mail server while not shipping proprietary software nor unrelated features often found in popular groupware.

Installation

Setting up the DNS

加一筆 A 與 MX 紀錄指向郵件主機

mail.mydomain.com. IN A a.b.c.d

mydomain.com. IN MX 10 mail.mydomain.com.

DKIM/SPF & DMARC Entries

DKIM 的 key 要從 Admin 管理介面 > Mail domains > Details > Generate keys。

Create the configuration file

透過這個網站產生 Docker 需要設定檔 docker-compose.yml , mailu.env

前往 https://setup.mailu.io/ 

必要的資訊如下:

Step 1 - pick a flavor

Step 2 - Initial configuration

Step 3 - pick some features

Step 4 - expose Mailu to the world

Database preferences

Download the configuration file
mkdir /mailu
cd /mailu
wget http://setup.mailu.io/1.7/file/64c4e566-dda9-4e09-abcb-9b8732dc873b/docker-compose.yml
wget http://setup.mailu.io/1.7/file/64c4e566-dda9-4e09-abcb-9b8732dc873b/mailu.env
Start the Compose project
cd /mailu
docker-compose -p mailu up -d

create the primary administrator user account

docker-compose -p mailu exec admin flask mailu admin myadmin mydomain.com THISISPASSWORD
Login as admin to verify

open the URL: http://127.0.0.1:8080/ui login with the account that you just created.

mailu-admin.png

Mail Management

Webmail

https://mail.mydomain.com/webmail

mailu-webmail.png

user

docker-compose exec admin flask mailu user myuser mydomain.com 'password123'

user-delete

docker-compose exec admin flask mailu user-delete foo@mydomain.com

設定 postfix 為寄信主機

情境說明

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

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

說明:

關鍵參數定義:

安裝設定 container
git clone https://github.com/a-lang/docker-postfix-smtp.git 
docker pull alangtw/postfix-smtp:trusty

修改啟動參數

run.sh:

-e maildomain=mydomain.com -e smtp_user=alang@mydomain.com: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 記錄,內容為:

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 記錄,內容為:

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: alang@mydomain.com
pass: yourpass

$> echo -ne '\000alang@mydomain.com\000yourpass' | openssl base64
AGFsYW5nQG15ZG9tYWluLmNvbQB5b3VycGFzcw==

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

連線 smtp 主機

$> 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 郵件安全協議檢查,而且很容易得知檢查的結果。

Thunderbird SMTP 設定:

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





外部轉信主機設定

GoDaddy SMTP

GoDaddy Setup: Office 365 Email: Enable SMTP Authentication

Sign in Email & Office Dashboard > Select one email account created (your@domain.name) > Advanced Settings > SMTP Authentication: ON

main.cf:

## for GoDaddy SMTP with Office 365
relayhost = [smtp.office365.com]:587
# SASL
smtp_sasl_auth_enable=yes
smtp_sasl_password_maps = hash:/etc/postfix/saslpasswd_godaddy
smtp_sasl_security_options = noanonymous
# TLS
smtpd_tls_key_file = /etc/postfix/tls/godaddy.key
smtpd_tls_cert_file = /etc/postfix/tls/godaddy.crt
smtpd_use_tls = yes
smtp_use_tls = yes
smtpd_tls_auth_only = no
smtp_tls_note_starttls_offer = yes
smtpd_tls_loglevel = 2
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_randome_source = dev:/dev/urandom
# Fix for MAIL-FROM
smtp_generic_maps = hash:/etc/postfix/generic

測試 TLS 連線

openssl s_client -quiet -starttls smtp -connect smtp.office365.com:587
depth=2 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA
verify return:1
depth=1 /C=US/O=DigiCert Inc/CN=DigiCert Cloud Services CA-1
verify return:1
depth=0 /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=outlook.com
verify return:1
250 SMTPUTF8

Ctrl + c 離開。

建立密碼檔 saslpasswd_godaddy,內容格式如下:

smtp.office365.com your@domain.name:thisispass
chmod 0600 saslpasswd_godaddy
postmap hash:/etc/postfix/saslpasswd_godaddy

建立憑證檔

cd /etc/postfix
mkdir tls
cd tls
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout godaddy.key -out godaddy.crt

指定 MAIL-FROM 位址

編輯 /etc/postfix/generic

root@freepbx.sangoma.local your@sender.email.address
root your@sender.email.address
asterisk your@sender.email.address

轉換 generic

cd /etc/postfix
postmap generic

Google Mail

Domino Notes SMTP

測試 TLS 連線

openssl s_client -quiet -starttls smtp -connect 10.14.26.18:587
depth=0 C = TW, ST = Taiwan, L = Taoyuan, O = WIN Semiconductors Corp., OU = IT, CN = tpemissp01.winfoundry.com, emailAddress = dominooa@winfoundry.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = TW, ST = Taiwan, L = Taoyuan, O = WIN Semiconductors Corp., OU = IT, CN = tpemissp01.winfoundry.com, emailAddress = dominooa@winfoundry.com
verify error:num=21:unable to verify the first certificate
verify return:1
250 PIPELINING

SMTP 不需要帳密認證

postconf -e "relayhost = [10.14.26.18]:587"
postconf -e "smtp_use_tls = yes"

Q & A

STARTTLS is required to send mail
Jul 27 02:41:51 freepbx postfix/smtp[20403]: B56021017FB13: to=<alang.hsu@gmail.com>, relay=smtp.office365.com[52.96.165.34]:587, delay=10, delays=0.02/0.01/5.3/5.1, dsn=4.0.0, status=deferr
ed (host smtp.office365.com[52.96.165.34] said: 451 5.7.3 STARTTLS is required to send mail [BN9PR03CA0153.namprd03.prod.outlook.com] (in reply to MAIL FROM command))

Solution:

XXX not allowed to send as asterisk@freepbx.sangoma.local
Jul 27 04:11:53 freepbx postfix/smtp[31670]: warning: smtp.office365.com[52.96.28.178]:587: response longer than 2048: 554 5.2.252 SendAsDenied; info...
Jul 27 04:11:53 freepbx postfix/smtp[31670]: E0E4010176933: to=<info@mediasystemsfl.com>, relay=smtp.office365.com[52.96.28.178]:587, delay=313418, delays=313416/0.01/1.1/0.26, dsn=5.2.252, 
status=bounced (host smtp.office365.com[52.96.28.178] said: 554 5.2.252 SendAsDenied; info@mediasystemsfl.com not allowed to send as asterisk@freepbx.sangoma.local; STOREDRV.Submission.Excep
tion:SendAsDeniedException.MapiExceptionSendAsDenied; Failed to process message due to a permanent exception with message [BeginDiagnosticData]Cannot submit message. 0.35250:14350000, 1.3667
4:0A000000, 1.61250:00000000, 1.45378:02000000, 1.44866:EC2D0000, 1.36674:0E000000, 1.61250:00000000, 1.45378:F12D0000, 1.44866:CA010000, 16.55847:9A120000, 17.43559:000000002402000000000000
0000000000000000, 20.52176:140F52951900103100000000, 20.50032:140F52958917000000000000, 0.35180:140F5295, 255.23226:0A000000, 255.27962:0A000000, 255.27962:0E000000, 255.31418:19000000, 0.35
250:1F001336, 1.36674:0A000000, 1.61250:00000000, 1.45378:02000000, 1.44866:58000000, 1.36674:32000000, 1.61250:00000000, 1.45378:5D000000, 1.44866:01000000, 16.55847:D3000000, 17.43559:0000
000098030000000000000F00000000000000, 20.52176:140F52951900101062000000, 20.50032:140F5295891700001F001A00, 0.35180:67000000, 255.23226:0A001380, 255.27962:0A000000, 255.27962:32000000, 255.
17082:DC040000, 0.27745:0B002900, 4.21921:DC040000, 255.27962:FA000000, 255.1494:03003600, 0.38698:0F010480, 1.41134:46000000, 7.36354:010000000000010B01000000, 0.37692:01000000, 0.37948:860
00000, 5.33852:00000000534D545000000000, 7.36354:010000000000010907000000, 4.56248:DC040000, 7.40748:010000000000010B0A000000, 7.57132:000000000000000003000000, 4.39640:DC040000, 1.63016:320
00000, 8.45434:EAFEADFEA5E644438592F8B9E718580F00000000, 1.46798:04000000, 5.10786:0000000031352E32302E353435382E3032353A424C30505231364D42323333383A39333261363135642D616239372D346165312D623
030362D3234323361383536363439313A3332323631360093001000000000, 7.51330:2A6B5D23866FDA0800000000, 0.39570:07000000, 1.55954:0A000000, 0.49266:0200
Jul 27 04:11:53 freepbx postfix/cleanup[31676]: AC9D41016F023: message-id=<20220727041153.AC9D41016F023@freepbx.sangoma.local>
Jul 27 04:11:53 freepbx postfix/bounce[31675]: E0E4010176933: sender non-delivery notification: AC9D41016F023
Jul 27 04:11:53 freepbx postfix/qmgr[27367]: AC9D41016F023: from=<>, size=8634, nrcpt=1 (queue active)
Jul 27 04:11:53 freepbx postfix/qmgr[27367]: E0E4010176933: removed
Jul 27 04:11:53 freepbx postfix/local[31678]: AC9D41016F023: to=<asterisk@freepbx.sangoma.local>, relay=local, delay=0.02, delays=0.01/0.01/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Jul 27 04:11:53 freepbx postfix/qmgr[27367]: AC9D41016F023: removed

Solution:

GoDaddy SMTP 服務會檢查 sender 的地址是否有效。讓 postfix 將特定無效的地址轉換成其他指定的有效地址。使用檔案 generic 編輯要對應的郵件地址。

openssl 測試連線不成功

執行測試連線時,如果只有見到以下 1 ~ 2 行輸出,表示 TLS 連線失敗

write:errno=104

連線成功的訊息如下

depth=2 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA
verify return:1
depth=1 /C=US/O=DigiCert Inc/CN=DigiCert Cloud Services CA-1
verify return:1
depth=0 /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=outlook.com
verify return:1
250 SMTPUTF8
certificate verification failed

postfix/smtp[17989]: certificate verification failed for 10.14.26.18[10.14.26.18]:587: untrusted issuer /DC=com/DC=winfoundry/CN=win-root

要連線的 SMTP Server,可能使用了自簽的憑證,這個不會影響信件的寄送,可直接忽略。

如果不想讓這訊息出現,必須取的遠端 SMTP Server 所用憑證的 CA 根憑證檔,然後設定 postfix 讀取這個 CA 檔。

TLS handshake failed
STARTTLS=client, error: connect failed=-1, SSL_error=5, errno=104, retry=-1
ruleset=tls_server, arg1=SOFTWARE, relay=tpemissp01.winfoundry.com, reject=403 4.7.0 TLS handshake failed.
...relay=tpemissp01.winfoundry.com. [10.14.26.18], dsn=4.0.0, stat=Deferred: 403 4.7.0 TLS handshake failed.

使用 openssl 測試與 SMTP 主機的 TLS 連線是否成功。


sSMTP

sSMTP - Simple SMTP

sSMTP is a simple MTA to deliver mail from a computer to a mail hub (SMTP server). sSMTP is simple and lightweight, there are no daemons or anything hogging up CPU; Just sSMTP. Unlike Exim4, sSMTP does not receive mail, expand aliases, or manage a queue.

Setting up

/etc/ssmtp/ssmtp.conf

# For My SMTP relay server
AuthUser=alang@domain.com
AuthPass=ThisIsPassword
FromLineOverride=YES
mailhub=smtp.domain.com:587
UseSTARTTLS=YES
如何自訂 sender 的位址

修改 /etc/ssmtp/ssmtp.conf

FromLineOverride=NO
root=win.mis03

修改 /etc/ssmtp/revaliases

root:win.mis03@msa.hinet.net
發信測試

方法一: 使用 ssmtp

$> ssmtp alang.hsu@gmail.com

To: alang.hsu@gmail.com
From: sender@domain.com
Subject: Test Mail
Hello, World
<Ctrl-D to Exit>

方法二: 使用 mail

echo "Hello, World" | mail -s "Test Mail"

NOTE:

使用方法一時,From 必須輸入一個有效的郵件地址。

使用方法二有可能會寄不出去,原因是 sender 的郵件地址不是一個有效的位址。參考自訂 sender 位址的步驟。