Postfix Mail Server tutorial
Postfix is a free and open-source mail transfer agent (MTA) that routes and delivers E-mail.
What is an MTA? Well within the Internet email system, a message transfer agent (MTA), or mail transfer agent, or mail relay is software that transfers e-mail messages from one computer to another using SMTP protocol.
This guide will cover the setup of Postfix server with LDAP backend. This instance will use 2 ports, 587 and 25 for sending and recieving mails. We will setup TLS which will be used to encrypt authentication, will add restrictions for senders and recievers, add DKIM(DomainKeys Identified Mail) which is used to verify senders and Rspamd for blocking spam mails.
Install packages
Postfix
apt install postfix postfix-ldap postfix-pcre
Letsencrypt
Letsencrypt TLS certificates can be installed using certbot package.
apt install certbot
Run certbot command to create certificate
certbot certonly
Certbot nginx module can be installed to create certficates from nginx configuration
apt install python3-certbot-nginx
certbot --nginx
Rspamd and DKIM
- DomainKeys Identified Mail (DKIM) enables domain owners to automatically "sign" emails from their domain, just as the signature on a check helps confirm who wrote the check. The DKIM signature is a digital signature that uses cryptography to mathematically verify that the email came from the domain
We will install OpenDKIM package in debian to setup DKIM keys
apt install opendkim opendkim-tools mkdir dkimkeys
Setting up keys
- A DKIM selector(your_selector) is a string which is used by server sending mail to locate private key and sign email, while receiving server use it to locate public key in DNS and verify email
- The DNS record DKIM record will always be in format your_selector._domainkey.example.com
- Create DNS record as described in /etc/dkimkeys/your_selector.txt
- Configure Domain,Selector,Keyfile values in /etc/opendkim.conf.
opendkim-genkey -s "your_selector" -d "example.com" --directory /etc/dkimkeys
- Rspamd
- Rspamd is an spam filtering system and email processing framework that allows evaluation of messages by a number of rules including regular expressions, statistical analysis and custom services such as URL black lists.
- Rspamd installisation docs
Installisation
sudo apt-get install -y lsb-release wget gpg # for install
CODENAME=`lsb_release -c -s`
sudo mkdir -p /etc/apt/keyrings
wget -O- https://rspamd.com/apt-stable/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/rspamd.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ $CODENAME main" | sudo tee /etc/apt/sources.list.d/rspamd.list
echo "deb-src [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ $CODENAME main" | sudo tee -a /etc/apt/sources.list.d/rspamd.list
sudo apt-get update
sudo apt-get --no-install-recommends install rspamd
Create /etc/rspamd/local.d/milter_headers.conf
use = ["authenticated-results", "x-spam-status"];
authenticated_headers = ["authenticated-results"]
More configuration options can be found at rspamd
main.cf configuration
- Configuration files, main.cf and master.cf, are present in /etc/postfix directory.
- Postfix configuration parameters are set in main.cf. Authentication, TLS, Mail size etc are configured using main.cf
- Master.cf is used to configure postfix daemon process. SMTP ports like 25 and 587(Submission), restrictions on ports, running non-postfix commands and scripts etc can be configured here.
- We will be using 2 ports:
- port 25(smtp) for receiving mails, no authentication
- port 587(submission) for sending mail, authentication over TLS
Info about every Postfix parameter can be found in postconf manpage
man 5 postconf
Authentication
- Postfix supports Dovecot SASL and we'll use it for authentication. You can follow the instructions at Dovecot IMAP setup to configure authentication in dovecot.
Following parameters are required in main.cf for postfix to use dovecot's authentication
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
Adds authenticated user in received message header
smtpd_sasl_authenticated_header = yes
Force authentication over tls
smtpd_tls_auth_only = yes
Lookup tables
- Lookup tables are used to search and find users, mailbox path, sender login mismatch, group expansion etc
- First, let us configure an user Lookup table for local and remote mails. Create a file ldap_users.cf in /etc/postfix/ldap
server_host = localhost:389
bind = no
search_base = dc=example,dc=in
query_filter = (&(objectClass=inetOrgPerson)(mail=%s))
result_attribute = uid
Since this table is configured for virtual_alias_maps, postfix will search ldap with defined query, where %s will be substituted with email of user. For an user user@domain.com,
%s = user@domain.com
%u = user
%d = domain.com
So, for any value is passed to the table, %s substitutes the value as it is.
Next, we will define out sender login maps table. Create a file ldap_sender.cf in /etc/postfix/ldap
server_host = localhost:389
bind = no
search_base = dc=example,dc=in
query_filter = (&(objectClass=qmailUser)(mail=%s))
result_attribute = uid
Postfix cannot directly use these lookup tables, so we create local databases or .db files for postfix for it. This database can be created using postmap command. Postmap command must be run after each update to the lookup table, else changes will not be reflected in postfix
postmap /etc/postfix/ldap/ldap_users.cf
postmap /etc/postfix/ldap/ldap_sender.cf
Postmap command can also be used to test whether the lookup table is working as expected.
postmap -q user@example.com ldap:/etc/postfix/ldap/ldap_users.cf
Here %s is equal to 'user@example.com'. If the query succeeds, table will return attribute uid.
Mail Delivery
- Mail is delivered using Dovecot LMTP. More info on LMTP configuration can be found in Dovecot LMTP docs
mailbox_transport = lmtp:unix:private/dovecot-lmtp
SMTP Restrictions
- Restrictions which needs to be configured while sending mail are
- Only authenticated senders can send mails
- The username used for authentication and email in FROM address must belong to the same user
The order in which restrictions are set is important. Lets look at the sender restriction defined below. Here reject_sender_login_mismatch(postfix will reject sending mails if smtpd_sender_login_maps query fails) is followed by 2 more restrictions. So, postfix will reject sender if username and email does not belong to same user, allow authenticated users and reject all others. Since we set reject_sender_login_mismatch as the first restriction, the user will not be able to send mails if this check fails.
smtpd_sender_restrictions = reject_sender_login_mismatch,
permit_sasl_authenticated,
reject
- Relay restrictions
- Relays are smtp servers which can be used to send mails. Most service providers relays use authentication before sending mails. Else, any one can send mails which will cause spam mails, hence the deliverability of mail. Most service providers will reject mails from our server if it is used to send out spam mail.
- An open relay does not require authentication to send mails.
smtpd_relay_restrictions = permit_mynetworks,
permit_sasl_authenticated,
defer_unauth_destination,
- Recipient restricitons
- These restrictions are applied to the addresses in TO field.
smtpd_recipient_restrictions = permit_mynetworks,
reject_invalid_helo_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
warn_if_reject reject_unknown_helo_hostname,
warn_if_reject reject_unknown_reverse_client_hostname,
reject_unknown_sender_domain,
reject_unknown_recipient_domain
- Postfix Lookup Tables
- Lookup tables are used for user and mailbox lookup, sender vertification, group expansion etc.
- The tables defined in this section are LDAP lookup tables. The virtual alias map configured here will return an LDAP attribute(uid or mail) on passing an email or username to the user lookup tabloe(ldap_users.cf)
- smtpd_sender_login_maps checks whether username used to authenticate against server and FROM address are owned by the same user
More documentation can be found at LDAP tables or man 5 ldap_table
virtual_alias_maps = ldap:/etc/postfix/ldap/ldap_users.cf
smtpd_sender_login_maps = ldap:/etc/postfix/ldap/ldap_sender.cf
TLS
- TLS is configured for both smtp and submission ports.
- We can either enforce or use oppurtunistic TLS.
- encrypt: force the SMTP server to use TLS which is used by submission port.
- may - oppurtunistic(StartTLS), TLS is used only if the server supports it and is configured for smtp(25) port
smtpd_tls_security_level = encrypt
smtp_tls_security_level = may
smtpd_tls_manditory_ciphers = high
smtpd_tls_loglevel = 1
Log hostname of remote server that offers StartTLS
smtp_tls_note_starttls_offer = yes
Define allowed and blocked TLS protocols, ciphers
smtpd_tls_mandatory_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
smtpd_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
Configure TLS certificate path
smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
DKIM and Spam filter
- DKIM key, Rspamd and other mail filters are configured in postfix using smtpd_milters parameter in main.cf
# OpenDKIM host Rspamd host
smtpd_milters = inet:localhost:8892 inet:localhost:11332
milter_default_action = accept
non_smtpd_milters = $smtpd_milters
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
Additional configuration
- Disable VRFY command. VRFY command is used to verify that mailbox exists on server and since it adds additional load, we will disable it.
- Enforce server to send HELO command before MAIL command
disable_vrfy_command = yes
smtpd_helo_required = yes
master.cf configuration
- Modify configuration for port 25/smtp to enable StartTLS and disable authentication
smtp inet n - y - - smtpd
-o smtpd_tls_security_level=may
-o smtpd_sasl_auth_enable=no
- Uncomment 587/submission and add the following params
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_client_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject
- Commented out arguments need not be deleted