Knowledge base

max-rcpt-per-message

<source>

How many recipients are accepted per message
in the configuration this is a linemax-rcpt-per-message 0inside the block <source>
The same name 1:<domain><source>— some of them are other settings, some are the same one
A ceiling on acceptance, not on sending

How many recipients the node agrees to accept in one message. The submitting system lists them with RCPT TO commands — one per address — and as soon as their number goes over the limit, the following ones get a refusal.

The default is 0, that is, no limit. Out of the box the node will accept a message with any number of addresses, however many the submitting system names. The directive is needed where such generosity has to be curbed: there are several submitters, or there is one, but it makes mistakes.

The refusal applies not to the message but to the extra addresses. Each RCPT TO over the limit is rejected on its own; the message stays accepted and goes to the recipients that fit. This behavior is switched by the neighboring line too-many-rcpts-fails-message: with it the refusal moves to DATA, and then the message is not accepted at all. Without it the extra addresses simply drop out of the message.

The namesake from the receiver block is a different directive. <domain> carries a setting with the same name, and it is not about acceptance but about sending: how many addresses to put into one transfer to the receiver. Its default is 1000, not 0, and its meaning is the opposite — not “how many to accept” but “into how many pieces to split.” The name clash is the vendor’s, and it is worth keeping in mind when reading someone else’s configuration.

The main trap. The extra recipients disappear silently — for the submitting system. The refusal comes for individual RCPT TO commands, and many mailers treat such a response as a failure of that particular address rather than a signal that “the message did not go to everyone”: the message is accepted, the report is green, and part of the list received nothing. Until too-many-rcpts-fails-message is set, the difference between “sent” and “accepted for sending” is visible only in the node’s log.
What the Hub does. It writes neither this line nor its pair too-many-rcpts-fails-message. The submission blocks the Hub builds contain authentication, sending address selection, return address rewriting and header editing; none of them has a recipient limit, and the vendor’s 0 remains.

For our submission this does not matter: warm-up sends messages to one recipient each — there is nothing to hit. The line would become necessary on a node that receives batches, and especially where there are several submitters.

Recommended values

Keep 0 while the submission is your own. The limit protects the node from someone else’s mistake. If messages are submitted by our own scheduler, one recipient per message, there is nothing to limit, and an extra line only adds a way to shoot yourself in the foot.

Set it when there are several submitters. Then the number is not taken out of thin air but from how those systems work: the largest legitimate batch size plus a margin. A value too low will start silently trimming mailings, a value too high will protect nothing.

Set it as a pair. Separately from too-many-rcpts-fails-message the limit is almost useless: it shrinks the message instead of rejecting it. The pair “limit plus refusal at DATA” gives the submitting system an honest failure it will see and can retry.

The order of choice is our recommendation. From the manual here come the value grammar, the 0 default and the fact that the refusal comes at RCPT and moves to DATA with the paired directive.
Example configuration
# a limit without the paired line trims the message; with it — rejects it entirely
<source 10.0.0.0/8>
    require-auth true
    max-rcpt-per-message 500    too-many-rcpts-fails-message true
</source>
The upper line sets the ceiling, the lower one decides what happens when it is exceeded: without it the extra addresses drop out, and the message goes to the rest.
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▶

Setting the limit without the paired line

§ 3.3.7.39

What it costsThe node does not refuse the message but accepts it without the extra addresses. The submitting system sees success, part of the list receives nothing, and the discrepancy surfaces only when reports are reconciled.
How to spot itThe number of delivered messages is consistently lower than the number sent, and there are no bounces in the reports.
How to do it rightSet too-many-rcpts-fails-message together with the limit — then going over it turns into an honest refusal at DATA, which the submitting system will record as a failure and can retry.

Copying the number from the receiver block

§ 3.3.10.83

What it costsThere, the directive with the same name cuts the outgoing transfer into pieces and defaults to a thousand. Here the same number becomes an acceptance ceiling — the meaning is different, and 1000 will turn out either excessive or, on a large batch, cutting.
How to spot itThe limit in the configuration looks meaningful but does not match any real batch size of the submitting system.
How to do it rightCount from submission: take the largest legitimate batch size and add a margin. The number from the receiver block does not carry over here.

Writing unlimited to mean “a bit more”

§ 3.3.7.39

What it costsunlimited and 0 are the same thing: there is no limit at all. The line looks like a setting but in fact returns the node to vendor behavior, and the protection it was added for does not work.
How to spot itThe configuration has a limit, yet a message with any number of addresses goes through in full.
How to do it rightWrite a number. If no limit is needed, it is better to remove the line entirely — that makes it clearer that there is no restriction.
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.
Reference data
Syntax
max-rcpt-per-message <integer>
Values
an integer, or 0 or unlimited — no limit
Default
0 § 3.3.7.39
Applying
reload, no restart needed
Queue
will not touch what is already queued
Where to write it
<source>
How many times
once in the block
Everything here comes from the manual, with the section.
Inheritance
The value merges across matching <source> blocks: a narrower address entry overrides a broader one — the same order as for receiver blocks. It is picked up by pmta reload, no service restart needed; it does not affect already accepted messages.
How to check on the node
The line lives in the submission block, and no node command prints it — you have to look at the configuration itself:
grep -n 'max-rcpt-per-message\|too-many-rcpts-fails-message' /etc/pmta/config
pmta test config
The first command will show both lines at once — separately they decide little. The second will check that the configuration parses at all. The behavior is checked by submitting a message with more addresses than the limit: without the paired line the message will be accepted trimmed.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Connect a sending platform