85.1.18. pepsi-stage-aliases¶
expand message recipients through an alias mapping file
- Manual section:
1
85.1.18.1.1. Name¶
pepsi-stage-aliases - the alias / mailing-list expansion stage of the Pepsi pipeline.
85.1.18.1.2. Synopsis¶
pepsi-stage-aliases [GLOBAL-OPTIONS] worker
85.1.18.1.3. Description¶
pepsi-stage-aliases is a stage program run by pepsi-dispatch(1). It
loads a pepsi.workqueue row (refusing to act unless its status is
running), reads its [stage-<stage>] section, and rewrites the message’s
envelope recipients through the alias map named by ALIASES. Every recipient
that matches an entry in the map is replaced by that entry’s target addresses;
recipients that match nothing are left unchanged. The resulting recipient list is
de-duplicated case-insensitively so each address is delivered to at most once,
and the message is advanced to NEXT_STAGE.
The stage only loads the envelope and state — never the headers or body. When
no recipient matches the map (and no duplicate is removed) the message is advanced
unchanged.
85.1.18.1.4. Alias file¶
ALIASES names a human-readable mapping file parsed like a Postfix virtual(5) table. Each non-blank line maps one key to one or more target addresses:
# comments begin with '#'; blank lines are ignored
postmaster@example.com alice@example.com
staff@example.com bob@example.com, carol@partner.example
@example.net ops@example.com
sales-*@example.org sales@example.com
The key (left-hand side) is the first whitespace-delimited field: a full
address, an @domain catch-all, or a * wildcard pattern (a *-glob
such as *@example.org or sales-*@example.org). The targets (right-hand
side) are separated by commas and/or whitespace and are kept verbatim — they may
be local or remote, but may not contain a wildcard. A line with a key but no
targets is ignored (a recipient is never silently deleted). If the same key
appears twice, the later line wins.
As in virtual(5), a line whose first character is whitespace continues
the previous mapping rather than starting a new one, so a long target list may
be wrapped over several lines; blank and all-comment lines in between do not
break such a continuation. A # begins a comment only at the start of a field
(at the start of the line, or after whitespace), so bug#42@example.com is an
ordinary key rather than a truncated one.
Warning
Wildcards are globs, not regular expressions. * matches any run of
characters and every other character — a . included — is a literal. To
alias a whole domain write *@example.net (or the @example.net
catch-all); .*@example.net is a regular expression and, read as a glob,
demands a leading dot, so it matches no real address and every message to that
domain falls through unaliased. (The pepsi.whitelist patterns of
pepsi-whitelist(1) are POSIX EREs; this map is not.) Both
pepsi-setup’s syntax check and the stage’s own map parser reject/flag a
regex-looking key and name the glob you probably meant.
The file is read into memory and re-read only when its identity changes —
modification time, size and inode, so an mtime-preserving replacement
(cp -p, a restored backup) is noticed too — and a busy worker therefore does
not re-parse it for every message. A missing file is an empty map (no aliases
configured). A file that exists but cannot be read (permissions, an I/O error) is
an error: the message is paused and retried with back-off, like any other fault
of the host, rather than delivered unaliased – a postmaster@ or catch-all
entry silently not applying would misdeliver or bounce it. The unreadable file is
not cached, so the next attempt reads it again.
pepsi-setup syntax-checks the ALIASES file at install time when it exists,
and writes a commented starter template when it does not (see
pepsi-setup(1)); a malformed line is reported there as a warning
before deployment rather than only at run time, never as a fatal error.
85.1.18.1.5. Matching and expansion¶
A recipient is lower-cased and looked up verbatim; on a miss the @domain
catch-all key for its domain is tried, and finally any * wildcard key — the
most specific matching wildcard wins (a narrow sales-*@example.org beats a
broad *@example.org beats a bare *; ties are broken deterministically).
Sub-address (+tag) detail is not stripped, so a specific list address such
as list+announce@example.com can be aliased on its own.
Expansion is transitive: when an alias target is itself a key it is expanded in turn, so nested distribution lists resolve to their leaf addresses. A loop — an alias that refers back to itself directly or through a chain — is broken by resolving the repeated key to its literal address rather than recursing forever. A chain deeper than 32 hops is stopped the same way (the address is delivered to literally, with a warning), so a generated map cannot overflow the worker’s stack.
85.1.18.1.6. Delivery Status Notifications¶
state.dsn.rcpt is parallel to the recipient list, so it is rebuilt in lockstep
with the rewritten recipients. An expanded target inherits the NOTIFY of the
original recipient it came from with any SUCCESS keyword removed (RFC 3461
§5.2.7.3(c): otherwise one submission to a five-member alias would draw five
positive DSNs for one recipient, and would disclose the alias’s membership; a
NOTIFY that was only SUCCESS becomes NEVER), and, following the same
section, carries an ORCPT pointing at the original recipient (its existing
ORCPT if it had one, otherwise rfc822;<original-recipient>). A recipient that was not expanded keeps
its DSN entry unchanged. Message-level RET/ENVID and all other state
keys are preserved.
85.1.18.1.7. Configuration¶
Options live in the stage’s own [stage-<name>] section
(PROGRAM = pepsi-stage-aliases): the ALIASES map-file path and the
NEXT_STAGE the expanded message advances to. Both are required — the
stage advances every message it sees, so pepsi-setup rejects a section
missing either. They are documented in pepsi.conf(5).
85.1.18.1.8. State¶
Inputs: the envelope rcpt_to and the per-recipient state.dsn.rcpt.
Outputs: a rewritten rcpt_to and a matching state.dsn.rcpt, written
only when the recipient list actually changed (an alias matched, or a duplicate
was removed); no other state is touched. The state layout is described in
pepsi.state(7).
Transitions: advances to NEXT_STAGE (the only transition); the stage never pauses, fails, reroutes or finishes.
85.1.18.1.9. Commands¶
- worker
Run as a persistent pepsi-dispatch(1) worker, reading message ids on standard input. This is how the dispatcher runs the stage in production.
85.1.18.1.10. Global Options¶
- -c FILE, –config FILE
Read the configuration from FILE instead of searching the default locations.
- -L LOGLEVEL, –log LOGLEVEL
Set the logging verbosity (default
info).- -v, –verbose
Show log messages from all sources.
- -h, –help; -V, –version
Print a usage summary / the version and exit.
85.1.18.1.11. Exit Status¶
- 0
The message was processed (advanced to NEXT_STAGE).
- 1
An error occurred (message not found or not
running, a misconfigured stage — e.g. a missing ALIASES or NEXT_STAGE — or a database error). The reason is written to the log. A missing alias file is not an error: it is treated as an empty map.
85.1.18.1.12. Examples¶
Reprocess message 42 through a one-off worker (it must be running):
echo 42 | pepsi-stage-aliases -c /etc/pepsi/pepsi.conf worker
A pipeline section placed just before local delivery, expanding recipients and forwarding to the local-delivery stage:
[stage-aliases]
PROGRAM = pepsi-stage-aliases
NEXT_STAGE = local
ALIASES = /etc/pepsi/aliases
85.1.18.1.13. See Also¶
pepsi-config(1), pepsi-stage-relay-to-maildir(1), pepsi-stage-if(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)
85.1.18.1.14. Bugs¶
Report bugs to the Pepsi issue tracker.