Knowledge base

map-header-to-field

<acct-file>

Substituting a message header into a standard accounting field
in the configuration this is a linemap-header-to-field noneinside the block <acct-file>
When your own value is needed in someone else’s column

The line takes the contents of a message header and puts it into a standard field of the accounting record — for one record type. Not set by default.

The difference from record-fields is fundamental. There the header is added as a new column (header_NAME), and the parsing program must know about it. Here it replaces an existing column — and a program that already reads it will get your value without a single change.

Several lines can be written for one field, and order matters: the first header found in the message is taken. If none is found, the field keeps its original value.

One header can be spread across several fields, and it will go into each.

The line does not work with the tq type — the manual notes this separately.

The main trap is replacing a field that someone else’s parsing relies on. The field keeps its name and changes its meaning: the recipient column holds not an address but your identifier. The mistake is silent — the data looks plausible and means something else.
What the Hub does. It does not write it: we link to our side more honestly — with a separate column through record-fields (*,header_NAME), and the receiver knows it is a header.

The line will come in handy when migrating someone else’s node where the statistics collector was written for a fixed set of columns and cannot be rewritten.

Recommended values

The order of lines is part of the setting:

Entry What it does
d header_x-uid rcpt the header goes into the recipient field of deliveries
a second line for the same field taken if the first header is not in the message
d header_x-uid orig the same header also goes into a second field

The tq type is not supported.

The syntax, the significance of order, the fallback to the original value, the exclusion of tq and the ability to spread one header across several fields come from the manual (§ 3.3.11.10). The comparison with record-fields is ours.
Example configuration
# a third-party collector reads the rcpt column, and it cannot be rewritten
<acct-file /var/log/pmta/acct.csv>
    records d, b
    map-header-to-field d header_x-uid rcpt    map-header-to-field d header_x-legacy-uid rcpt
</acct-file>
The second line is a fallback: it fires only if the first header is not in the message. If neither is found, the column will keep the real recipient address.
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 ends2 mistakes▶

Replacing a field without warning the parsing side

our experience

What it costsThe column keeps its name and changes its meaning. Analytics keeps treating it as the recipient address, while it holds an identifier — and the mistake looks like plausible data.
How to spot itThe recipient column holds values that do not look like addresses.
How to do it rightAgree with the parsing side or move the value into a separate column through record-fields.

Expecting substitution in tq records

§ 3.3.11.10

What it costsThis type is not supported by the line. The setting will silently not apply to it, and the field will stay original.
How to spot itSubstitution works for deliveries and does not work for queue-level errors.
How to do it rightFor tq, use a separate column in record-fields.
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
map-header-to-field <mapping>
Values
a record type, then header_NAME, then an accounting field name
Default
none § 3.3.11.10
Applying
reload, no restart needed
Queue
will not touch what is already queued
Where to write it
<acct-file>
How many times
once in the block
Everything here comes from the manual, with the section.
Inheritance
There is no inheritance: the line lives inside its <acct-file> and applies to one record type in it. A neighboring accounting block can write the same event with unreplaced fields — that is how it should be done if the replacement is needed by only one consumer.
How to check on the node
Check the column’s contents, not the presence of the line:
head -3 "$(ls -t /var/log/pmta/acct-*.csv | head -1)"
The replaced column should hold the header’s value. If it holds the previous value, none of the listed headers was in the message — that is the normal fallback.
In the Hub
Cost of a mistake
dangerous: effects outlast a rollback
Scenarios
Collect telemetry