Knowledge base

The stream is named by a header, if the source is allowed to do so

critical

X-Virtual-MTA header selection
X-Virtual-MTA — the most common way to name a stream

For this to work, three things must come together: the stream is declared in the configuration; the submission address falls into some <source> block; and that block has the permission to process the header. Without the third, the header is not an error but empty space — the engine simply does not read it.

The header is stripped before delivery — that is the default, and it is the right one: the line names the fleet’s internal names, and the recipient has no need to know them. It can be kept, but deliberately.

A pool name works too. The same header with a pool name instead of a stream name, and the message leaves through one of the members in rotation.

This is our main method. Hub warm-up names the address precisely with this header: it is precise down to the message, visible at submission and requires nothing from the configuration except one permission line.

The main trap. The permission is granted to the source as a whole and is not limited to a list of streams. You cannot say “this sender may name only its own three addresses”: by allowing the header, you have allowed naming any stream on the node, including one being warmed up for someone else. The only boundary is not granting the permission at all.
What the Hub does. It writes the permission itself: process-x-virtual-mta yes 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 the header on every message. There is no “who may name which streams” restriction — the engine does not have one either — so client separation rests on submission going under different logins and through the Hub itself, not directly into the node.
Recommended values

The mechanism has no values of its own. Three neighboring source directives are configured: process-x-virtual-mta — whether to read the header, retain-x-virtual-mta — whether to keep it in the message, allow-empty-x-virtual-mta — what counts as an empty value. All three default to “no, do not,” and that is a sensible default set.

All from the manual — the three directives, their defaults and the rule “without the permission the header is neither read nor stripped.”
Example configuration
# the permission is granted to the source; the header in the message names the stream
<virtual-mta shop-example-com>
    smtp-source-host 203.0.113.10 shop.example.com
</virtual-mta>

<source 10.0.0.0/24>
    process-x-virtual-mta yes    always-allow-relaying yes
</source>
A message submitted from this subnet with the line x-virtual-mta: shop-example-com will leave from the address 203.0.113.10. Without the process-x-virtual-mta line, the same header does nothing — and travels to the recipient.
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▶

Granting the permission to the wrong source

§ 3.3.7.52

What it costsThe source is chosen by the submitter’s address, and a node usually has several <source> blocks. A permission written into a block the submission does not fall under does nothing: the header is not read, the stream is taken from the default, and the line itself travels to the recipient.
How to spot itThe header is visible in the delivered message; accounting has the stream name from the default.
How to do it rightFind the <source> block the submission address falls under and put the permission there. A narrower block overrides a wider one — check the narrowest of the matching ones.

Granting the permission to a client source

§ 9.4.1

What it costsThe set of streams cannot be restricted: by allowing the header, you have allowed naming any stream on the node. A client may leave from an address being warmed up for someone else and ruin another’s reputation.
How to spot itIn accounting, one client shows another client’s stream names.
How to do it rightDo not grant the permission to sources you do not trust. If they do need a choice, give it with a pattern rule where you define the “sender → stream” mapping.

Keeping the header in the message for no reason

§ 3.3.7.53

What it costsretain-x-virtual-mta yes delivers the fleet’s internal stream names to the recipient. It brings no benefit at all, while revealing how the infrastructure is built.
How to spot itThe source of the delivered message shows X-Virtual-MTA with a telling name like shop-example-com.
How to do it rightKeep the no default. If the stream name is needed for analysis, it is already in accounting, in the vmta field.
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
The mechanism has no inheritance: the header is parsed in every message. The permissions are inherited — all three directives are written in <source> and merge by the source rule: a narrower block overrides a wider one. So a permission granted in <source> 0/0 also applies to all subnets for which nothing to the contrary is said.
How to check on the node
Check in two steps: that the stream exists and that the message left through exactly it. The first — on the node:
pmta show vmtas
The name from the header must match a line of this list literally. The second — in accounting: pmtaacctfind –output csv[vmta,rcpt] will show which stream the message actually left through. If the name is in the list but accounting has a different one, the header permission was not granted to the source submission comes from.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Address warm-up · Sender isolation
Priority
critical