Knowledge base

record-fields

<acct-file>criticalset by the Hub

Which fields go into records of the chosen type
in the configuration this is a linerecord-fields all fields for each selected typeinside the block <acct-file>
Columns that cannot be restored later

The line sets the set of columns for one record type, and it is written separately for each type. The default is *.

The star is not “all fields” but the default set. The directive description says “all”, but the field tables are more precise: * gives the fields marked with a star. The first-attempt time, the retry count, encryption and proxy fields are not in it — they are named explicitly.

The list syntax is simple and worth memorizing whole:

Entry Meaning
* the default fields for this type
timeLogged,orig,rcpt only the listed ones
*,!orcpt the default fields except the one named
*,header_Message-Id the default fields plus a message header

An arbitrary header is header_NAME. This is how anything you put in the message yourself gets into accounting: a campaign identifier, the recipient’s identifier in your database, anything. It is the only way to tie an accounting record to your side.

A field not selected cannot be recovered. Downstream it produces not an error but emptiness, and no processing will bring it back.

Some fields are unlocked by other lines. The first-attempt time appears only with track-time-first-attempt; the user-string text only if the userString field is listed.

The main trap is narrowing the list for the sake of file size. The savings are small: accounting lines are short, and on disk transient errors dominate anyway unless they have been moved out separately. The price, meanwhile, is permanently losing the ability to answer a question nobody has asked yet.
What the Hub does. It writes it — in both accounting blocks. The base for each type is the asterisk, the standard set of fields. Deliveries and bounces (d, b) also get timeFirstAttempt, totalSecondsQueued and numRetries: the asterisk does not include them (§ 12.2.1), and without them there is no way to tell where delivery time goes. Complaints in the telemetry block also get header_feedback-id — the header with the complaint identifier.

The choice is deliberate: a narrow set would save little, while questions to telemetry keep piling up over time. The batch is parsed by our receiver, and extra fields cost it nothing.

Recommended values

Start with the asterisk and narrow it only for a measured reason:

Value When
* (default) almost always
*,header_NAME a link to your own database is needed
*,!field one field gets in the way — a long one, for example
an explicit list an external requirement on the data composition

Each record type has its own list — the line is repeated once per type.

The star default, its meaning according to the field tables, exclusions and header_XXX come from the manual (§ 3.3.11.12, § 12.2.1–12.2.7). The analysis of our choice is based on the Hub code.
Example configuration
# the default set for each type, plus the complaint header for feedback-loop
<acct-file /var/log/pmta/mtahub-webhook.json>
    records d, b, rb, t, feedback-loop
    record-fields d  *    record-fields b  *
    record-fields f  *,header_feedback-id
</acct-file>
The line is written once per record type. A message header gets into accounting only this way — by listing header_NAME.
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▶

Narrowing the field set and discovering the loss a month later

our experience

What it costsDownstream, a field that was not selected produces emptiness, not an error. People notice when they first need to answer a question involving it — and past records can no longer be restored.
How to spot itThe analytics has the column, but not a single record has a value in it.
How to do it rightReturn to * and narrow only on a requirement, not for the sake of savings.

Expecting a message header in accounting without listing it explicitly

§ 3.3.11.12

What it costsThe asterisk means all standard fields of the type. Message headers are not included in it and are added only with a header_NAME entry.
How to spot itThe message has the header, accounting does not.
How to do it rightAdd *,header_NAME for the record type you need.

Writing one line for all record types

our experience

What it costsThe line applies to one type, named by the first word. The types it was not written for take the default — and that works, but it looks like a setting that does not exist.
How to spot itThe field set is set “for all,” yet in the file it differs between types.
How to do it rightWrite one line per type or rely on the default deliberately.
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
record-fields <field-list>
Values
a comma-separated list of fields; * — all, ! — exclude, header_NAME — a message header
Default
all fields for each selected type § 3.3.11.12
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. Different accounting blocks can write the same type with different sets of fields.
How to check on the node
For a CSV file, the column set is visible in the header — the first line of the file:
head -1 "$(ls -t /var/log/pmta/acct-*.csv | head -1)"
For the JSON format the fields are visible in any record: head -1 file.json. If an expected field is missing, check two things — whether it is listed here and whether it needs a separate line, like the first attempt time.
In the Hub
Value
The Hub picks it itself — pace, warm-up stage, metrics
Cost of a mistake
reversible: harms only while it is set
Scenarios
Troubleshoot deliverability · Collect telemetry
Priority
critical