Ubuntu Mail Configuration
Mail server configuration is one of the most difficult aspects of Linux server configuration. I generally use Postfix and Dovecot on my Ubuntu VPS’s. I have prepared the following rough checklist which I used during my latest (Ubuntu 22.04) mail server configuration.
The following assumes that:
- You have created your Ubuntu VPS Server and you have command line
root access (via
sudo -i
) to your server. - All DNS configuration for your domain(s) is completed and you have control of your DNS server(s).
- You have opened inbound ports 25/tcp (smtp), 587/tcp (submission), and 995/tcp (pop3s).
- Your VPS provider supports outbound 25/tcp (smtp) connections (most providers do not).
- Your domain name is something like mydomain.com,
your server hostname is something like mysrv.mydomain.com,
and your
MX
record for your domain is something like mail.mydomain.com.
Installation and Initial Configurations
👉 https://help.ubuntu.com/community/Postfix
# apt install postfix # dpkg-reconfigure postfix # /etc/init.d/postfix restart
# cat >/etc/postfix/sasl/smtpd.conf pwcheck_method: saslauthd mech_list: plain login
👉 https://help.ubuntu.com/community/PostfixBasicSetupHowto
# cat >/etc/profile.d/mailenv.sh export MAIL=$HOME/Maildir
Use the instructions at https://help.ubuntu.com/community/PostfixVirtualMailBoxClamSmtpHowto to create virtual mailboxes for separate domains and non-Linux accounts; to create a virtual mailbox owner; and to set up Postfix to use virtual mailboxes.
Install Dovecot:
# apt install dovecot-core dovecot-imapd dovecot-pop3d # apt autoremove
Configure /etc/dovecot/local.conf file (as explained in
“Configure Dovecot / file /etc/dovecot/dovecot.conf
/ Ubuntu 12.04”) and change ssl = yes
in the file.
Add /usr/local/sbin/adddovecotuser and /usr/local/sbin/deldovecotuser scripts.
Add Dovecot (POP3, IMAP) users, like:
# adddovecotuser myuser@mydomain.com
Check configurations once more with the below:
👉 https://www.krizna.com/ubuntu/setup-mail-server-ubuntu-14-04/
👉 https://doc.dovecot.org/configuration_manual/dovecot_ssl_configuration/
SSL & Auth
👉 https://help.ubuntu.com/lts/serverguide/postfix.html → https://ubuntu.com/server/docs/mail-postfix
Configure Postfix for SMTP-AUTH using SASL (Dovecot SASL):
# postconf -e 'smtpd_sasl_auth_enable = yes' # postconf -e 'smtpd_sasl_security_options = noanonymous' # postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination' # postconf -e 'smtpd_sasl_type = dovecot' # postconf -e 'smtpd_sasl_path = private/auth' # postconf -e 'smtpd_sasl_local_domain =' # postconf -e 'broken_sasl_auth_clients = yes'
👉 https://ubuntu.com/server/docs/security-certificates
If your secure server is to be used in a production environment, you probably need a CA-signed certificate. It is not recommended to use a self-signed certificate. Obtain a digital certificate for TLS from Let’s Encrypt. Assuming the CA (letsencrypt) certificate resides in the /etc/letsencrypt/live/mydomain.com/ directory, run the following:
# postconf -e 'smtpd_tls_key_file = /etc/letsencrypt/live/mydomain.com/privkey.pem' # postconf -e 'smtpd_tls_cert_file = /etc/letsencrypt/live/mydomain.com/fullchain.pem'
Configure Postfix to provide TLS encryption for both incoming and outgoing mail:
# postconf -e 'smtp_tls_security_level = may' # postconf -e 'smtpd_tls_security_level = may' # postconf -e 'smtp_tls_note_starttls_offer = yes' # postconf -e 'smtpd_tls_loglevel = 1' # postconf -e 'smtpd_tls_received_header = yes' # postconf -e 'myhostname = mysrv.mydomain.com' # postconf -e 'smtp_helo_name = mail.mydomain.com'
SMTP Authentication
Postfix supports two SASL implementations Cyrus SASL and Dovecot SASL.
Check the files /etc/dovecot/conf.d/10-master.conf and /etc/dovecot/conf.d/10-auth.conf as described in https://ubuntu.com/server/docs/mail-postfix (Configuring SASL):
File /etc/dovecot/conf.d/10-master.conf:
[...] # Postfix smtp-auth unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } [...]
File /etc/dovecot/conf.d/10-auth.conf:
[...] auth_mechanisms = plain login [...]
and uncomment the following line:
disable_plaintext_auth = yes
Change also the following files:
/etc/dovecot/conf.d/10-mail.conf:
mail_location = maildir:~/Maildir
/etc/dovecot/conf.d/20-pop3.conf:
pop3_uidl_format = %08Xu%08Xv
Dovecot SSL Configuration
After a letsencrypt certificate is obtained and assuming that the certificate files are in /etc/letsencrypt/live/mydomain.com/ directory:
# cd /etc/dovecot/private # mv dovecot.key dovecot.key.old # mv dovecot.pem dovecot.pem.old # ln -s /etc/letsencrypt/live/mydomain.com/privkey.pem dovecot.key # ln -s /etc/letsencrypt/live/mydomain.com/fullchain.pem dovecot.pem
Note: The configuration file for Dovecot SSL is:
/etc/dovecot/conf.d/10-ssl.conf. As an alternative, you can change the
ssl_cert
and ssl_key
entries in that file.
Configure for Mail Submission (port 587)
Edit /etc/postfix/master.cf like this:
submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes # -o smtpd_tls_auth_only=yes # -o smtpd_reject_unlisted_recipient=no # -o smtpd_client_restrictions=$mua_client_restrictions # -o smtpd_helo_restrictions=$mua_helo_restrictions # -o smtpd_sender_restrictions=$mua_sender_restrictions # -o smtpd_recipient_restrictions= -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING
and run:
# /etc/init.d/postfix restart
Other Configurations
Banner:
# postconf -e ' smtpd_banner = mail.mydomain.com ESMTP'
Check your IP address’ abuse status (replace myipaddress with your real external IP address in the link below):
👉 https://www.anti-abuse.org/multi-rbl-check-results/?host=myipaddress
Extra configurations for spam control
👉 http://www.postfix.org/SMTPD_ACCESS_README.html#lists
Put _SPF and _DMARC records in your DNS
👉 https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf
👉 https://www.linuxbabe.com/mail-server/create-dmarc-record
Add the following TXT DNS records to your mail sending (mydomain.com) zone configuration file:
IN TXT "v=spf1 include:_spf.mydomain.com ~all" mail IN TXT "v=spf1 include:_spf.mydomain.com ~all" _dmarc IN TXT "v=DMARC1; p=none; rua=mailto:your_email_address; ruf=mailto:your_email_address; sp=reject; ri=86400" _spf IN TXT "v=spf1 ip4:ip_addr1 ip6:ip_addr2 ip4:ip_addr3 ~all"
Here, ip_addrX is the IP address(es) of your email server(s).
Check SPF records at https://dmarcian.com/.
Tell Postfix to check for SPF records for incoming emails
👉 https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf
Install:
# apt install postfix-policyd-spf-python
Add the following lines at the end of /etc/postfix/master.cf:
policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf
Merge the following lines into /etc/postfix/main.cf:
policyd-spf_time_limit = 3600 smtpd_recipient_restrictions = […], check_policy_service unix:private/policyd-spf
The first line specifies the Postfix policy agent timeout setting. The following lines will impose restriction on incoming emails by checking SPF records.
# systemctl restart postfix
Setting up DKIM
👉 https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf
Install:
# apt install opendkim opendkim-tools
Add postfix user to opendkim group:
# gpasswd -a postfix opendkim
Uncomment the following lines in /etc/opendkim.conf:
(Replace simple
with relaxed/simple
.)
Canonicalization relaxed/simple Mode sv SubDomains no
Add the following below “SubDomains no
”:
AutoRestart yes AutoRestartRate 10/1M Background yes DNSTimeout 5 SignatureAlgorithm rsa-sha256
Add the following to the end of the file:
#OpenDKIM user # Remember to add user postfix to group opendkim UserID opendkim# Map domains in From addresses to keys used to sign messages KeyTable /etc/opendkim/key.table SigningTable refile:/etc/opendkim/signing.table # Hosts to ignore when verifying signatures ExternalIgnoreList /etc/opendkim/trusted.hosts InternalHosts /etc/opendkim/trusted.hosts
Create signing table, key table and trusted hosts file:
# mkdir /etc/opendkim # mkdir /etc/opendkim/keys # chown -R opendkim:opendkim /etc/opendkim # chmod go-rw /etc/opendkim/keys # echo '*@mydomain.com default._domainkey.mydomain' \ >/etc/opendkim/signing.table # echo 'default._domainkey.mydomain' \ 'mydomain.com:default:/etc/opendkim/keys/mydomain.com/default.private' \ >/etc/opendkim/key.table # echo '127.0.0.1 localhost *.mydomain.com' >/etc/opendkim/trusted.hosts
Generate private/public key pair:
# mkdir /etc/opendkim/keys/mydomain.com # opendkim-genkey -b 2048 -d mydomain.com \ -D /etc/opendkim/keys/mydomain.com -s default -v # chown opendkim:opendkim /etc/opendkim/keys/mydomain.com/default.private
Get contents of public key:
# cat /etc/opendkim/keys/mydomain.com/default.txt
Insert it into your DNS records (for example, update /etc/bind/db.mydomain.com if you are using BIND) and check:
# opendkim-testkey -d mydomain.com -s default -vvv opendkim-testkey: using default configfile /etc/opendkim.conf opendkim-testkey: checking key 'default._domainkey.mydomain.com' opendkim-testkey: key not secure opendkim-testkey: key OK
Connect Postfix to OpenDKIM:
# mkdir /var/spool/postfix/opendkim # chown opendkim:postfix /var/spool/postfix/opendkim
Edit the socket configuration file /etc/opendkim.conf
and replace “Socket local:/var/run/opendkim/opendkim.sock
”
with:
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Add the following to the end of /etc/postfix/main.cf:
# Milter configuration # OpenDKIM milter_default_action = accept milter_protocol = 2 smtpd_milters = local:/opendkim/opendkim.sock non_smtpd_milters = local:/opendkim/opendkim.sock
Restart:
# systemctl restart opendkim ; systemctl restart postfix
To check DKIM send a test email
to
check-auth@verifier.port25.com.
A report like this should be returned from port25.com:
========================================================== Summary of Results ========================================================== SPF check: pass "iprev" check: pass DKIM check: pass SpamAssassin check: ham
Whitelist Hosts/IP Addresses
To whitelist some servers from spam lists:
# cat >/etc/postfix/rbl_override ## Don't forget: postmap /etc/postfix/rbl_override my_ip OK mydomain.com OK
add a:
check_client_access hash:/etc/postfix/rbl_override,
line to smtpd_recipient_restrictions =
entry in
/etc/postfix/main.cf file and run:
# postmap /etc/postfix/rbl_override # /etc/init.d/postfix restart
Mail Operations
- To add virtual hosts edit: /etc/postfix/vhosts.
- To add virtual Dovecot (POP3, IMAP) mailboxes edit: /etc/postfix/vmaps or (better) use adddovecotuser script.
- To add aliases (forwarding) edit: /etc/postfix/valiases. (👉 https://www.binarytides.com/postfix-mail-forwarding-debian/)
# postmap /etc/postfix/vmaps; \ postmap /etc/postfix/valiases; \ systemctl restart postfix
Sample contents of configuration files
# cat /etc/postfix/vhosts mydomain.com mydomain2.com mydomain3.com
# cat /etc/postfix/vmaps myuser@mydomain.com mydomain.com/myuser/
To define mail address aliases:
# cat /etc/postfix/valiases ### mydomain.com: myuser@mydomain.com mygmailuser@gmail.com postmaster@mydomain.com mygmailuser@gmail.com
Mail Queue Management
# mailq # qshape deferred # show deferred mails # mailq -q # attempt to deliver all queued mail! # postsuper -d ALL # delete all (or specific) queued mails from mailq # postcat -q queue_id # show contents of mail queued with queue_id
👉 https://www.lukehebert.com/2014/05/17/postfix-message-flows-and-common-issues/
👉 https://www.lukehebert.com/2014/05/04/postfix-command-reference/
👉 http://www.postfix.org/QSHAPE_README.html
Final contents of /etc/postfix/main.cf
The order of lines may be different:
smtpd_banner = mail.mydomain.com ESMTP biff = no append_dot_mydomain = no readme_directory = no compatibility_level = 3.6 smtpd_tls_cert_file = /etc/letsencrypt/live/mydomain.com/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/mydomain.com/privkey.pem smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache smtpd_relay_restrictions = permit_mynetworks,permit_sasl_authenticated,defer_unauth_destination myhostname = mysrv.mydomain.com alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases myorigin = /etc/mailname mydestination = mysrv.mydomain.com mydomain.com localhost.localdomain, localhost relayhost = mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all inet_protocols = all smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination, check_client_access hash:/etc/postfix/rbl_override, reject_rbl_client zen.spamhaus.org, reject_rhsbl_reverse_client dbl.spamhaus.org, reject_rhsbl_helo dbl.spamhaus.org, reject_rhsbl_sender dbl.spamhaus.org, check_policy_service unix:private/policyd-spf smtp_tls_security_level = may smtpd_tls_security_level = may smtp_tls_note_starttls_offer = yes smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes home_mailbox = Maildir/ virtual_mailbox_domains = /etc/postfix/vhosts virtual_mailbox_base = /home/vmail virtual_mailbox_maps = hash:/etc/postfix/vmaps virtual_minimum_uid = 1000 virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 virtual_alias_maps = hash:/etc/postfix/valiases 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 smtp_helo_name = mail.mydomain.com disable_vrfy_command = yes smtpd_sender_restrictions = reject_unknown_sender_domain smtpd_data_restrictions = reject_unauth_pipelining anvil_rate_time_unit = 600 anvil_status_update_time = 3600 policyd-spf_time_limit = 3600 milter_default_action = accept milter_protocol = 2 smtpd_milters = local:/opendkim/opendkim.sock non_smtpd_milters = local:/opendkim/opendkim.sock
Checking Once More Everything
Step by step check:
👉 https://www.linuxbabe.com/mail-server/setup-basic-postfix-mail-sever-ubuntu
Test your sending email configuration using:
👉 https://www.mail-tester.com/
DMARC:
👉 https://dmarcguide.globalcyberalliance.org/
👉 https://www.immuniweb.com/ssl/