Knowledge base

Headers the sender uses to control delivery

critical

X- control headers
The decision is made not by the configuration but by the message

Six headers through which the submitting side controls delivery, and each has its own switch on the source:

Header What it does Permission Keep in the message
X-Virtual-MTA selects the sending stream process-x-virtual-mta retain-x-virtual-mta
x-job tags the message with a job process-x-job retain-x-job
x-envid sets the envelope identifier process-x-envid —
X-DKIM-Options edits the signing options process-x-dkim-options retain-x-dkim-options
X-DKIM-Key brings a private key process-x-dkim-key retain-x-dkim-key
x-schedule sets sending windows process-x-schedule retain-x-schedule

The design is the same: one directive decides whether to read the header, the other whether it stays in the message after delivery. The manual stresses that the halves are independent: they can be set in any combination, and neither knows anything about the other.

All defaults are false. That is, header control is off until it is enabled for the source submission comes from. A platform counting on stream selection by header will get no error against a source without permission — the selection simply will not work.

The main trap is that the manual contradicts itself in the most dangerous place.

The section on processing the signing key says: if processing is not enabled, the engine does not remove the header, and it advises checking the installation so that private keys do not leak. The section on retaining the same header claims the opposite: with both directives false, the engine ignores the header but still removes it before delivery.

The other sections diverge the same way: the three “process” sections — for the stream, for the envelope identifier, for the signing options — directly say “leaving the header in the message if it was there.” Both phrases about removal are in the “retain” sections and are written as carbon copies.

The weight of evidence is on the side of “stays in the message,” and the cost of error is asymmetric: in the worst case the private key travels to the recipient. Follow the manual’s own advice — check it on your installation rather than choosing between two phrases.

What the Hub does. It uses one header out of six — X-Virtual-MTA. The permission for it is set in every source of the working configuration: both in those selected by address and in the named login-based submission sources. Warm-up puts this header on every message, and it is the main way of selecting a sending address.

The job header the Hub forbids explicitly — with a process-x-job false line in every named submission source. The other four it does not set at all: they stay at the vendor default false.

The Hub does not touch header retention anywhere, that is, it relies on the default. For X-Virtual-MTA this means the stream name is stripped before delivery and is not shown to the recipient.

Example configuration
# permissions are granted to a source, not to the node as a whole
<source 10.0.0.0/24>
    process-x-virtual-mta yes    process-x-job false
    always-allow-relaying yes
</source>
From this subnet, stream selection by header will work; the engine will not read the job tag. Both lines concern only this subnet — the neighboring block decides for itself.
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▶

Assuming an unread header disappears

§ 3.3.7.44

What it costsThree sections of the manual say the opposite directly: with processing off, the header stays in the message and travels to the recipient. Internal stream names, job tags and — in the worst case — the private signing key end up with the addressee.
How to spot itThe delivered message shows control headers that should not be there.
How to do it rightCheck on your installation — send a message with all the control headers to your own mailbox and see what arrives. It is also the only way to resolve the manual’s contradiction.

Granting the permission to the wrong source

§ 3.3.7

What it costsA permission works by the source merge rules, while the platform submits from a specific address or under a login. A line in a block the submission does not fall under does nothing — and no error arises.
How to spot itThe platform sets the header, the node ignores it, and there is nothing unusual in the submission logs.
How to do it rightDetermine the block the submission falls under and put the permission there. For submission under a login, that is a named block, not an address block.

Relying on the engine to protect the private key

§ 3.3.7.46

What it costsThe key travels the whole way from the submitting application to the node in the message body: through queues, logs and intermediate storage. Whatever the engine does with the header before delivery, it does not protect that path.
How to spot itThe private key turns up in the submitting side’s logs.
How to do it rightKeep keys in the node configuration and do not pass them in messages. A header with a key is justified only where the entire path to the node is yours.
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 permissions are visible only in the configuration — the engine has no separate command for them:
grep -n 'process-x-\|retain-x-\|jobid-' /etc/pmta/config /etc/pmta/virtualhost.txt
The lines found need to be sorted by source block and layered by the merge rule: a permission in a wide block goes to the narrow ones too. Whether a header worked is visible from the consequence: the stream name in accounting, the job tag in the job list, the signature in the delivered message.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Sending address rotation · Node security · Connect a sending platform
Priority
critical