Postfix is the most widely deployed open-source mail transfer agent — it is the default MTA on most Linux distributions and the sending backbone for many small-to-medium commercial email programmes. For programmes below 500,000 monthly messages that require a self-managed MTA without the licensing cost of PowerMTA, Postfix configured correctly provides reliable, authenticated delivery with good deliverability characteristics. This guide covers the Postfix configuration specific to commercial outbound email: DKIM signing, TLS setup, rate limiting, and the monitoring configuration that provides delivery visibility without PowerMTA's accounting log.

Open source
Postfix is free — no licensing cost for any volume level
OpenDKIM
Standard DKIM signing integration for Postfix — required for MAGY compliance
~500K/month
Practical volume ceiling before PowerMTA provides significantly better operational control
mail.log
Postfix delivery log — primary diagnostic tool, requires log parsing for structured monitoring

Postfix Overview and When to Use It

Postfix is appropriate for commercial email programmes that need a self-managed MTA with full authentication configuration and direct IP control, at volumes below approximately 500,000 messages per month. Its strengths: free and open source (no licensing cost), extremely stable and well-documented, integrates cleanly with standard Linux mail tools (OpenDKIM, Amavis, SpamAssassin), and provides direct access to mail logs for delivery monitoring. Its limitations compared to PowerMTA: no built-in per-domain connection pool management with the granularity of PowerMTA's domain blocks, no native accounting log in structured format (delivery monitoring requires log parsing), and less flexible queue management for high-volume batch sending. For programmes below the volume threshold where PowerMTA's additional capabilities are needed, Postfix is the correct choice — it is operationally simpler and costs nothing.

Installation and Basic Configuration

Install Postfix on AlmaLinux 8/RHEL 8 or Debian/Ubuntu:

# AlmaLinux 8 / RHEL 8
dnf install postfix -y
systemctl enable postfix
systemctl start postfix

# Ubuntu/Debian
apt-get install postfix -y
systemctl enable postfix

The primary Postfix configuration file is /etc/postfix/main.cf. The minimum configuration for outbound commercial email sending:

# /etc/postfix/main.cf — basic outbound configuration

# Server identity
myhostname = mail1.brand.com        # Must match PTR record
mydomain = brand.com
myorigin = $mydomain

# Accept mail only from localhost (relay server configuration)
inet_interfaces = loopback-only     # Only accept from local applications
mynetworks = 127.0.0.0/8

# Don't accept incoming mail for local delivery (outbound relay only)
mydestination =

# Relay host (empty = deliver directly to destination MX)
relayhost =

# Queue management
maximal_queue_lifetime = 5d         # Maximum time a message waits
bounce_queue_lifetime = 1d          # Fast bounce for permanent failures
minimal_backoff_time = 300s         # Minimum retry wait (5 minutes)
maximal_backoff_time = 4000s        # Maximum retry wait (~66 minutes)

# SMTP client settings (outbound)
smtp_connect_timeout = 30s
smtp_helo_timeout = 30s
smtp_rcpt_timeout = 30s
smtp_data_init_timeout = 120s
smtp_data_done_timeout = 600s

# Hostname in EHLO/HELO must match PTR record
smtp_helo_name = $myhostname

# Connection limits
default_destination_concurrency_limit = 20   # Max concurrent connections per domain
smtp_destination_concurrency_limit = $default_destination_concurrency_limit
smtp_destination_rate_delay = 0              # No delay between messages per connection

# Allow slightly more connections to major ISPs
gmail.com_destination_concurrency_limit = 20
outlook.com_destination_concurrency_limit = 15
yahoo.com_destination_concurrency_limit = 15

DKIM Signing with OpenDKIM

OpenDKIM is the standard DKIM signing milter for Postfix. Installation and configuration for outbound DKIM signing:

# Install OpenDKIM
dnf install opendkim opendkim-tools -y

# Generate 2048-bit DKIM key pair for brand.com
mkdir -p /etc/opendkim/keys/brand.com
opendkim-genkey -b 2048 -d brand.com -s mail     -D /etc/opendkim/keys/brand.com/
chown -R opendkim:opendkim /etc/opendkim/keys/

