Knowledge base

How the node selects a source and combines its settings

critical

<source> matching and inheritance
A setting takes effect somewhere other than where it is written

<source> blocks come in two breeds, and they behave differently.

Address blocks name one address (10.0.0.5) or a network in classless notation (10/8). A connection falls under all blocks whose addresses cover it, and the settings add up — exactly as with receiver blocks: where two blocks say different things, the narrower one wins.

The manual prints its own example twice — as written and as the engine sees it after merging. It is the clearest passage in the chapter: reading the configuration line by line is useless; what takes effect is not a line but the sum of lines.

Named blocks (<source S1>) are not matched against addresses at all. They are enabled only when referenced by name: with the source= parameter on smtp-listener or with the source directive inside <smtp-user>.

What happens to the address settings in that case the manual describes in one word: the named block overrides what was matched by address. The word promises inheritance — a setting the named block says nothing about should come to it from the address block.

For us it turned out differently. Return address rewriting set in the general 0/0 block did not carry over to an authenticated connection: the address stayed unchanged until the same line was repeated in the named block. Hence the rule by which the Hub now assembles the configuration — the named block repeats the whole set, not just what differs.

Names in curly braces are reserved. The manual names two: {pickup} changes how the pickup directory is processed, {auth} sets defaults for any authenticated user.

The main trap. The question “is this client allowed to submit mail” is not answered by any single block — it is answered by their sum. And after a login the answer may change once more: the user’s named block overrides everything matched by address.

Hence the practical rule: a permission granted in the 0/0 block also applies to all subnets for which nothing to the contrary is said. “Grant it only to our own” means a ban in the wide block and a permission in the narrow one, not the other way around.

What the Hub does. It writes source blocks of both breeds, in two files.

In the main file there are address blocks: 127.0.0.1 for submission from the machine itself, a block for each address in “Who may submit mail”, and 0/0 as the common base. The narrow block inherits from the wide one everything it does not say itself: stream selection by submission address, the selection list and the suppression of local reports. In the base configuration, installed before any pairs exist, 0/0 has neither stream selection nor the list yet.

In the addresses file there are named ones, one per submission login: the common {pmta-auth} and a block for each “domain plus address” pair. The source directive inside <smtp-user> refers to them. In each such block the Hub writes out the full set — the submission service, the relaying permission, the authentication requirement, stream selection, the suppression of local reports, header handling — not just the differences from the address blocks. This is not out of caution: we did not see inheritance reach the authenticated connection.

The Hub puts names in curly braces — a format shared with Protosender. The manual declares this namespace reserved and names two of its own names in it; ours do not resemble them and they work, but the namespace is still the vendor’s.

Example configuration
# both blocks cover submission from the machine itself — they act merged
<source 0/0>
    default-virtual-mta by-smtp-source-ip
    add-received-header false
</source>

<source 127.0.0.1>
    always-allow-relaying yes    max-message-size 30M
</source>
Submission from the machine itself gets a relaying permission and its own size limit — plus everything from the wide block: stream selection by address and no added Received header. The narrowest block has neither of those two lines.
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 ends4 mistakes▶

Reading the configuration line by line

§ 3.3.7

What it costsThe setting is looked for in the block with the submission address — and not found, because it is written in the wide one. Or the other way around: it is found in the wide one and assumed to be in effect, although the narrow one overrode it. The manual prints the example before and after merging precisely for this case.
How to spot itThe node behaves differently from what is written in the block you are reading.
How to do it rightWrite out all the blocks covering the submission address and layer them by the “narrow over wide” rule. A setting that is in none of them takes the vendor default.

Expecting a named block to be matched on its own

§ 3.3.7

What it costsNamed blocks are not matched against addresses. A block nobody refers to never takes effect — and the settings written in it apply to no connection.
How to spot itThe submission login works, but behaves like an anonymous connection from the same address.
How to do it rightRefer to the block by name — with the source= parameter on the listener or with the source directive inside the user block.

Relying on inheritance into a named block

our experience

What it costsThe manual says “overrides,” which implies that whatever is not mentioned comes from the address block. It did not work that way for us: return address rewriting from the general block did not carry over to the authenticated connection, and the return address stayed unchanged.
How to spot itA setting written in the general block does not take effect for submission under a login — while for the same submission without a login it does.
How to do it rightRepeat the whole set in the named block, not just the differences. Check by behavior, not by reading the configuration.

Allowing in the wide block and hoping to restrict with the narrow one

our experience

What it costsMerging goes from top to bottom by narrowness, not by the order of lines in the file. A permission in the 0/0 block goes to every subnet that has not said otherwise itself — including the one all this was set up for.
How to spot itAnyone can submit mail, even though the narrow block looks restrictive.
How to do it rightPut the ban in the wide block and the permission in the narrow one. Check by merging, not by reading a single line.
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.
How to check on the node
The node does not show the merged view — no command prints source settings. You will have to assemble it by eye, from two files:
grep -n '^<source\|^</source' /etc/pmta/config /etc/pmta/virtualhost.txt
pmta test config
The first command gives the list of blocks and their boundaries, the second checks that the file parses at all. After that it is manual work: write out all the blocks the submission address falls under and layer them by the “narrow over wide” rule. Unlike for receivers, the engine has no show settings command for sources.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Configuration lifecycle · Node security · Sender isolation
Priority
critical