Postfix SMTP server

21 September,2023

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 package

  apt install postfix

Configure Postfix

Authentication

Mail delivery

User lookup and Sender verification

Postfix uses lookup tables to store and query information about users, mailboxes, access control, address rewriting and even content filtering. We will create two such tables for LDAP lookup.

  server_host = localhost:389
  bind = no
  search_base = dc=example,dc=in
  query_filter = (&(oddbjectClass=qmailUser)(mail=%s))
  result_attribute = uid
  virtual_alias_maps = ldap:/etc/postfix/ldap/ldap_users.cf
  smtpd_sender_login_maps = ldap:/etc/postfix/ldap/ldap_check_sender.cf

TLS

  smtpd_tls_security_level = encrypt
  smtpd_tls_manditory_ciphers = high
  smtpd_tls_loglevel = 1
  # Block TLS less than v1.2
  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
  # Change certificate location.
  smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
  smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
  # Following parameter will log servers that offer STARTTLS
  smtp_tls_note_starttls_offer = yes

SMTP Restrictions

Postfix allows you to specify lists of access restrictions for each stage of the SMTP conversation. Each restriction list is evaluated from left to right until some restriction produces a result of PERMIT, REJECT or DEFER (try again later). The end of each list is equivalent to a PERMIT result. By placing a PERMIT restriction before a REJECT restriction you can make exceptions for specific clients or users.

  smtpd_sender_restrictions = reject_sender_login_mismatch,
    permit_sasl_authenticated,

  smtpd_relay_restrictions = permit_mynetworks,
    permit_sasl_authenticated,
    defer_unauth_destination,

  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

Configure master file

  smtp      inet  n       -       y       -       -       smtpd
    -o smtpd_tls_security_level=may
    -o smtpd_sasl_auth_enable=no
  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

DKIM and Rspamd with Postfix

Letsencrypt certificates

Example config

An example main.cf config file

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 2

# TLS parameters
smtpd_tls_mandatory_ciphers = high
smtpd_tls_security_level = encrypt
smtpd_tls_loglevel = 1
smtpd_tls_eecdh_grade = ultra
smtpd_tls_auth_only = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/example.in/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/example.in/privkey.pem
smtp_tls_note_starttls_offer = yes
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

smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

myhostname = example.in
myorigin = $myhostname
mydestination = example.in
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
recipient_delimiter = +
mailbox_size_limit = 0
# message size limit is 50MB
message_size_limit = 52428800
inet_interfaces = all
inet_protocols = all

# User Authentication
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes

# LDAP user table
virtual_alias_maps = ldap:/etc/postfix/ldap/ldap_users.cf
smtpd_sender_login_maps = ldap:/etc/postfix/ldap/ldap_check_sender.cf

# LMTP
mailbox_transport = lmtp:unix:private/dovecot-lmtp

# DKIM keys, Rspamd and mail filters
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}

# Policy and restrictions
smtpd_sender_restrictions = reject_sender_login_mismatch,
  permit_sasl_authenticated,
smtpd_relay_restrictions = permit_mynetworks,
  permit_sasl_authenticated,
  defer_unauth_destination
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,

disable_vrfy_command = yes
smtpd_helo_required = yes
strict_rfc821_envelopes = yes