What tools can I use to simulate email traffic and stress test a Postfix cluster?

Updated on 15 Oct 2026: We corrected the SMTP test commands and added checks for cluster failover and recovery of queued mail.
The practical shortlist starts with Postfix smtp-source for generating SMTP traffic and Postfix smtp-sink for accepting and discarding that traffic. Add the older Postal benchmark package only when it is already packaged for the lab, use swaks for precise functional SMTP checks, and use a temporary blackhole Postfix receiver for a closer rehearsal of real routing.
For a target such as 50,000 messages per minute, do not send that volume to real customer inboxes or a normal mailbox platform. Split the test into two parts: first, a synthetic capacity test that proves the cluster can accept, queue, and hand off mail at the target rate; second, a controlled delivery test that includes DNS, TLS, content filtering, recipient variance, retry behavior, and logging overhead.
- SMTP traffic generator: Use smtp-source when you want raw SMTP injection without application code.
- Discard receiver: Use smtp-sink when the receiving side should accept mail and throw it away.
- Migration rehearsal: Route test domains into a temporary receiver and measure the entire Postfix path.
Best tools for Postfix stress testing
If the goal is to prove that a new Postfix cluster can accept a high rate, start with Postfix's SMTP test programs. Distribution packages do not always install them or put them on PATH. smtp-source can generate sessions and messages; smtp-sink can receive them without creating mailbox storage pressure. The smtp-source manual explicitly labels it unsupported and gives no compatibility guarantee between versions. Verify both installed man pages and executable paths before scripting the tests.
|
|
|
|---|---|---|
smtp-source | SMTP injection | Unsupported synthetic tool |
smtp-sink | Discard receiving | No mailbox path |
Postal | Older benchmark package | Compatibility varies |
swaks | STARTTLS and SMTP AUTH checks | Not a bulk tool |
Blackhole Postfix | Real routing | Needs isolation |
Use this as the practical shortlist before deciding how realistic the test must be.
A useful Server Fault example uses the same basic idea: generate SMTP traffic and point it at a sink instead of the public internet. That pattern keeps the stress test under your control.
A test through the Postfix cluster into a sink measures acceptance rate, queue behavior, and local resource limits. A direct generator-to-sink test bypasses Postfix. A basic sink omits remote MX policies, DNS latency, and TLS; content scanning is measured only when configured filters remain in the test path. Postfix smtp-source has no SMTP command pipelining, STARTTLS, or SMTP AUTH support, so this example measures plaintext SMTP capacity.
- Capacity truth: The cluster can accept and process synthetic load at a known rate.
- Delivery gap: A sink does not tell you how remote mail systems will react.
A safe pattern for high-volume tests
For a cluster migration, use a staged test that isolates risk. Build one or more generator hosts, point the new Postfix cluster at a private receiver, and measure every step. The generator should not run on the same host as the Postfix nodes being measured, or generator limits will be confused with MTA limits. Replace the documentation addresses 192.0.2.10 and 192.0.2.20 with the lab cluster and receiver addresses. Restrict receiver access to the lab and block SMTP egress to public destinations.

Postfix cluster load test flow with generator hosts, a private SMTP receiver, and performance metrics.
Run a discard receiverbash
# Run as an unprivileged user on the receiver host. smtp-sink -c -m 1000 192.0.2.20:2525 1000 # Add sink hosts only if receiver capacity limits the test.
That receiver accepts SMTP and discards the message body. The -m 1000 option sets its simultaneous-connection limit; the final 1000 is the pending-connection backlog, subject to operating system limits. Check open-file limits on the generators and receivers. A target of 50,000 messages per minute is about 833 messages per second. Scale the generators and receivers separately only when their measured capacity limits the test.
Configure routing before generating traffic. This example assumes a dedicated lab instance and hash map support in postconf -m; otherwise use an installed indexed map type consistently. Preserve existing transport_maps entries when adapting the configuration. The bracketed IP bypasses MX lookups, so use private DNS for a separate DNS test. Allow relay access only for generator IPs and verify one message reaches the sink before increasing load.
Test domain entries in /etc/postfix/transporttext
example.test smtp:[192.0.2.20]:2525 .example.test smtp:[192.0.2.20]:2525
Build and verify the lab transport mapbash
postmap hash:/etc/postfix/transport postmap -q example.test hash:/etc/postfix/transport postconf -e 'transport_maps = hash:/etc/postfix/transport' postfix check postfix reload
Generate SMTP loadbash
smtp-source -s 500 -l 2048 -m 100000 -c \ -f sender@example.test \ -t recipient@example.test \ 192.0.2.10:25
This command attempts 100,000 messages with 2 KiB bodies, excluding headers, using up to 500 parallel sessions. Because -d is absent, smtp-source reconnects after each message. That tests connection churn, but the command does not enforce a fixed rate of 50,000 messages per minute. Add -d to reuse connections, and use -w or an external rate controller to pace each sending thread. Record any smtpd process or per-client connection limits reached during the run before changing the configuration.
Start below the target rate, then increase in steps. Do not jump straight to the maximum number, because you need to know where queue depth begins to grow, when latency changes, and whether the system recovers cleanly after the test ends.
Shape a realistic SMTP workload
A single fixed payload at maximum concurrency benchmarks only one path. Build a workload matrix that changes connection behavior, message size, recipient distribution, and response timing. Keep each run reproducible so a throughput change can be traced to one workload variable.
- Connection behavior: Run without -d for connection churn, then add it to measure persistent SMTP sessions.
- Pacing: Use -w for a fixed per-thread delay or -R for a random delay, then verify the achieved rate in Postfix logs.
- Message bodies: Use -l for controlled payload sizes and -F for representative headers and MIME content.
- Recipient distribution: Use -N to generate numbered recipients when the private receiver accepts them. Use separate private next-hop destinations to test per-destination concurrency; several domains routed to one sink can share the same delivery bottleneck.
Change one workload dimension at a time before combining them. Use swaks for targeted STARTTLS and SMTP AUTH checks. Measure encrypted throughput with a TLS-capable submitting client and a temporary Postfix receiver, keeping production TLS and relay restrictions intact.
Choose the right test style
The main decision is whether you want a synthetic acceptance test or an end-to-end rehearsal. Both are useful, but they answer different questions. Run both before moving customers to a new cluster.
Synthetic SMTP capacity test
- Purpose: Find raw acceptance capacity and queue behavior.
- Tools: Postfix smtp-source, smtp-sink, and shell orchestration.
- Risk: It can overstate live performance because remote delivery is absent.
End-to-end rehearsal
- Purpose: Check routing, DNS, TLS, retries, logging, and monitoring.
- Tools: Temporary Postfix receiver, private MX records, and real logs.
- Risk: Poor isolation can overload the receiving side or pollute metrics.
For the Postfix side, keep the official Postfix tuning guide close while you test. It helps you focus on concurrency, process limits, queue behavior, and filesystem pressure instead of guessing. If the cluster is on Red Hat Enterprise Linux, the Red Hat Postfix guide is also worth checking before you lock in package and service assumptions.

