Level 2

Postfix mail server: installation, configuration, and relay control

Maximilian B. 10 min read 14 views

Postfix is the production Mail Transfer Agent (MTA) on most Linux mail servers. It replaced Sendmail as the default on Debian, Ubuntu, and RHEL-family distributions because it is modular, secure by default, and straightforward to configure. But "straightforward" still means hundreds of parameters, a multi-process architecture, and relay controls that can lock you out of your own mail or turn your server into an open relay if you get them wrong. This article covers Postfix installation, core configuration, relay control, TLS encryption, SASL authentication, and queue management for a production deployment.

Postfix Architecture and Multi-Process Design

Postfix mail server: installation, configuration, and relay control visual summary diagram
Visual summary of the key concepts in this guide.

Postfix is not a single daemon. It is a collection of cooperating processes, each handling one part of the mail pipeline. The master process (master) supervises everything. Understanding this architecture is key to troubleshooting delivery issues in the broader Linux email architecture. Key components:

Postfix multi-process architecture diagram showing the master supervisor process and all cooperating daemons: smtpd (incoming SMTP from remote MTAs and MUA clients on ports 25, 587, 465), pickup (local process submissions), cleanup (header rewriting), the mail queue (incoming, active, deferred, hold), qmgr (queue manager and retry scheduler), trivial-rewrite (address resolution), smtp client (outgoing delivery to remote MTAs), local/lmtp (local mailbox delivery to Maildir or Dovecot), and bounce/defer (DSN generation)
  • smtpd — the SMTP server. Accepts incoming connections on ports 25, 587, and 465. Enforces access controls and relay restrictions.
  • smtp — the SMTP client. Delivers outgoing mail to remote servers.
  • pickup — monitors the maildrop directory for locally submitted messages (from sendmail command, cron jobs, etc.).
  • cleanup — processes every message entering the queue: adds missing headers, rewrites addresses, runs header/body checks.
  • qmgr — the queue manager. Schedules delivery attempts, manages deferred mail, and controls retry timing.
  • trivial-rewrite — resolves addresses and determines routing (local vs. relay vs. transport maps).
  • bounce — generates bounce (DSN) messages for undeliverable mail.

The master process configuration lives in /etc/postfix/master.cf. Each line defines a service, its type (inet, unix, fifo), privilege level, and command. You rarely edit master.cf for basic setups, but you will need it for enabling submission (port 587), SMTPS (port 465), or content filters.

Postfix Installation and Initial Configuration on Linux

# Debian 13.3 / Ubuntu 24.04.3 LTS
sudo apt install postfix
# During installation, select "Internet Site" and enter your mail hostname.

# Fedora 43 / RHEL 10.1
sudo dnf install postfix
sudo systemctl enable --now postfix

After installation, the main configuration file is /etc/postfix/main.cf. Here are the parameters you must set correctly for any production mail server:

# /etc/postfix/main.cf - key parameters

# Identity
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain

# What interfaces and addresses to listen on
inet_interfaces = all
inet_protocols = ipv4

# Which domains this server is the final destination for
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain

# Trusted networks allowed to relay without authentication
mynetworks = 127.0.0.0/8, [::1]/128

# Mailbox delivery (use Dovecot LMTP for production)
# For simple setups:
home_mailbox = Maildir/
# For Dovecot LMTP (recommended):
# virtual_transport = lmtp:unix:private/dovecot-lmtp

# Queue and size limits
message_size_limit = 52428800
mailbox_size_limit = 0

# Banner (do not expose software version)
smtpd_banner = $myhostname ESMTP

Use postconf to inspect and modify parameters without editing the file directly:

# Show all non-default settings
postconf -n

# Show a specific parameter
postconf myhostname

# Set a parameter (writes to main.cf)
sudo postconf -e "myhostname = mail.example.com"

# After changes, reload (not restart, to avoid dropping active connections)
sudo postfix reload

Verifying Postfix configuration after changes

Always validate your configuration before reloading. A syntax error in main.cf can prevent Postfix from starting:

# Check for configuration errors
sudo postfix check

# Compare your settings against defaults to spot unintended changes
postconf -n | sort

# Test that Postfix can resolve its own hostname
postconf myhostname mydomain myorigin

# Verify listening sockets after reload
ss -tlnp | grep master

Postfix Relay Control: Preventing Open Relay Attacks

