.. This file is part of PEPSI. Copyright (C) 2026 GNUnet e.V. PEPSI is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. =================== pepsi-stage-aliases =================== *Expand envelope recipients through an alias / mailing-list map.* Role ==== ``pepsi-stage-aliases`` rewrites a message's envelope recipients through a mapping file before delivery: 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 list is de-duplicated so each address is delivered to at most once, and the message advances to ``NEXT_STAGE``. It is the classic ``/etc/aliases`` / virtual-domain expansion step, and is normally placed just before local delivery. It loads only the envelope and ``state`` — never the headers or body — and never pauses, fails or finishes a message. Reference: :manpage:`pepsi-stage-aliases(1)`. Features ======== * **Postfix-style map file.** ``ALIASES`` names a human-readable file parsed like a Postfix :manpage:`virtual(5)` table: each non-blank line maps one *key* — a full address, an ``@domain`` catch-all, or a ``*``-glob such as ``sales-*@example.org`` — to one or more comma/whitespace-separated target addresses (kept verbatim; targets may not themselves contain a wildcard). A key with no targets is ignored, so a recipient is never silently deleted. * **Most-specific match wins.** A recipient is lower-cased and looked up verbatim; on a miss the ``@domain`` catch-all is tried, then the most specific matching ``*`` wildcard (a narrow ``sales-*@example.org`` beats a broad ``*@example.org`` beats a bare ``*``). Sub-address (``+tag``) detail is **not** stripped, so a specific list address can be aliased on its own. * **Transitive expansion with loop breaking.** When a target is itself a key it is expanded in turn, so nested distribution lists resolve to their leaf addresses; a cycle is broken by resolving the repeated key to its literal address rather than recursing forever. * **Cached, fail-soft.** The map is read into a process-global cache and re-parsed only when the file's identity (modification time, size or inode) changes, so a busy worker does not re-read it per message. A missing or unreadable file is treated as an empty map (and logged), so a momentary misconfiguration does not fail mail. ``pepsi-setup`` syntax-checks the file at install time when it exists. Delivery Status Notifications ============================= ``state.dsn.rcpt`` runs 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 with any ``SUCCESS`` removed (a ``NOTIFY`` that was only ``SUCCESS`` becomes ``NEVER``), so one submission to an alias does not draw one positive DSN per member; following RFC 3461 §5.2.7 it also carries an ``ORCPT`` pointing at that original recipient (its existing ``ORCPT`` if any, otherwise ``rfc822;``). An unexpanded recipient keeps its DSN entry, and message-level ``RET``/``ENVID`` and every other ``state`` key are preserved. Configuration ============= ``[stage-]``: ``PROGRAM = pepsi-stage-aliases``, the ``ALIASES`` map-file path, and the ``NEXT_STAGE`` the expanded message advances to. ``pepsi-setup`` creates a starter ``ALIASES`` template when the file is missing and syntax-checks it when present. See :manpage:`pepsi-stage-aliases(1)` and :doc:`../configuration`. State ===== * **Inputs:** the envelope ``rcpt_to`` and the parallel ``state.dsn.rcpt``. * **Outputs:** a rewritten ``rcpt_to`` and matching ``state.dsn.rcpt`` (only when an alias applied or a duplicate was removed); no other ``state`` is touched. * **Transitions:** advance to ``NEXT_STAGE`` (the only transition). See also ======== :doc:`pepsi-stage-relay-to-maildir`, :doc:`pepsi-stage-relay-to-lmtp`, :doc:`pepsi-stage-if`, :doc:`../features`, :manpage:`pepsi-stage-aliases(1)`.