Grafana view of Postfix load test throughput, queue depth, SMTP errors, and server resource usage.
Do not confuse load testing with delivery testing
A Postfix stress test answers whether the cluster can handle traffic. It does not answer whether your messages will authenticate correctly, avoid a blocklist or blacklist problem, or reach the inbox. Those are separate checks, and they should happen before the customer migration window.
Suped's DMARC reporting and email authentication platform supports the migration by showing which sending sources pass SPF and DKIM checks and whether the authenticated domains match the visible From domain for DMARC. Review those results after shifting a small amount of production traffic to the new cluster. Aggregate reports are delayed, so use message-header checks for immediate feedback.
Before the first production traffic shift, send a real message through the new path and inspect it with the email tester. Also run the domain health checker and enable DMARC monitoring so authentication failures are visible during the migration. If the cluster uses new IPs, add blocklist monitoring as a separate guardrail.
Email tester
Send a real email to this address. Suped shows a results button when the test is ready.
?/43tests passed
Treat load generation and authentication monitoring as different workstreams. A cluster can survive 50,000 messages per minute and still fail DKIM signing, use an SPF-authenticated domain that does not match the visible From domain for DMARC, or send through an IP with a blocklist (blacklist) issue.
- Use load tools for: Acceptance rate, queue pressure, retry behavior, and resource limits.
- Use Suped for: DMARC report review, authentication failure investigation, and blocklist (blacklist) alerts during the migration.
Suped DMARC dashboard showing email volume, authentication health, and source breakdown
Metrics to collect during the test
The test only matters if you collect enough data to make a migration decision. Record accepted and downstream-delivered messages per second, queue depth, queue age, deferred messages, bounce generation, SMTP error classes, TLS negotiation time, DNS lookup time, CPU, memory, disk I/O, network throughput, and log write rate for each Postfix node. Count successful final DATA acknowledgments separately from connection attempts, and keep message counts separate from recipient-delivery counts.
If it is installed, run qshape on every node during each rate step. Growth in the incoming queue points to message input outrunning the queue manager, while an aging active or deferred queue points to slow delivery, destination latency, or insufficient concurrency. Per-node results also expose uneven traffic distribution behind a load balancer. Alongside qshape's age distribution, collect queue length, total bytes, and oldest-message age; include the hold and maildrop queues when relevant. Run queue inspections at fixed intervals because frequent full scans add disk I/O.
Inspect queue age on each Postfix nodebash
qshape incoming qshape active qshape deferred
Track p95 and p99 delivery latency alongside the Postfix delays=a/b/c/d log fields: a is time before the last active-queue entry, b is time there before connection setup, c is connection setup including DNS and TLS where used, and d is transmission. A status=sent log entry confirms acceptance by the next hop, not inbox placement.
Load test stop signals
Use stop signals that are tied to operational impact, not only CPU percentage.
Healthy
Green
Queue drains after each step and deferred mail stays near baseline.
Investigate
Yellow
Queue grows during a step but drains quickly after load stops.
Stop
Red
Queue age keeps rising, errors increase, or retries do not recover.
Queue depth alone can mislead you. A queue that spikes and drains is normal during a rate step. A queue that keeps aging after the generator stops is the signal that delivery, disk, DNS, or concurrency settings need attention.
- Rate metric: Accepted messages per second shows what the cluster can ingest.
- Drain metric: Queue age shows whether the system clears work after the burst.
- Error metric: SMTP 4xx replies are temporary failures and 5xx replies are permanent failures; inspect reply text and logs to locate the cause.
- Resource metric: Disk write rate and fsync behavior often become limits before CPU does.
Test cluster failover and queue recovery
High availability needs a separate failure test at the planned peak. A load balancer redirects new connections, but it does not transfer mail already accepted into a failed node's local queue.
- Take one node offline during a sustained run. For a 50,000-message-per-minute target, the remaining nodes must sustain about 833 messages per second within the agreed latency and error limits.
- Measure how quickly health checks remove the failed node, and verify that the submitting application retries interrupted sessions. smtp-source alone does not reproduce application retry behavior.
- Restore the failed node and confirm its queued mail drains. With independent local queues, accepted mail waits for that node or its queue storage to become available again.
- Use unique identifiers in a small captured sample to check for missing or duplicate messages after recovery. Keep receiver capture overhead separate from the discard-only throughput benchmark.
Keep queue directories separate for concurrently running Postfix instances. If the design uses shared-storage failover, test fencing so only one instance owns that queue at a time. New-connection failover and recovery of accepted mail are separate acceptance criteria.
A staged Postfix load test runbook
A staged runbook keeps the test useful and reversible. Avoid a single uncontrolled burst that proves something broke but leaves no clean record of which setting or component failed first.
- Baseline first: Run a low-rate smtp-source test and confirm logs, metrics, and queue tools agree.
- Raise rates: Increase traffic in fixed steps until you pass expected peak volume, then hold the target long enough to expose sustained queue growth and recovery limits.
- Add realism: Introduce TLS, DNS lookups, content filters, and mixed message sizes.
- Test failure: Follow the cluster failover checks above, including recovery of mail already accepted by the failed node.
- Record proof: Save test windows, configuration diffs, rate steps, errors, and queue recovery time.
For a reusable receiver design, dedicate a blackhole testing domain that cannot route to the public internet. If the migration is about bursts rather than steady state, test volume spikes specifically. If you see connection failures after tuning or upgrading, handle too many connections as its own Postfix tuning problem instead of treating it as a generator problem.
The useful result is a planned peak that stays within the latency limit, drains its queue after the generator stops, redistributes traffic after a node loss, and leaves clean logs that explain what happened.
Views from the trenches
Best practices
Run the generator and sink on separate hosts so CPU limits do not hide Postfix bottlenecks.
Use staged rates and fixed message sizes before adding TLS, filters, or DNS latency.
Keep test routing private, then compare queue drain time against live migration targets.
Common pitfalls
Testing against a regular mailbox server shifts the outage risk to the receiving side.
A single local sink can make the cluster look faster than real DNS and TLS delivery.
Raising concurrency without watching disk I/O gives a misleading capacity number.
Expert tips
Record accepted rate, deferred rate, and queue depth together, not as separate wins.
Warm resolver caches once, then run a cold-cache pass to expose DNS latency costs.
Use a temporary receiver that discards most mail and samples enough for review later.
Marketer view
Marketer from Email Geeks says smtp-sink is useful for accepting and discarding large test flows, but it does not model delivery or DNS latency.
2021-12-29 - Email Geeks
Marketer view
Marketer from Email Geeks says sending the test into a regular mailbox server is possible only when the inbound owner approves the risk and capacity.
2021-12-29 - Email Geeks
Recommended Postfix test stack
Use smtp-source and smtp-sink for the baseline, swaks for targeted protocol checks, and a temporary Postfix receiver for the migration rehearsal. Keep the same rate steps and workload when comparing configurations so throughput and queue recovery results are comparable.
After load testing, check a controlled production sample with Suped's email tester and review DMARC reports for the new sending path. Investigate authentication failures before increasing the production share, and monitor new sending IPs for blocklist (blacklist) entries.
Frequently asked questions
It can generate that throughput when the generator hosts, network, and Postfix target sustain it, but message count and session concurrency do not guarantee a fixed rate. Start with measured generator capacity, add hosts when needed, pace the senders, and compare accepted and downstream-delivered rates in Postfix logs.
Only if the mailbox owner approves the test and the receiving side has capacity. A temporary receiver or smtp-sink is safer because it removes mailbox storage and user-facing risk.
The older Postal benchmark package can be useful where it installs cleanly in a controlled lab. Do not spend time forcing incompatible components to build when smtp-source and a private receiver already answer the core capacity question.
The biggest mistake is treating a sink test as proof of inbox delivery or complete remote-server behavior. A test routed through Postfix measures acceptance and queue behavior, but the basic sink does not reproduce remote MX policies, DNS latency, or TLS. Filters are measured only if they remain in the test path.
Suped's DMARC reporting and email authentication platform helps check the new sending path after a controlled traffic shift. Review authentication failures in DMARC reports and investigate blocklist (blacklist) alerts before increasing production traffic.