An open relay accepts and forwards mail from anyone to anywhere. Spammers scan for open relays constantly. Within hours of misconfiguring relay controls, your server IP will land on blacklists. These parameters control relay behavior and are critical for Linux server security:

Flowchart of Postfix smtpd_recipient_restrictions evaluation: SMTP RCPT TO received, check permit_mynetworks (permit if yes), check permit_sasl_authenticated (permit if yes), check reject_unauth_destination (continue if local destination, reject with 554 if external and unauthenticated), followed by additional RBL and domain checks before final acceptance — with open relay risk warning and correct rule ordering

Restricting relay with mynetworks

Clients connecting from IPs in mynetworks can relay without authentication. Keep this as tight as possible — typically just localhost.

# Only localhost can relay without auth
mynetworks = 127.0.0.0/8, [::1]/128

# If you have a trusted internal network (be very careful):
# mynetworks = 127.0.0.0/8, [::1]/128, 10.0.1.0/24

Controlling relay_domains

Domains that this server will relay for (accept mail from the internet and forward to another server). By default this is empty, meaning Postfix only relays for domains listed in mydestination or virtual domain maps.

Configuring smtpd_recipient_restrictions

This is the primary access control list evaluated when a client sends RCPT TO. Order matters. Postfix evaluates rules top to bottom and stops at the first match.

smtpd_recipient_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unauth_destination,
    reject_invalid_hostname,
    reject_non_fqdn_sender,
    reject_non_fqdn_recipient,
    reject_unknown_sender_domain,
    reject_unknown_recipient_domain,
    reject_rbl_client zen.spamhaus.org

reject_unauth_destination is the critical rule. It rejects any mail that is not destined for your local domains and did not come from a trusted network or authenticated user. Without this rule, you have an open relay.

Never place permit before reject_unauth_destination in the restriction list. Doing so creates an open relay. Always test relay behavior after any access control change by sending mail from an external host to an external destination through your server — it must be rejected.

Postfix TLS Configuration for Encrypted Email Transport

Postfix TLS support covers both incoming (smtpd) and outgoing (smtp) connections. On a 2026 production server, TLS is mandatory. Pair this with proper certificate management practices to ensure your encryption chain is solid.

# Incoming TLS (smtpd - server side)
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_protocols = >=TLSv1.2
smtpd_tls_mandatory_protocols = >=TLSv1.2
smtpd_tls_loglevel = 1

# Outgoing TLS (smtp - client side)
smtp_tls_security_level = may
smtp_tls_protocols = >=TLSv1.2
smtp_tls_loglevel = 1
smtp_tls_CApath = /etc/ssl/certs

# For port 587 submission and port 465 SMTPS, enable in master.cf:
# submission inet n - y - - smtpd
#   -o smtpd_tls_security_level=encrypt
#   -o smtpd_sasl_auth_enable=yes
#   -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject

# smtps inet n - y - - smtpd
#   -o smtpd_tls_wrappermode=yes
#   -o smtpd_sasl_auth_enable=yes

The security_level=may on port 25 means Postfix will use TLS if the remote server supports it but will not require it (opportunistic TLS). This is correct for server-to-server relay because many legitimate servers still lack TLS. For submission ports (587, 465), set security_level=encrypt so clients must use TLS.

Enabling submission and SMTPS in master.cf

The master.cf file controls which services Postfix runs. To accept authenticated client submissions, uncomment and configure the submission and smtps services:

# /etc/postfix/master.cf - uncomment and configure these blocks

# Port 587 - STARTTLS submission
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_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

# Port 465 - implicit TLS (SMTPS)
smtps     inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

SASL Authentication with Dovecot Backend

SASL lets remote MUAs authenticate before relaying. Postfix itself does not handle authentication; it delegates to Dovecot's SASL implementation (recommended) or Cyrus SASL.

# main.cf - enable SASL via Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname

# Dovecot side (/etc/dovecot/conf.d/10-master.conf)
# Add a service auth section:
# service auth {
#   unix_listener /var/spool/postfix/private/auth {
#     mode = 0660
#     user = postfix
#     group = postfix
#   }
# }

With SASL enabled and permit_sasl_authenticated in your recipient restrictions, authenticated users can relay through your server from any IP. This is how roaming email clients (phones, laptops) send mail through your server.

Virtual Domains, Mailbox Maps, and Alias Configuration

For hosting multiple domains on one Postfix instance, use virtual domain support instead of mydestination:

