Postfix is a Mail Transfer Agent (MTA) for routing and delivering email. Proxmox Mail Gateway (PMG) is a mail security gateway that filters spam and viruses before delivery. This reference covers both.
Postfix Queue Management
Viewing the Queue
# Show the mail queue (aliased to mailq)
mailq
# or
postqueue -p
# Show queue with detailed status codes
postqueue -p | grep -E "^\w{10,}" | head -20
# Count messages in queue
mailq | tail -1
# Output: -- 0 Kbytes in 5 Requests.
# Show queue ID and size
mailq | grep -E "^[A-F0-9]"
# Show deferred queue only
mailq | grep -A 1 "^[A-F0-9]" | grep -v "^--$"
# Show active queue
postqueue -p | grep -B1 "Status: active"Queue Manipulation
# Flush the queue (attempt delivery of all queued mail)
postqueue -f
# Flush only deferred mail
postsuper -r ALL && postqueue -f
# Delete all mail from queue
postsuper -d ALL
# Delete a specific message by queue ID
postsuper -d ABCDEF1234
# Delete all deferred messages
postsuper -d ALL deferred
# Re-queue all mail (mark for immediate delivery attempt)
postsuper -r ALL
# Re-queue a specific message
postsuper -r ABCDEF1234
# Hold a message (prevent delivery)
postsuper -h ABCDEF1234
# Release a held message
postsuper -H ABCDEF1234
# Show held messages
mailq | grep -B1 "Status: hold"Queue Inspection
# View message content (headers + body)
postcat -q ABCDEF1234
# View headers only
postcat -q -h ABCDEF1234
# View queue summary by domain
mailq | grep -oP '\b\w+@\K[\w.-]+' | sort | uniq -c | sort -rn
# Show queue age distribution
mailq | awk '/^[A-F0-9]/{print $2}' | sort | head
# Find messages from a specific sender
postqueue -p | grep -B2 "[email protected]"Mail Logs
log File Analysis
# Main mail log
tail -f /var/log/mail.log
# Debian/Ubuntu: /var/log/mail.log
# RHEL/CentOS: /var/log/maillog
# Show recent deliveries
tail -100 /var/log/mail.log | grep "status=sent"
# Show deferrals
tail -100 /var/log/mail.log | grep "status=deferred"
# Show bounces
tail -100 /var/log/mail.log | grep "status=bounced"
# Show rejected connections
grep "rejected" /var/log/mail.log
# Show connections from a specific IP
grep "192.168.1." /var/log/mail.logjournalctl
# View Postfix logs via journald
journalctl -u postfix -n 100 -f
# View logs since yesterday
journalctl -u postfix --since yesterday
# Show deferrals only
journalctl -u postfix -n 500 | grep "status=deferred"
# Show logs for a specific queue ID
journalctl -u postfix | grep ABCDEF1234
# Show logs in real-time
journalctl -u postfix -fpflogsumm (Log Summary)
# Install pflogsumm
apt install -y pflogsumm
# Daily summary
pflogsumm /var/log/mail.log
# Summary for a specific date
pflogsumm /var/log/mail.log.1
# Send daily report via email
pflogsumm -d yesterday /var/log/mail.log | mail -s "Postfix Stats" [email protected]
# Generate report with problems only
pflogsumm -p /var/log/mail.log
# Show per-domain traffic
pflogsumm --verbose --detail=1 /var/log/mail.log
# Show rejections summary
pflogsumm --reject-detail /var/log/mail.logGrep Patterns for Troubleshooting
# Find connection timeouts
grep "timeout" /var/log/mail.log
# Find authentication failures
grep "SASL authentication failed" /var/log/mail.log
# Find TLS errors
grep -i "tls" /var/log/mail.log | grep -i "error\|fail\|timeout"
# Find rate-limiting events
grep "too many connections\|rate limit" /var/log/mail.log
# Find greylisted messages
grep "greylist" /var/log/mail.log
# Find messages flagged as spam
grep "spam" /var/log/mail.log
# Extract all sender domains from deferrals
grep "status=deferred" /var/log/mail.log | grep -oP 'from=<\K[^>]+' | sort -u
# Find deferred messages over 1 hour old
grep "status=deferred" /var/log/mail.log | awk -F' ' '{if($2 < (strftime("%H")-1)) print}'DKIM / SPF / DMARC
DKIM Setup (OpenDKIM)
# Install OpenDKIM
apt install -y opendkim opendkim-tools
# Generate DKIM key pair
mkdir -p /etc/opendkim/keys/example.com
cd /etc/opendkim/keys/example.com
# Generate 2048-bit key (use 1024 for DNS record size limits)
opendkim-genkey -D /etc/opendkim/keys/example.com/ -d example.com -s 202401
# Set ownership
chown -R opendkim:opendkim /etc/opendkim
# Rename key files
mv 202401.private default.private
mv 202401.txt default.txt
# Configure /etc/opendkim.conf
cat >> /etc/opendkim.conf << 'CONF'
Domain example.com
KeyFile /etc/opendkim/keys/example.com/default.private
Selector 202401
Socket inet:8891@localhost
Canonicalization relaxed/simple
Mode sv
SubDomains no
AutoRestart yes
AutoRestartRate 10/1h
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
CONF
# Configure /etc/default/opendkim
# SOCKET="inet:8891@localhost"
# Configure Postfix for DKIM
postconf -e "milter_default_action = accept"
postconf -e "milter_protocol = 6"
postconf -e "smtpd_milters = inet:localhost:8891"
postconf -e "non_smtpd_milters = inet:localhost:8891"
# Restart services
systemctl restart opendkim postfixDKIM DNS Record
# Display the DKIM DNS record to add
cat /etc/opendkim/keys/example.com/default.txt
# Output: 202401._domainkey.example.com IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIGfMA0G..."
# Extract clean DNS value (remove quotes and whitespace)
cat /etc/opendkim/keys/example.com/default.txt \
| tr -d '"' \
| awk '{print $NF}'
# Test DKIM
opendkim-testkey -d example.com -s 202401 -vvv
# Send test email and check headers
# Look for: DKIM-Signature header and Authentication-Results headerSPF Record
# SPF TXT record for example.com
# v=spf1 mx ip4:192.168.1.10 include:_spf.google.com ~all
# Allow only specified mail servers
v=spf1 mx -all
# Allow current server IP + Google Workspace
v=spf1 mx ip4:203.0.113.10 include:_spf.google.com -all
# Softfail (still allows delivery, marks as suspicious)
v=spf1 mx ~all
# Hard fail (reject unauthorized senders)
v=spf1 mx -all
# Include third-party senders
v=spf1 include:spf.mailgun.org include:sendgrid.net -all
# Test SPF
dig TXT example.com +short
# or
nslookup -type=TXT example.comDMARC Record
# DMARC TXT record for _dmarc.example.com
# Policy options: none (p=none), quarantine (p=quarantine), reject (p=reject)
# Monitoring only (no action)
_dmarc.example.com IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]"
# Quarantine suspicious mail
_dmarc.example.com IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]; ruf=mailto:[email protected]; pct=100"
# Reject policy (strict)
_dmarc.example.com IN TXT "v=DMARC1; p=reject; sp=reject; adkim=s; aspf=s; rua=mailto:[email protected]; fo=1"
# Subdomain policy (sp=): none, quarantine, reject
# DKIM alignment (adkim): r=relaxed, s=strict
# SPF alignment (aspf): r=relaxed, s=strict
# Test DMARC
dig TXT _dmarc.example.com +shortPostfix Configuration
main.cf Basics
# Core settings
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
# Relay settings
relayhost = [smtp.example.com]:587 # Smart host relay
mynetworks = 127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16 # Trusted networks
# Message size limits
message_size_limit = 25600000 # 25 MB
mailbox_size_limit = 512000000 # 512 MB
# Recipient limits
smtpd_recipient_limit = 100
queue_minfree = 20G
# Rate limiting
smtpd_client_connection_count_limit = 10
smtpd_client_connection_rate_limit = 30
smtpd_client_message_rate_limit = 30
smtpd_client_recipient_rate_limit = 30
# SMTP banners (security)
smtpd_banner = $myhostname ESMTP $mail_name
# Or disable version info:
smtpd_banner = $myhostname ESMTPTLS & SMTP Security
# Force TLS for incoming connections
smtpd_tls_security_level = may # Opportunistic TLS (accept both)
smtpd_tls_security_level = encrypt # Force TLS (reject plain)
# TLS certificate
smtpd_tls_cert_file = /etc/ssl/certs/mail.example.com.pem
smtpd_tls_key_file = /etc/ssl/private/mail.example.com.key
# TLS protocols
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
# Outbound TLS
smtp_tls_security_level = may
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
# Session cache
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
# DH parameters (generate: openssl dhparam -out /etc/ssl/dhparam.pem 2048)
smtpd_tls_dh1024_param_file = /etc/ssl/dhparam.pem
# Enforce TLS for specific destinations
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# /etc/postfix/tls_policy:
# example.com encrypt
# .example.com encryptBlacklist & Whitelist
# postscreen (built-in pre-connect filter)
postconf -e "postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr"
postconf -e "postscreen_dnsbl_sites = zen.spamhaus.org, bl.spamcop.net, b.barracudacentral.org"
postconf -e "postscreen_dnsbl_threshold = 3"
postconf -e "postscreen_greet_action = enforce"
postconf -e "postscreen_bare_newline_action = enforce"
# Access maps (post-screen lookup)
postconf -e "smtpd_client_restrictions = check_client_access cidr:/etc/postfix/client_access"
# /etc/postfix/client_access
# 192.168.1.0/24 OK
# 10.0.0.0/8 OK
# 203.0.113.0/24 REJECT
# 185.0.0.0/8 REJECT Spam source
# Sender access
postconf -e "smtpd_sender_restrictions = check_sender_access hash:/etc/postfix/sender_access"
# /etc/postfix/sender_access
# [email protected] REJECT
# *@known-spam.com REJECT
# Recipient access
postconf -e "smtpd_recipient_restrictions = check_recipient_access hash:/etc/postfix/recipient_access"
# RHSBL (right-hand side blacklist)
postconf -e "smtpd_recipient_restrictions = reject_rhsbl_sender dbl.spamhaus.org"
# Rebuild hash maps
postmap /etc/postfix/client_access
postmap /etc/postfix/sender_access
postmap /etc/postfix/recipient_access
# Reload Postfix
systemctl reload postfixRate Limiting
# Connection limits per client
smtpd_client_connection_count_limit = 10
smtpd_client_connection_rate_limit = 30
# Recipient limits
smtpd_recipient_limit = 100
# Anvil (connection rate statistics)
postconf -e "anvil_rate_time_unit = 60s"
postconf -e "anvil_status_update_time = 3600s"
# Connection time limits
smtpd_timeout = 300
smtp_helo_timeout = 300
smtpd_data_restrictions = reject_unauth_pipelining
# Show rate limit stats
postfix anvil