PowerMTA's configuration file controls every aspect of high-volume email delivery: how many concurrent connections each IP makes to each ISP, which IP addresses different message streams use, how DKIM signing is applied, how bounces are classified and acted upon, and how the system behaves when ISPs throttle or block traffic. A misconfigured PowerMTA can bottleneck throughput, damage IP reputation through over-aggressive connection behaviour, or fail to process bounces — making it impossible to maintain list hygiene at scale. This guide covers the core configuration structure, per-ISP delivery tuning, DKIM integration, bounce management, and the monitoring setup required to operate PowerMTA in production.
PowerMTA Delivery Performance — ISP Throughput with Tuned vMTA Config
Configuration File Structure
PowerMTA's primary configuration file is located at /etc/pmta/config (path may vary by installation). Unlike Postfix's separate main.cf and master.cf files, PowerMTA uses a single hierarchical configuration with nested block structures:
# /etc/pmta/config — basic structure
# Global settings
host-name mail.yourdomain.com
smtp-listener 0/0:25
# License
license /etc/pmta/license
# Logging paths
log-file /var/log/pmta/pmta.log
log-rotate-size 200M
# Virtual MTA definitions
<virtual-mta vmta-main>
smtp-source-ip 203.0.113.10
ehlo-hostname mail.yourdomain.com
</virtual-mta>
# Per-ISP delivery policies (domain blocks)
<domain gmail.com>
max-smtp-out 10
max-msg-per-connection 100
</domain>
# Accounting (bounce and delivery logging)
<acct-file /var/log/pmta/acct.csv>
records d
record-fields d timeLogged,orig,rcpt,vmta,jobId,dlvStatus,dsnStatus,dsnDiag
</acct-file>
Server Identity and Basic Settings
# /etc/pmta/config — global settings section
# Hostname used in EHLO and logging
host-name mail.yourdomain.com
# SMTP listener — 0/0:25 = all interfaces, port 25
# For injection-only (relay): listen on localhost only
smtp-listener 127.0.0.1:25
# For receiving messages from external campaign systems
smtp-listener 0/0:25
# Injection port (where your email platform injects messages)
# Use a non-standard port to separate injection from MTA-to-MTA
smtp-listener 0/0:587
smtp-smarthost-port 587
# Maximum queue size
max-queue-size 500M
# Worker threads
smtp-server-threads 30
smtp-client-threads 200
# Postmaster address (receives FBL reports and admin messages)
postmaster postmaster@yourdomain.com
# Log settings
log-file /var/log/pmta/pmta.log
log-rotate-size 200M
log-rotate-count 10
Virtual MTA: Stream Isolation
Virtual MTAs (vMTAs) are the core stream isolation mechanism in PowerMTA. Each vMTA has its own IP address, its own delivery queues, and its own per-ISP connection behaviour. Messages injected with a specific X-Binding or X-VirtualMTA header route to the named vMTA.
<virtual-mta name="client-acme">
<smtp-source-host>203.0.113.10</smtp-source-host>
<domain-key name="acme" domain="acme.com" path="/etc/pmta/keys/acme.pem"/>
<max-smtp-out>10</max-smtp-out>
<max-msg-rate>200/h</max-msg-rate>
</virtual-mta>
<domain name="gmail.com">
<max-smtp-out>10</max-smtp-out>
<smtp-pattern-list name="gmail-deferrals">
<smtp-pattern response="421*" action="defer" period="60s"/>
</smtp-pattern-list>
</domain>
# Stream isolation: transactional vs marketing on separate IPs
<virtual-mta vmta-transactional>
smtp-source-ip 203.0.113.10
ehlo-hostname tx.yourdomain.com
# Maximum simultaneous outbound connections from this vMTA
max-smtp-out 100
# Per-connection message limit
smtp-retries-after-shutoff 5
</virtual-mta>
<virtual-mta vmta-marketing>
smtp-source-ip 203.0.113.11
smtp-source-ip 203.0.113.12 # multiple IPs rotate across connections
ehlo-hostname mkt.yourdomain.com
max-smtp-out 80
smtp-retries-after-shutoff 3
</virtual-mta>
<virtual-mta vmta-bulk>
smtp-source-ip 203.0.113.20
smtp-source-ip 203.0.113.21
smtp-source-ip 203.0.113.22
ehlo-hostname bulk.yourdomain.com
max-smtp-out 150
</virtual-mta>
# vMTA pools allow automatic load distribution
<virtual-mta-pool pool-marketing>
virtual-mta vmta-marketing
virtual-mta vmta-bulk
</virtual-mta-pool>
Your injection application (MailWizz, custom code, or any SMTP client) targets a specific vMTA by setting the X-Binding: vmta-name SMTP header when injecting messages.
Per-ISP Domain Blocks: Delivery Tuning
Domain blocks in PowerMTA configure the delivery behaviour for specific receiving domains or MX patterns. This is where per-ISP throttling is implemented — the most impactful configuration for inbox placement at scale.
# Gmail — engagement-sensitive, allow reasonable concurrency
<domain gmail.com>
max-smtp-out 10 # max concurrent connections to Gmail MXs
max-msg-per-connection 100 # messages per SMTP session
retry-after 421 4.7.0 15m # Gmail "unsolicited" throttle — wait 15min
retry-after 421 4.3.0 5m # Gmail infrastructure throttle — retry after 5min
max-msg-rate 500/m # max messages per minute to Gmail total
</domain>
# Microsoft — conservative; aggressive sends trigger 421 4.7.650
<domain outlook.com hotmail.com live.com msn.com>
max-smtp-out 5
max-msg-per-connection 50
retry-after 421 4.7.650 30m # Microsoft reputation throttle
retry-after 421 4.7.0 20m
max-msg-rate 200/m
</domain>
# Yahoo / AOL — watch for TS codes
<domain yahoo.com ymail.com aol.com>
max-smtp-out 8
max-msg-per-connection 50
retry-after 421 TS01 60m # TS01 = complaint rate issue — wait an hour
retry-after 421 TS03 15m # TS03 = connection rate — 15min then retry
</domain>
# Apple iCloud
<domain icloud.com me.com mac.com>
max-smtp-out 10
max-msg-per-connection 100
</domain>
# Conservative policy for ISPs not specifically configured
<domain *>
max-smtp-out 20
max-msg-per-connection 200
max-msg-rate 1000/m
</domain>
DKIM Signing Configuration
PowerMTA supports DKIM signing natively for domains configured with private keys. The configuration maps each sending domain to its DKIM private key and selector:
# DKIM signing in /etc/pmta/config
# Method 1: Direct private key reference (simple setup)
<dkim>
domain yourdomain.com
selector mail
private-key-file /etc/pmta/dkim/yourdomain.com.private.key
header-list from:to:subject:date:message-id:content-type
canonicalization relaxed/simple
sign-hash sha256
</dkim>
# Method 2: Multiple domains with domain-key blocks
<domain-key mail._domainkey.yourdomain.com>
type DK
private-key /etc/pmta/dkim/yourdomain.com.private.key
domain yourdomain.com
selector mail
</domain-key>
<domain-key mail._domainkey.anotherdomain.org>
type DK
private-key /etc/pmta/dkim/anotherdomain.org.private.key
domain anotherdomain.org
selector mail
</domain-key>
Generate 2048-bit DKIM keys for PowerMTA:
# Generate key pair
openssl genrsa -out /etc/pmta/dkim/yourdomain.com.private.key 2048
openssl rsa -in /etc/pmta/dkim/yourdomain.com.private.key \
-pubout -out /etc/pmta/dkim/yourdomain.com.public.key
# Set permissions — private key must be readable by pmta user only
chown pmta:pmta /etc/pmta/dkim/yourdomain.com.private.key
chmod 600 /etc/pmta/dkim/yourdomain.com.private.key
# Get the DNS record value
openssl rsa -in /etc/pmta/dkim/yourdomain.com.private.key \
-pubout 2>/dev/null | grep -v -- '---' | tr -d '\n'
# Publish this value in: mail._domainkey.yourdomain.com TXT "v=DKIM1; k=rsa; p=..."
Bounce Classification and Accounting
PowerMTA's accounting system writes delivery events (bounces, successful deliveries, FBL complaints) to CSV files for processing by downstream list management systems. The accounting configuration determines what data is captured and how often files are rotated:
# Accounting file configuration
# Bounce log — records every bounce event
<acct-file /var/log/pmta/bounce.csv>
move-interval 1h
move-to /var/log/pmta/accounting/
world-readable yes
records b
record-fields b timeLogged,bounceCat,vmta,orig,rcpt,srcMta,dlvSourceIp,jobId,dsnStatus,dsnMta,dsnDiag
</acct-file>
# Full delivery accounting
<acct-file /var/log/pmta/acct.csv>
move-interval 24h
move-to /var/log/pmta/accounting/
world-readable yes
records d
record-fields d timeLogged,orig,rcpt,vmta,jobId,dlvStatus,dsnStatus
</acct-file>
# FBL (complaint) log
<acct-file /var/log/pmta/fbl.csv>
move-interval 24h
move-to /var/log/pmta/accounting/fbl/
world-readable yes
records feedback-loop
record-fields f timeLogged,format,header_To,header_Return-Path,reportedDomain,header_X-FBLId
</acct-file>
Automatic bounce suppression rules
# Automatic actions based on bounce category
<bounce-action>
type permanent
match bad-mailbox bad-domain routing-errors inactive-mailbox
action suppress
</bounce-action>
<bounce-action>
type transient
match quota-issues bad-connection
action retry
retry-after 4h
</bounce-action>
<bounce-action>
type transient
match spam-related
action retry
retry-after 6h
max-tries 3
</bounce-action>
Access Control and Security
# Restrict SMTP injection to trusted sources only
# Messages can only be injected from these IPs
<smtp-server>
allow-unencrypted-plain yes # Allow password authentication without TLS for localhost
max-smtp-in 50 # Maximum incoming injection connections
</smtp-server>
# Source IP allowlist — only these IPs can inject mail
<source 127.0.0.1/8>
relay yes
</source>
<source 10.0.0.0/8>
relay yes
</source>
# All other sources — no relay
<source *>
relay no
</source>
Monitoring and Management
Web monitoring interface
# Enable web management interface
<http>
port 8080
address 127.0.0.1 # Restrict to localhost; use SSH tunnel for remote access
enable-config-editing yes
</http>
Essential CLI monitoring commands
# Overall system status
pmta status
# Queue depth per virtual MTA
pmta show status detail
# Per-domain delivery statistics
pmta show domain gmail.com
# Active queue depth
pmta show queue
# Inspect bounce log (last 100 lines)
tail -100 /var/log/pmta/bounce.csv | cut -d',' -f1,2,4,5,10
# Reload configuration after changes (no restart required)
pmta reload
# Flush deferred messages to a specific domain (use carefully)
pmta resume domain gmail.com
# Check suppression list
pmta show suppressed address@example.com
Hardware and Capacity Planning
PowerMTA's throughput ceiling is determined by hardware, not software configuration. Key sizing guidelines:
| Daily volume target | CPU | RAM | Storage | IPs |
|---|---|---|---|---|
| Up to 500K/day | 4 cores | 8GB | SSD 100GB | 1–3 |
| 500K–2M/day | 8 cores | 16GB | NVMe 200GB | 3–10 |
| 2M–10M/day | 16 cores | 32GB | NVMe RAID 500GB | 10–30 |
| 10M+/day | Multi-server cluster | 64GB+ | NVMe RAID per node | 30+ |
The most common bottleneck at high volume is disk I/O — PowerMTA queues are disk-based. NVMe storage is effectively mandatory above 1M/day. The second common bottleneck is DNS resolution — run a local caching resolver (Unbound or Bind) so MX lookups don't serialise delivery at repeated popular destination domains.