# main.cf
virtual_mailbox_domains = example.com, example.org, example.net
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_alias_maps = hash:/etc/postfix/virtual

# /etc/postfix/vmailbox - maps addresses to mailbox locations
user@example.com    example.com/user/
info@example.org    example.org/info/

# /etc/postfix/virtual - aliases
admin@example.com   user@example.com
postmaster@example.com  user@example.com
@example.net        catchall@example.com

# After editing, rebuild the hash maps:
sudo postmap /etc/postfix/vmailbox
sudo postmap /etc/postfix/virtual
sudo postfix reload

The postmap command compiles text lookup tables into indexed .db files that Postfix reads at runtime. Always run postmap after editing any hash-type map file.

Using transport maps for per-domain routing

When different domains need different delivery backends (some to local Dovecot, some to an external server), use transport maps:

# main.cf
transport_maps = hash:/etc/postfix/transport

# /etc/postfix/transport
example.com         lmtp:unix:private/dovecot-lmtp
example.org         smtp:[backup-mx.example.org]:25
internal.example.com  lmtp:inet:10.0.1.50:24

# Rebuild and reload
sudo postmap /etc/postfix/transport
sudo postfix reload

Header and Body Checks for Content Filtering

Configuring header and body checks

Postfix can inspect message headers and body content using regular expressions. This provides a first layer of content filtering before messages reach Rspamd or Sieve for more advanced spam control.

# main.cf
header_checks = regexp:/etc/postfix/header_checks
body_checks = regexp:/etc/postfix/body_checks

# /etc/postfix/header_checks
/^Subject:.*\bviagra\b/i    REJECT Spam content detected
/^X-Mailer: SuperSpamBot/   REJECT Known spam tool

# /etc/postfix/body_checks
/click here to claim your prize/i   REJECT Spam body content

Connection rate limiting against brute-force attacks

Protect against brute-force attacks and excessive connections:

# main.cf - rate limiting
smtpd_client_connection_rate_limit = 30
smtpd_client_message_rate_limit = 60
smtpd_client_recipient_rate_limit = 120
smtpd_error_sleep_time = 5s
smtpd_soft_error_limit = 10
smtpd_hard_error_limit = 20

# anvil service tracks client connection rates
# Defined in master.cf (default is already present):
# anvil    unix  -       -       y       -       1       anvil

Postfix Mail Queue Management Commands

# View the queue
mailq

# Count queued messages
mailq | tail -1

# Flush all deferred mail (retry now)
postqueue -f

# Flush mail for a specific domain
postqueue -s example.com

# Put a message on hold
postsuper -h QUEUE_ID

# Release a held message
postsuper -H QUEUE_ID

# Delete a message from the queue
postsuper -d QUEUE_ID

# Delete ALL messages (nuclear option)
postsuper -d ALL

# Requeue messages (reprocess through cleanup)
postsuper -r ALL

# View the content of a queued message
postcat -q QUEUE_ID

Quick Reference - Cheats

Task Command
Show non-default config postconf -n
Show all config (including defaults) postconf
Set a parameter postconf -e "param = value"
Rebuild lookup table postmap /etc/postfix/virtual
Reload config (no downtime) postfix reload
Check config syntax postfix check
View mail queue mailq
Flush deferred mail postqueue -f
Delete queued message postsuper -d QUEUE_ID
Read queued message postcat -q QUEUE_ID
Test SMTP relay manually openssl s_client -connect mail.example.com:587 -starttls smtp
Show TLS session info in logs Set smtpd_tls_loglevel = 1

Summary

A production Postfix mail server deployment requires getting several things right simultaneously: identity parameters (myhostname, mydomain, myorigin), relay controls (mynetworks, smtpd_recipient_restrictions with reject_unauth_destination), TLS certificates for both incoming and outgoing connections, and SASL authentication for roaming clients.

The most dangerous misconfiguration is an open relay, which takes minutes to exploit and days to recover from (IP blacklist removal). Always test relay behavior from an external host after any access control change. Use postconf -n to audit your running configuration and postfix check to validate syntax before reloading.

For multi-domain hosting, virtual domains with postmap-compiled lookup tables give you flexible address routing. For delivery, hand off to Dovecot LMTP rather than writing to local mailboxes directly. And keep your queue clean — a growing deferred queue is almost always a sign of DNS problems, remote server issues, or a compromised account sending spam.

Share this article
X / Twitter LinkedIn Reddit