*`Updated: 2023/07/21`*
## Setup DNS Records
### MX Record
The <domain_name> can be considered as a main domain (e.g. `example.com`) or a subdomain (e.g. `mail.example.com`). Using the subdomain and MX record is a batter way for web mail server management.
```
# DNS setting example
# A record for subdomain
mail.cocobird.net. 3600 IN A <IP>
# MX record for domain (content format: "<priority> <mail_domain>")
cocobird.net. 3600 IN MX 10 mail.cocobird.net.
```
### SPF Record
```
# SPF record example
mail.cocobird.net. 3600 IN TXT "v=spf1 include:_spf.google.com ip4:<IP> ~all"
```
### DMARC Record
```
# DMARC record example
_dmarc.mail.cocobird.net. 3600 IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-reports@mail.cocobird.net"
```
## Install and Configure postfix
### postfix Setting
1. Install postfix
```bash
sudo apt install postfix
# --> Select Internet Site
# --> Enter domain name
# --> Default the following options
# Enable postfix service while start-up
sudo systemctl enable postfix
```
2. Edit configure file `/etc/postfix/main.cf`
```
# In file '/etc/postfix/main.cf'
myhostname = <domain_name>
# Check mydestination includes $myhostname and <domain_name>
```
3. Restart postfix service
```
sudo systemctl restart postfix
```
### TLS Setting
1. Edit configure file `/etc/postfix/main.cf`
```
# In file '/etc/postfix/main.cf'
myhostname = <domain_name>
# Check mydestination includes $myhostname and <domain_name>
smtpd_tls_cert_file=/etc/letsencrypt/live/<domain_name>/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/<domain_name>/privkey.pem
smtpd_use_tls = yes
smtpd_tls_auth_only = yes
smtpd_tls_received_header = yes
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination
# TLS for external
smtp_use_tls = yes
smtp_tls_note_starttls_offer = yes
```
2. Edit configure file `/etc/postfix/master.cf`
```
# In file '/etc/postfix/master.cf'
# Find and uncomment to enable smtps service
smtps inet n - y - - smtpd
# -o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
```
### Use Virtual Mailbox
1. Remove domain setting in `mydestination`, e.g. (mail.cocobird.net)
2. Add virtual mailbox setting
```
# In file '/etc/postfix/main.cf'
...
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = cocobird.net, mail.cocobird.net
```
## Install and Configure DKIM Service
### Install opendkim
1. Install opendkim
```bash
sudo apt install opendkim opendkim-tools
```
2. Add postfix to opendkim group
```bash
# Add postfix user to opendkim group
sudo gpasswd -a postfix opendkim
```
### Configure opendkim
#### a. Config `/etc/opendkim.conf` Method
1. Edit configure file `/etc/opendkim.conf`
```
# In file '/etc/opendkim.conf'
Syslog yes
SyslogSuccess yes
LogWhy yes
Canonicalization relaxed/simple
Mode sv
#SubDomains no
OversignHeaders From
Domain <domain_name>
Selector <selector>
KeyFile /etc/dkimkeys/<key_name>.private
#Socket local:/run/opendkim/opendkim.sock
Socket inet:8891@localhost
#Socket inet:8891
#Socket local:/var/spool/postfix/opendkim/opendkim.sock
```
2. Edit default configure file `/etc/default/opendkim`
```
# In file '/etc/default/opendkim'
# Uncomment to specify an alternate socket
# Note that setting this will override any Socket value in opendkim.conf
# default:
# SOCKET=local:$RUNDIR/opendkim.sock
SOCKET="inet:8891@localhost"
```
3. Edit postfix configure file `/etc/postfix/main.cf`
```
# In file '/etc/postfix/main.cf'
.
.
.
# Add following lines at the end
# DKIM
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
```
4. Generate DKIM key
```bash
opendkim-genkey --selector=<selector> --domain=<domain_name>
# The keys <selector>.txt and <selector>.private will be generated under current directory.
```
Once generated the DKIM key, move the key to default DKIM key path, the path must match the `KeyFile` setting under `/etc/opendkim.conf`
```bash
sudo mv <selector>.txt <selector>.private /etc/dkimkeys/
# Modify the directory owner to opendkim
sudo chown -R opendkim:opendkim /etc/dkimkeys/
```
:::warning
Changing owner is an important step for opendkim.service to find the private key location.
:::
#### b. Using KeyTable and SigningTable Method
1. Comment Domain, Selector and KeyFile, then and add table paths.
```
# --- /etc/opendkim.conf ---
# Domain ... (註解掉)
# Selector ... (註解掉)
# KeyFile ... (註解掉)
# 啟用對應表
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
InternalHosts refile:/etc/opendkim/InternalHosts
```
2. Generate keys.
```
# 為主網域 example.com 產生金鑰,Selector 設為 default
sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -d example.com -s default -D /etc/opendkim/keys/example.com
sudo chown -R opendkim:opendkim /etc/opendkim/keys/example.com
# 為子網域 sub.example.com 產生金鑰,Selector 設為 mail
sudo mkdir -p /etc/opendkim/keys/sub.example.com
sudo opendkim-genkey -b 2048 -d sub.example.com -s mail -D /etc/opendkim/keys/sub.example.com
sudo chown -R opendkim:opendkim /etc/opendkim/keys/sub.example.com
```
3. Config KeyTable
```
# --- /etc/opendkim/KeyTable ---
# 金鑰名稱 Domain Selector KeyFile (私鑰)
key_main example.com:default:/etc/opendkim/keys/example.com/default.private
key_sub sub.example.com:mail:/etc/opendkim/keys/sub.example.com/mail.private
```
4. Config SigningTable
```
# --- /etc/opendkim/SigningTable ---
# 寄件者 (From 標頭) 使用的金鑰名稱 (來自 KeyTable)
*@example.com key_main
*@sub.example.com key_sub
```
5. Config InternalHosts
```
# --- /etc/opendkim/InternalHosts ---
# 1. 絕對必要的基本設定 (本機)
127.0.0.1
::1
localhost
# 2. 本機伺服器的 IP 位址
# 假設您的伺服器公用 IP 是 203.0.113.10
203.0.113.10
# 假設您的伺服器內部 IP 是 192.168.1.100
192.168.1.100
# 3. (選用) 其他可信任的內部主機
# 假設您有一台 Web 伺服器在 192.168.1.200
192.168.1.200
# 4. (選用) 信任整個內部子網路
# 如果您信任 192.168.1.x 網段的所有機器
# 192.168.1.0/24
```
### Setup DNS DKIM Record
According to the former section, The file `<selector>.txt` describes the DNS record format, simply add the content into DNS record.
```!
# In file '/etc/dkimkeys/<selector>.txt'
<selector>._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; p=<rsa_hash_code>" ) ; ----- DKIM key <selector> for <domain_name>
```
### SMTP Firewall Setting
```bash
# 用於伺服器對伺服器 (Server-to-Server) 的郵件傳輸
sudo ufw allow 25/tcp
# 用於客戶端寄信 (Submission, STARTTLS)
sudo ufw allow 587/tcp
# (如果您有設定 SMTPS) 用於客戶端寄信 (SSL/TLS)
sudo ufw allow 465/tcp
```
## Install IMAP and POP3 Service
### Install dovecot
1. Install dovecot and lmtp module
```
sudo apt install dovecot-imapd dovecot-pop3d
sudo apt install dovecot-lmtpd
```
2. Edit configure file `/etc/dovecot/dovecot.conf`
```
# In file '/etc/dovecot/dovecot.conf'
.
.
.
# Add following lines at the end
protocols = imap pop3 lmtp
mail_location = maildir:~/Maildir
```
### Auth and SSL
#### System User Method
3. Edit configure file `/etc/dovecot/conf.d/10-auth.conf`
```
# In file '/etc/dovecot/conf.d/10-auth.conf'
disable_plaintext_auth = no
auth_username_format = %n
auth_mechanisms = plain login
```
4. Edit configure file `/etc/dovecot/conf.d/10-ssl.conf`
```
# In file '/etc/dovecot/conf.d/10-ssl.conf'
ssl = yes
ssl_cert = </etc/letsencrypt/live/<domain_name>/fullchain.pem
ssl_key = </etc/letsencrypt/live/<domain_name>/privkey.pem
```
5. Edit configure file `/etc/dovecot/conf.d/10-mail.conf`
```
# In file '/etc/dovecot/conf.d/10-mail.conf'
mail_privileged_group = mail
```
6. Change postfix mail location
```bash
# Location same as 'mail_location' under '/etc/dovecot/dovecot.conf'
sudo postconf -e "home_mailbox = Maildir/"
```
#### Virtual User Method
1. Edit `10-auth.conf`
```
# --- /etc/dovecot/conf.d/10-auth.conf ---
# 關閉明文認證,除非在 SSL/TLS 加密連線中
disable_plaintext_auth = no
auth_username_format = %n
# 認證機制
auth_mechanisms = plain login
# 註解掉 (或刪除) 系統使用者認證
#!include auth-system.conf.ext
# 啟用 (取消註解) passwd-file 認證
!include auth-passwdfile.conf.ext
```
2. Edit `auth-passwdfile.conf.ext`
```
# --- /etc/dovecot/conf.d/auth-passwdfile.conf.ext ---
passdb {
driver = passwd-file
# 指向您的密碼檔案
# scheme=SHA512-CRYPT 指示 Dovecot 檔案中的密碼是使用此演算法加密的
# username_format=%n 捨去@domain的資訊
args = scheme=SHA512-CRYPT username_format=%n /etc/dovecot/users
}
userdb {
# 我們使用 'static' (靜態) driver,
# 這表示所有虛擬使用者的 UID/GID 和 home 目錄都使用相同規則。
driver = static
# 這必須與您在 Postfix (或其他 MTA) 中設定的 vmail 使用者/目錄相符
args = uid=vmail gid=vmail home=/var/vmail/%n
}
```
3. Create vmail group
```bash
# -r 建立系統使用者
# -d 指定家目錄 (所有郵件的根目錄)
# -s /sbin/nologin 禁止此使用者登入
# -g vmail (先建立群組)
sudo groupadd -r vmail
sudo useradd -r -g vmail -d /var/vmail -s /sbin/nologin -c "Virtual Mail User" vmail
```
4. Generate user password hash using doveadm
```bash
# -s 指定加密演算法 (必須與 'args' 中的 'scheme' 相符)
sudo doveadm pw -s SHA512-CRYPT
```
5. Create `sudo nano /etc/dovecot/users`
```
# --- /etc/dovecot/users ---
# 格式: user:{scheme}hash
user1:{SHA512-CRYPT}$6$....(user1 的雜湊值)...
user2:{SHA512-CRYPT}$6$....(user2 的雜湊值)...
```
6. Set file permission
```
# 將檔案擁有者設為 dovecot (或 root)
sudo chown dovecot:dovecot /etc/dovecot/users
# 設定權限為 600 (只有擁有者可讀寫)
sudo chmod 600 /etc/dovecot/users
```
7. Set LMTP (Local Mail Transfer Protocol)
```
# --- /etc/dovecot/conf.d/10-master.conf ---
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0660
user = postfix
group = postfix
}
}
```
### IMAP/POP3 Firewall Settings
```bash
# IMAP (STARTTLS)
sudo ufw allow 143/tcp
# IMAPS (SSL/TLS)
sudo ufw allow 993/tcp
# (如果您也啟用了 POP3)
# POP3 (STARTTLS)
sudo ufw allow 110/tcp
# POP3S (SSL/TLS)
sudo ufw allow 995/tcp
```
## Relayhost Setting
1. Edit configure file `/etc/postfix/main.cf`
```
# In file '/etc/postfix/main.cf'
# SASL (Dovecot Not Support Client)
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
#relayhost = [mail.cocobird.net]
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
#smtp_sasl_auth_enable = yes
#smtp_tls_security_level = encrypt
#smtp_sasl_tls_security_options = noanonymous
#smtp_sender_dependent_authentication = yes
#smtp_sasl_security_options = noanonymous, noplaintext
#smtp_sasl_tls_security_options = noanonymous
#smtp_sasl_mechanism_filter = plain, login
```
2. Edit configure file `/etc/postfix/sasl_passwd`
```
# In file '/etc/postfix/sasl_passwd'
[<domain_name>] username:password
# Alternative form:
# [<domain_name>]:submission username:password
```
3. Edit configure file `/etc/postfix/sasl_passwd`
```
# In file '/etc/postfix/sasl_passwd'
# Find and uncomment
service auth {
.
.
.
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
```
## Mail Server Testing
- MXToolBox
- https://mxtoolbox.com/
- MXToolBox Mail deliverability
- https://mxtoolbox.com/deliverability
- Google Admin Toolbox Check MX
- https://toolbox.googleapps.com/apps/checkmx/
- mail-tester
- https://www.mail-tester.com/
- CheckTLS
- https://www.checktls.com/TestReceiver
## Reference
- SASL
- https://www.postfix.org/SASL_README.html#client_sasl