Postfix Mail Server tutorial

Postfix Mail Server tutorial
Photo by Alternate Skate / Unsplash

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