# View the DNS record to publish:
cat /etc/opendkim/keys/brand.com/mail.txt
# Example output:
# mail._domainkey IN TXT "v=DKIM1; k=rsa; p=PUBLIC_KEY_HERE"
# Publish this TXT record in brand.com DNS

Configure OpenDKIM (/etc/opendkim.conf):

# /etc/opendkim.conf

Mode                sv              # Sign and verify (sv) or sign only (s)
PidFile             /run/opendkim/opendkim.pid
Syslog              yes
SyslogSuccess       yes
LogWhy              yes

# Signing configuration
Domain              brand.com
KeyFile             /etc/opendkim/keys/brand.com/mail.private
Selector            mail
SignatureAlgorithm  rsa-sha256
Canonicalization    relaxed/relaxed

# Headers to sign (cover the headers that matter for deliverability)
SignHeaders         from,to,subject,date,message-id,content-type,mime-version,                    list-unsubscribe,list-unsubscribe-post

# Socket for Postfix milter integration
Socket              local:/run/opendkim/opendkim.sock

Connect OpenDKIM to Postfix by adding to /etc/postfix/main.cf:

# /etc/postfix/main.cf — add milter configuration
smtpd_milters = local:/run/opendkim/opendkim.sock
non_smtpd_milters = local:/run/opendkim/opendkim.sock
milter_default_action = accept     # If milter unavailable, still deliver
milter_protocol = 6

TLS Configuration for Outbound Sending

TLS is required for MAGY compliance — all outbound SMTP connections must use TLS encryption. Configure Postfix's SMTP client (outbound sender) for TLS:

# /etc/postfix/main.cf — TLS outbound configuration

# Require TLS for all outbound connections
smtp_tls_security_level = encrypt        # encrypt = require TLS, fail if unavailable
smtp_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtp_tls_mandatory_ciphers = high        # Require strong ciphers
smtp_tls_loglevel = 1                    # Log TLS connection details
smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt  # CA certificate bundle

# Session caching for performance
smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_scache
smtp_tls_session_cache_timeout = 3600s

# For the sending hostname's TLS certificate (required for inbound, used for EHLO)
smtpd_tls_cert_file = /etc/letsencrypt/live/mail1.brand.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail1.brand.com/privkey.pem

Obtain a TLS certificate for the sending hostname using Let's Encrypt (free) or a commercial CA. The certificate must be valid for mail1.brand.com (the hostname configured in myhostname). Renew Let's Encrypt certificates every 90 days — set up automated renewal with certbot:

# Install certbot and obtain certificate
dnf install certbot -y
certbot certonly --standalone -d mail1.brand.com

# Auto-renewal cron (runs twice daily, renews within 30 days of expiry)
echo "0 0,12 * * * root certbot renew --quiet --post-hook 'postfix reload'"     > /etc/cron.d/certbot-renewal

Rate Limiting and Per-Domain Controls

Postfix supports per-domain sending rate controls through the smtp_destination_concurrency_limit and per-domain override configuration. For commercial email, calibrate these per major ISP:

# /etc/postfix/main.cf — per-domain rate controls

# Global defaults
default_destination_concurrency_limit = 5   # Conservative default for unknown domains
smtp_destination_concurrency_limit = $default_destination_concurrency_limit

# Override per major ISP (add as transport_maps entries or direct overrides)
# Major ISP rate limits at High reputation:
gmail.com_destination_concurrency_limit = 20
yahoo.com_destination_concurrency_limit = 15
ymail.com_destination_concurrency_limit = 15
outlook.com_destination_concurrency_limit = 12
hotmail.com_destination_concurrency_limit = 12
live.com_destination_concurrency_limit = 12
msn.com_destination_concurrency_limit = 12

# EU ISPs at moderate volume
gmx.com_destination_concurrency_limit = 10
gmx.net_destination_concurrency_limit = 10
web.de_destination_concurrency_limit = 10

