Knowledge base

A queue is a receiving server together with a sending address

critical

queue
A pair, not a domain — and everything else depends on it

One phrase in the manual, said in passing while describing a monitor screen, carries half of the delivery model: messages are grouped by recipient domain separately for each sending address. The same gmail.com sent from two addresses is two queues, not one.

What follows from this. The receiver block limits count the pair, not the domain: max-msg-rate 500/h with two sending addresses means a thousand messages an hour to gmail.com. backoff-mode is also switched on per pair: from one address the queue can be in backoff mode, from another in normal mode. The number of simultaneous connections the receiving server sees from one address has nothing to do with how many another address has opened.

More addresses mean more queues, not less work in each. The same flow of messages spread across three addresses instead of one gives three queues, each with its own full limit. The work is not divided — it is multiplied.

Summaries count differently, and that is not a mistake. The domains screen adds all the addresses together, the queues screen does not. The same number will differ between them, because they are different aggregates.

The main trap is writing a limit “per receiver” while thinking of the domain. The line max-msg-rate 500/h in a node-level <domain gmail.com> block goes to each queue of this domain — that is, to each sending address. Add a fourth address and the allowed flow to gmail.com grows by a quarter, even though the configuration was not touched. The engine has no real “per domain across the whole node” boundary at all: it would have to be calculated outside.
What the Hub does. It reads queues exactly as a pair — the node summary returns them as “sending address per domain,” and the Hub stores backoff episodes per queue, not per domain. The model exists in the product.

⚠️ But analytics adds addresses together in places. Breakdowns by provider sum all addresses together — where the engine does not. The number on the “deliverability by provider” screen answers the question “how are we doing with this receiver overall,” not “what is happening in a specific queue,” and the two must not be confused.

And nothing checks that a limit landed in the intended queue. The Hub writes presets into the receiver block inside the sending address block — so per pair, correctly. But anything written by hand into a common block goes to all addresses at once, and there is no warning about it.

Recommended values

The concept has no values of its own — what matters is where the setting is written:

Where the line is written Who gets it
a receiver block inside an address block one queue — that very pair
a receiver block at the node level each queue of this domain, one per address
a receiver block inside a pool each queue of each pool member

The rule: if a number is meant “per receiver from this address,” write it inside the address block. That is what the Hub does, and it is how it should be done by hand too. A common block is fine for what holds for any address: the retry schedule, the encryption requirement, the bounce deadline.

The flow per domain has to be calculated by yourself. Multiply the queue limit by the number of addresses this domain is sent from — there is no other way to find out the allowed total rate.

The table and the rule “per receiver from this address — inside the address block” are ours. From the manual here are the very definition of a queue as a pair and the fact that the domains summary and the queues summary count different things.
Example configuration
# the same line in two places means different things
<domain gmail.com>
    bounce-after 4d          # true for any address — a common block
</domain>
<virtual-mta mta-news-1>
    <domain gmail.com>
        max-msg-rate 500/h   # only for the gmail.com/mta-news-1 queue    </domain>
</virtual-mta>
The top block sets the bounce deadline for all queues of this domain — it is a property of the receiver, not of the address. The highlighted line lives inside the address and goes to one queue: the second address will have its own rate, not a share of this one.
yellow — — directive names, blue — blocks. They are highlighted the same way in the text of the card.
▲

Common mistakes and problems

what people get wrong and how it ends3 mistakes▶

Treating the queue limit as a per-domain limit

§ 5.4

What it costsThe limit goes to each queue of this domain, that is, to each sending address. The total flow to the receiving server equals the limit multiplied by the number of addresses, and it grows with every new address without a single configuration edit.
How to spot itThe receiving server complains about the rate, while the configuration has a value that by calculation is two to three times below the acceptable one.
How to do it rightMultiply the queue limit by the number of addresses before comparing it with the receiving server’s acceptable rate. The engine has no “per domain across the whole node” boundary — it has to be calculated outside.

Comparing numbers from the domains screen and the queues screen

§ 5.4

What it costsThese are different aggregates: the first adds addresses together, the second does not. The discrepancy is taken for a counter error, and the cause is sought where there is none.
How to spot itThe sum across queues does not match the number on the domain line.
How to do it rightRemember which view is in front of you. To analyze a specific problem take the queues; to assess the relationship with a receiver take the domains.

Spreading the flow across addresses, expecting the load to be shared

§ 5.4

What it costsEach new address creates a new queue with a full limit rather than taking part of the work from an existing one. The receiving server gets more parallel flows, not the same flow by other routes.
How to spot itAfter adding addresses the receiving server’s bounce rate grew, even though the total number of messages did not change.
How to do it rightLower the queue limit when increasing the number of addresses if the total rate to the receiver must stay the same.
Compatibility
PowerMTA 6.0
described in the manual of this version · platform: any
The vendor does not state the first version for every directive — there is no note here. The name also appears in the 5.0 edition of the manual.
Inheritance
A queue is not inherited — it appears by itself as soon as there is a message for the pair. Settings are inherited: the node-level receiver block merges with the receiver block inside a pool and inside a sending address, and the narrowest level is the strongest. That is exactly why the same directive written at different levels goes to a different number of queues.
How to check on the node
Two commands show two different views — and the difference between them is worth seeing once:
pmta show queues
pmta show domains
The first lists queues — one line per pair, with each one’s mode and counters. The second adds addresses together and gives one line per domain. For one domain sent from three addresses the first will have three lines and the second one, and the numbers will not match — that is by design.
In the Hub
Cost of a mistake
safe: a wrong value breaks nothing
Scenarios
Address warm-up · Tune the pace for a provider · Untangle a stuck queue
Priority
critical