Knowledge base

Address lists — named and unnamed

<address-list>
One construct for three different tasks

Five directives fill a list: an address or pattern, a whole domain, addresses from a file and two hashed forms.

The name decides what the list is for. A named list is attached by name — suppression-lists for suppression, allowed-sender-lists for allowed senders. An unnamed one is written inside a bounce or complaint processor block and selects the mail that processor parses.

The hashed form deserves more attention than the manual gives it. The address is lowercased, hashed with SHA256 and encoded as BASE64URL; the engine hashes the address being checked and compares the hashes. That is, a suppression list can be handed over and stored without a single readable address in it. Patterns do not apply to hashes — only whole addresses.

Three tasks on one construct — what to suppress, who is allowed to send and which inbound mail to parse. That is why this is a mechanism, not a detail of one of the three.

The main trap is mixing up the two forms in your head. Patterns do not apply to hashes: /^bounce@/ in a hashed list will match nothing, because hashes of whole addresses are compared. Conversely, a regular list can be read by anyone with access to the configuration or its backup.
What the Hub does. It uses the unnamed form, and actively: the node’s base configuration has two unnamed lists — one inside the complaint processor (it catches fbl@fbl.<domain>), the other inside the bounce processor (it catches bounce@bounce.<domain> and the role addresses dmarc@, postmaster@, abuse@). The Hub does not write named lists: our suppression works before the node, with its own list in the database.
Recommended values

The mechanism has no values of its own — they are set by the five directives inside. Choosing the form:

Form What goes in Feature
address an address, a local part or a pattern the most flexible, readable by anyone
domain a whole domain one line instead of a listing
address-file addresses from a file, one per line the configuration does not grow
hashed-address a hash of a whole address no readable addresses in the file
hashed-address-file hashes from a file the same for a long list

When to use hashes. When the list must not be shown — for example, a client requires its suppression to be honored but does not hand over the addresses. The node will enforce a list it cannot read.

All five forms, how the hash is built and the “patterns do not apply to hashes” rule come from the manual (§ 3.3.5). The advice about a client list is ours.
Example configuration
# an unnamed list selects mail for the processor — this is how the Hub writes it
<bounce-processor>
    deliver-matched-email no
    deliver-unmatched-email no
    <address-list>        address /^bounce@bounce\./
    </address-list>
</bounce-processor>

# a named list is attached by name — this is how suppression is enabled
<address-list suppression1>
    hashed-address iZ0zh6XFp1VdUdLwoLe1Djl_5IH9mlj6-zibfclOEfY~
</address-list>
The upper list is unnamed: it lives inside the processor and selects the messages it will parse. The lower one is named — it is attached with the suppression-lists line. It holds a hash, and the configuration file does not reveal whose address it is.
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▶

Writing a pattern in a hashed list

§ 3.3.5.2

What it costsPatterns do not apply to hashes: hashes of whole addresses are compared. A line like /^bounce@/ will match nothing and will not cause an error either.
How to spot itThe list is configured, but suppression never triggers.
How to do it rightIn hashed lists — only whole addresses computed with the tool. Keep patterns in a regular list.

Forgetting that an unnamed list is not suppression

§ 3.3.5

What it costsAn unnamed list inside a processor selects mail for parsing; it does not suppress it. The expectation “I added the address, so messages will not go out” is not met here at all.
How to spot itThe address is on the list, yet messages still go to it.
How to do it rightFor suppression, create a named list and attach it with the suppression-lists line.

Putting someone else's readable list in the configuration

our experience

What it costsThe configuration file and its backups can be read by anyone with access to the node. A client’s suppression list in plain form is an export of their database sitting in a backup.
How to spot itIt is discovered during an access review, not in operation.
How to do it rightUse the hashed form. The node will enforce a list it cannot read, and neither the file nor the backup will reveal the addresses.
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 list itself has no inheritance: it is declared at the root of the file (or inside a processor) and inherits nothing. What is inherited is references to it — suppression-lists in <source> merges by the source rule, in a pool it goes to members, and a member’s own line overrides the pool one.
How to check on the node
The hash can be computed with the same tool the engine uses — and compared with what is in the list:
pmtahashedAddress test@FOO.com
The tool lowercases the address itself, so test@FOO.com and test@foo.com produce the same hash. If the list line does not match it character for character, there will be no match: patterns do not apply to hashes.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Receiving inbound mail · Address suppression · Sender isolation