# Message rate limits (messages per connection)
smtp_destination_recipient_limit = 100  # Max recipients per connection

SPF and Sender Restriction Configuration

For an outbound relay configuration (where Postfix only sends email from authorised applications), configure sender restrictions to prevent unauthorized use:

# /etc/postfix/main.cf — sender restrictions for relay security
# These apply to SMTP clients submitting email through Postfix

smtpd_sender_restrictions =
    permit_mynetworks,    # Allow from local network (authorised applications)
    reject_unknown_sender_domain  # Reject if sender domain has no MX or A record

smtpd_recipient_restrictions =
    permit_mynetworks,
    reject_unauth_destination  # Prevent open relay

# Submission port (587) for authenticated client connections
# /etc/postfix/master.cf — add submission service
# submission inet n - n - - smtpd
#   -o smtpd_tls_security_level=encrypt
#   -o smtpd_sasl_auth_enable=yes
#   -o smtpd_sasl_type=dovecot

Postfix Logging and Monitoring

Postfix logs all delivery events to the system mail log (/var/log/maillog on AlmaLinux, /var/log/mail.log on Debian/Ubuntu). The log format is human-readable but requires parsing for structured monitoring. Each delivery event produces a log line with the queue ID, the recipient, the destination server, the SMTP response, and the delivery status:

# Example Postfix delivery log entries:
Nov 19 14:23:01 mail1 postfix/smtp[12345]: 3A4B5C6D7E8F: 
  to=<recipient@gmail.com>, relay=gmail-smtp-in.l.google.com[142.250.31.26]:25,
  delay=0.8, delays=0.05/0.01/0.5/0.24,
  dsn=2.0.0, status=sent (250 2.0.0 OK)

# Bounce event:
Nov 19 14:24:15 mail1 postfix/smtp[12346]: 3A4B5C6D7EFF:
  to=<invalid@example.com>, relay=mx.example.com[198.51.100.1]:25,
  delay=1.2, dsn=5.1.1, status=bounced (550 5.1.1 User unknown)

# Throttle (4xx) event:
Nov 19 14:25:32 mail1 postfix/smtp[12347]: 3A4B5C6D7FAA:
  to=<user@yahoo.com>, relay=mta7.am0.yahoodns.net[98.137.65.151]:25,
  delay=4.3, dsn=4.7.0, status=deferred (421 4.7.0 [TSS04] Messages deferred)

For structured monitoring from Postfix logs, use pflogsumm (Postfix Log Summary) for daily reports or a log parsing script that extracts delivery status, SMTP response codes, and destination domains into a structured database for operational queries. The monitoring gap versus PowerMTA: Postfix does not provide the per-event structured data that PowerMTA's accounting log delivers — monitoring requires post-processing of human-readable log files rather than real-time consumption of structured per-event records.

Postfix vs PowerMTA: When to Upgrade

The indicators that suggest upgrading from Postfix to PowerMTA (or a similar commercial MTA):

  • Volume above 500K monthly: PowerMTA's connection pool management, per-domain domain blocks, and accounting log become operationally valuable at this volume.
  • Multi-client / multi-tenant sending: PowerMTA's VMTA architecture allows per-client IP isolation that Postfix cannot replicate without complex separate Postfix instances.
  • Deliverability investigation time: If more than 2 hours per month is spent diagnosing delivery problems from Postfix log parsing that would be resolved in minutes with PowerMTA's structured accounting log data, the operational time cost justifies the licence investment.
  • Advanced retry logic per ISP: PowerMTA's per-domain retry sequences and connection pool controls provide significantly more granular ISP-specific delivery optimisation than Postfix's global retry settings.

Below these thresholds, Postfix correctly configured with OpenDKIM, TLS, and per-ISP concurrency controls provides excellent outbound delivery for commercial email programmes at zero software cost. The configuration documented in this guide produces authenticated, TLS-encrypted delivery with per-ISP rate limiting — sufficient for reliable inbox placement at volumes below the commercial MTA investment threshold. Configure it correctly from initial setup; monitor the mail log for delivery problems; and Postfix will deliver email reliably for as long as the programme needs it to.

