Enable Postfix QMQP Safely with an Authorised Client List

QMQP can relay mail to arbitrary destinations, so an exposed or broadly authorised qmqpd is a serious mail-abuse risk waiting to happen. This guide enables Postfix's QMQP server on port 628, allows only named client addresses, reloads the service, and verifies that the listener is present. The examples use Postfix 3.8.6, installed here as package version 3.8.6-1ubuntu0.1.

Allow about twenty minutes. You need root or equivalent privilege to edit Postfix configuration and reload the daemon, plus a QMQP-speaking client elsewhere on your network if you want to test delivery. This guide does not send a message or alter a queue.

Security boundary: keep the service disabled unless you have a known client that requires it, and restrict both the Postfix allow-list and any firewall rule to that client.

1. Confirm the installed Postfix and service state

Check the package and the active configuration directory as ordinary, read-only commands:

$ postconf mail_version
mail_version = 3.8.6
$ postconf -h config_directory
/etc/postfix
$ postconf -M qmqpd/inet

The last command prints nothing on this machine because the QMQP service is commented out in /etc/postfix/master.cf. Postfix ships the service definition as a disabled line, and the qmqpd daemon is normally started by master, not launched directly from a shell.

Checkpoint: keep a copy of the files before editing them. This is an elevated, state-changing step:

# cp --preserve=all /etc/postfix/master.cf /etc/postfix/master.cf.before-qmqpd
# cp --preserve=all /etc/postfix/main.cf /etc/postfix/main.cf.before-qmqpd

If you need to abandon the change, restore those copies with cp and run postfix reload. Do not remove the backups until the service has been tested and accepted.

2. Choose the only clients that may connect

The default qmqpd_authorized_clients value is empty, which denies every client, because QMQP allows relay to any destination. Choose a specific address or a tightly bounded network. Use documentation addresses in a plan first, then replace them with the real address:

# postconf -e 'qmqpd_authorized_clients = 192.0.2.10'
# postconf qmqpd_authorized_clients
qmqpd_authorized_clients = 192.0.2.10

Postfix accepts host names, domain names, IP addresses, network and mask patterns, file names, and table specifications. Patterns are separated by whitespace or commas, and a leading ! reverses a match. For example, this allows a test network except for one address:

# postconf -e 'qmqpd_authorized_clients = !192.168.0.1, 192.168.0.0/24'
# postconf qmqpd_authorized_clients
qmqpd_authorized_clients = !192.168.0.1, 192.168.0.0/24

Warning: do not use 0.0.0.0/0, a wildcard domain, or an unreviewed hostname here. DNS names can change, and a wide network allowance turns a local integration endpoint into a relay for every host that can reach it. If your clients have fixed addresses, prefer those addresses.

Recovery: to return to the deny-all default while leaving the service definition in place, run:

# postconf -e 'qmqpd_authorized_clients ='
# postconf qmqpd_authorized_clients
qmqpd_authorized_clients =

3. Enable the port 628 service

Open master.cf with an editor that preserves the file as root:

# sudoedit /etc/postfix/master.cf

Find the commented QMQP definition and remove only its leading #:

628       inet  n       -       y       -       -       qmqpd

On this installation the shipped line is already present at port 628. Do not change the service name, switch it to a different daemon, or copy an SMTP restriction block into it: QMQP has one access policy, the client allow-list, and it does not provide a per-recipient rejection phase.

Run the configuration checks before reloading:

# postfix check
# postconf -M qmqpd/inet
qmqpd inet n - y - - qmqpd

The exact spacing can differ between Postfix builds. The useful check is that a qmqpd service is returned for inet on port 628. If postfix check reports an error, stop and fix the file before any reload.

4. Reload and verify the listener

Reloading is elevated and can affect the running mail service, although it is not a full stop and start:

# postfix reload
postfix/postfix-script: refreshing the Postfix mail system

Postfix qmqpd processes read changes to main.cf automatically over their limited lifetime; postfix reload speeds up the change and also makes the master.cf service definition active.

Check the TCP listener without sending mail:

$ ss -ltn | awk '$4 ~ /:628$/ {print}'
LISTEN 0      100          0.0.0.0:628       0.0.0.0:*

Your backlog, address family, and bound address may differ. If there is no line for port 628, check postfix status, rerun postfix check, inspect the service line, and read the Postfix log configured by syslog_facility and syslog_name. A listener alone does not prove that an unauthorised host will be rejected.

5. Test from the approved client

Use the real QMQP client only after checking the network path and the source address it will use. There is no general SMTP command that substitutes for a QMQP test. Send one harmless message to a controlled mailbox, then inspect the Postfix log and queue state.

Remember that QMQP sends one message per connection and the server receives the entire message before replying. A malformed message or an overlong netstring can make Postfix reply immediately and close the connection: the protocol provides only one server reply per delivery, so an individual recipient cannot be rejected after the message has been accepted.

If the client is rejected, first compare its observed source address with postconf qmqpd_authorized_clients. Do not solve an allow-list mistake by permitting the whole subnet. If the client is accepted but delivery does not behave as expected, inspect the log and queue instead of repeatedly resending the message.

6. Set limits that match the integration

The local qmqpd defaults are a 10,240,000-byte message limit, a 2,048-character input line limit, a 50-header hop-count limit, a 300-second network timeout, and a one-second delay before a negative reply. Inspect them before deciding whether the integration needs a change:

$ postconf -h message_size_limit line_length_limit hopcount_limit qmqpd_timeout qmqpd_error_delay
10240000
2048
50
300s
1s

These are global or QMQP-specific controls, not tuning suggestions to apply blindly. A smaller message limit may be appropriate for a narrowly defined feed, but changing it can reject legitimate messages. Change one value at a time, record the reason, run postfix check, and reload, keeping the previous value ready as the undo operation.

Done means