Generate Controlled QMQP Test Traffic with qmqp-source

qmqp-source is Postfix's QMQP traffic generator, built to fire controlled test messages at a listener you choose. You will finish with a repeatable way to control the message and recipient counts, and add either fixed or random pacing. The examples use qmqp-source from Postfix 3.8.6-1ubuntu0.1, installed here. Allow about 15 minutes if you already have a QMQP test listener and a disposable destination.

Warning: this is a traffic generator, not a mail-delivery helper. It sends QMQP transactions to the endpoint you name. Use a listener that you operate, test addresses that cannot reach real recipients, and a low message count first. Do not point it at a production mail service until you have confirmed the route and limits. The program is an unsupported Postfix test utility, and the manual does not promise compatibility between successive versions.

1. Check the installed command

Confirm which executable will run and record the package version:

$ command -v qmqp-source
/usr/sbin/qmqp-source
$ dpkg-query -W -f='${Package} ${Version}\n' postfix
postfix 3.8.6-1ubuntu0.1

The command has no useful help option in this installation. With no arguments it prints a usage line, which is a safe way to check that the executable is available:

$ qmqp-source
qmqp-source: fatal: usage: qmqp-source -cv -s sess -l msglen -m msgs -C count -M myhostname -f from -t to -R delay -w delay host[:port]

Checkpoint: if command -v returns nothing, stop here and use your normal package-management process. You do not need root privileges merely to inspect the command or run a test against a listener you can access.

2. Choose an isolated QMQP endpoint

The final argument identifies the server. For an Internet socket, use host or host:port; the documented default port is 628. The optional inet: prefix is also accepted. A UNIX-domain listener uses unix:/path/to/socket.

Write down the endpoint before running a load test. A hostname can resolve somewhere unexpected, and port 628 is not a guarantee that the service is a disposable test target. If you need to test a local listener, prefer an explicit loopback address or a known UNIX socket:

$ test -S /run/example-qmqp.sock && echo 'socket exists'
socket exists

The check above only inspects the socket. It does not create, remove or alter it. The service owner may need elevated privileges to create or configure a listener, but that is separate from running qmqp-source.

3. Send one small test message

Start with one message, one session and one recipient. Set both addresses explicitly so the machine hostname cannot decide where the generated message goes:

$ qmqp-source -c -m 1 -s 1 \
    -f [email protected] \
    -t [email protected] \
    127.0.0.1:628
1

The -m option sets the number of messages, while -s sets the number of QMQP sessions run in parallel. The -c option displays a running counter, incremented when a delivery completes. A successful run may therefore finish with the count displayed as 1, although the exact diagnostic output can vary with the test listener and Postfix build.

The example.invalid addresses are deliberately non-routable names reserved for examples. Replace them only with addresses accepted by your isolated test setup. The default sender and recipient are based on foo@myhostname; do not rely on that default for a controlled test.

4. Confirm connection failures before increasing the load

If the listener is absent, the command fails instead of silently completing the transaction. For example, this deliberately targets an unused local port:

$ qmqp-source -c -m 1 -s 1 127.0.0.1:1
qmqp-source: fatal: connect: Connection refused
$ printf '%s\n' "$?"
1

That result confirms a refused connection, not a successful QMQP test. Check the listener and its firewall policy without changing them:

$ ss -ltn | grep ':628 '
$ getent hosts test-qmqp.example.test

Do not treat a timeout, name-resolution error or protocol rejection as evidence that the service accepted a message. Capture the error, verify the endpoint, and rerun the single-message test. If the endpoint is a UNIX socket, check it with test -S and use its absolute path.

5. Set message size and recipient count

Use -l to choose the message payload length in bytes. The length includes the message headers, so it is not a pure body-size setting. Use a modest value while checking the listener:

$ qmqp-source -c -l 2048 -m 1 -s 1 \
    -f [email protected] \
    -t [email protected] \
    127.0.0.1:628
1

Use -r to send several generated recipients in each transaction:

$ qmqp-source -c -l 2048 -m 2 -r 3 -s 1 \
    -f [email protected] \
    -t [email protected] \
    127.0.0.1:628
2

Recipient names are generated by prepending a number to the recipient address. Keep this behaviour in mind when matching arrivals in the test system. If you need a different hostname in the command's default sender or recipient, -M myhostname supplies it, but explicit -f and -t values are easier to audit.

6. Add parallelism without losing control

Increase -s only after the one-session test works. For example, this sends four messages using two parallel QMQP sessions:

$ qmqp-source -c -m 4 -s 2 \
    -f [email protected] \
    -t [email protected] \
    127.0.0.1:628
1
2
3
4

The counter reports completed deliveries, so it is useful for watching progress but not for proving that a particular session is still connected. Parallel work can make a listener, network or log collector reach its limits quickly. Keep a small count, observe the service, then increase one variable at a time.

If a full queue causes the server to send TCP RESET instead of SYN|ACK, -C count tells the program how many times to retry before giving up. The default is one attempt. This is a narrow workaround for a listen-queue problem, not a general remedy for an unhealthy service:

$ qmqp-source -c -C 3 -m 2 -s 1 \
    -f [email protected] -t [email protected] 127.0.0.1:628

7. Control the gap between messages

Use -w interval for a fixed wait between messages. Use -R interval for a random wait from zero through the supplied interval. The waits apply between messages, and suspending one thread does not affect other delivery threads.

$ qmqp-source -c -m 5 -s 1 -w 2 \
    -f [email protected] -t [email protected] 127.0.0.1:628

Use a delay to make logs readable or to keep a small test from becoming a burst. It does not impose a rate limit on other senders or on the listener. -v makes the program more verbose for debugging; enable it for a short diagnostic run and avoid treating verbose output as a stable interface for scripts.

8. Select the address family when needed

Postfix uses IPv4 and IPv6 by default where supported. Add -4 to require IPv4 or -6 to require IPv6. The IPv6 option is unavailable when Postfix was built without IPv6 support, and -4 has no effect in that build. An explicit address can make the test easier to reason about:

$ qmqp-source -4 -c -m 1 -s 1 \
    -f [email protected] -t [email protected] 127.0.0.1:628

Do not add -6 merely because a hostname has an AAAA record. First confirm that the listener is bound on IPv6 and that the host's routing and firewall permit the connection.

Done means