Verifying the Complete Postfix Configuration

After completing the Postfix + OpenDKIM + TLS configuration, run a full end-to-end verification before sending production email. The verification sequence:

# Step 1: Check Postfix configuration syntax
postfix check

# Step 2: Verify OpenDKIM is running and signing
systemctl status opendkim
# Should show: active (running)

# Step 3: Send a test message and check headers
echo "Test message body" | mail -s "Postfix deliverability test" test@mail-tester.com

# Step 4: Check the mail-tester.com score (submit test email to get the URL)
# A correctly configured Postfix installation should score 9-10/10 on mail-tester.com

# Step 5: Verify authentication headers in a delivered message
# Send test to a Gmail seed address and check full headers:
# Authentication-Results should show:
# spf=pass dkim=pass (d=brand.com) dmarc=pass

The mail-tester.com score provides the broadest single-step configuration verification -- it checks SPF, DKIM, DMARC, blacklist status, content scoring, and TLS simultaneously. A score below 8/10 on mail-tester.com indicates configuration gaps that will affect deliverability and should be resolved before the first production send.

Production Hardening Checklist

Before using Postfix for any production commercial email sending, verify these additional hardening steps: (1) PTR record set by hosting provider for the sending IP -- required for Microsoft 365 delivery. (2) Firewall allows outbound port 25 from the server to all destinations (many VPS providers block port 25 by default -- request an unblock from the provider). (3) Postfix log rotation configured to prevent disk-filling log accumulation. (4) Daily pflogsumm summary email set up to provide delivery status visibility without real-time log monitoring. (5) Let's Encrypt auto-renewal configured and tested -- a certificate expiry causes TLS failures that produce delivery rejections.

Postfix, configured with the settings documented in this guide, is a production-capable outbound MTA that reliably delivers authenticated commercial email. It is not the most feature-rich option -- that distinction goes to PowerMTA -- but for programmes where open-source infrastructure, zero licensing cost, and straightforward Linux system administration are priorities, Postfix delivers commercial email effectively at the volumes for which it is appropriately scaled.

Common Postfix Deliverability Problems and Fixes

Problem: Mail deferred with "Connection refused" to destination MX -- This typically means port 25 is blocked by the hosting provider or a firewall rule. Check: telnet gmail-smtp-in.l.google.com 25. If connection is refused, contact the hosting provider to unblock outbound port 25 for the server IP.

Problem: dkim=fail in Authentication-Results despite OpenDKIM running -- Verify the DKIM public key in DNS matches the private key in /etc/opendkim/keys/. Check that the selector name in opendkim.conf matches the DNS record subdomain. Verify OpenDKIM socket permissions allow Postfix to connect: ls -la /run/opendkim/opendkim.sock should show group ownership accessible to Postfix.

Problem: Messages deferred with "TLS is required" at destination -- The destination server requires TLS but the Postfix client cannot establish a TLS connection. Check the sending server's TLS certificate is valid and not expired. Verify smtp_tls_security_level = encrypt is set and the CA bundle path is correct for the Linux distribution.

Problem: High deferral rate at Gmail with "421 Try again later" -- Gmail is rate-limiting the sending IP. Reduce gmail.com_destination_concurrency_limit from 20 to 10-12, and ensure the sending IP has built reputation through warmup before attempting high-volume sends. Monitor Postmaster Tools for the sending domain to track reputation building over time.

Postfix troubleshooting requires familiarity with the mail log format -- most problems leave clear diagnostic messages in /var/log/maillog. When a delivery problem appears, the sequence is: (1) identify the affected destination domain from the log, (2) read the SMTP response code and message, (3) cross-reference with the SMTP error code reference to determine whether the response is a permanent failure (5xx), temporary deferral (4xx), or a configuration problem. The mail log is verbose but complete -- every delivery attempt is recorded with the information needed to diagnose the outcome.

H
Henrik Larsen

MTA Operations Manager at Cloud Server for Email. Specialising in email deliverability, infrastructure architecture, and high-volume sending operations.