.. 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-relay-to-maildir ============================ *Deliver to local users' Maildirs; forward the rest.* Role ==== ``pepsi-stage-relay-to-maildir`` is the local-delivery stage. For each envelope recipient it decides whether the address is *local* and, if so, writes the message into that user's ``Maildir/new/`` via the setuid-root :manpage:`pepsi-helper-maildir-writer(1)` helper; every other recipient is forwarded to ``NEXT_STAGE``. Reference: :manpage:`pepsi-stage-relay-to-maildir(1)`. Features ======== Local recipient matching ------------------------ * A recipient is local when its domain is in ``LOCAL_DOMAINS`` (default ``[pepsi-ingress] ACCEPTED_DOMAINS``), its mailbox name resolves to a passwd entry, and that uid is permitted by ``TARGETS``. * ``TARGETS`` is an allow-list of user names, uids, and uid ranges (``alice``, ``452``, ``1000-1100``, ``10000-``); it defaults to the regular (non-system) uid range from ``/etc/login.defs``. The helper refuses any uid below ``UID_MIN`` regardless, so a system account listed here is bounced. * The mailbox name is the local-part with any ``RECIPIENT_DELIMITER`` sub-address (default ``+``) stripped, lower-cased. Partial delivery ---------------- * Local recipients are written to their Maildirs; the remaining recipients are split onto a new ``pending`` row, and *where* depends on why they are not local. A recipient on somebody else's domain is a **forward** and goes to ``NEXT_STAGE``, which should reach the SRS relay tail. A recipient on one of *our* ``LOCAL_DOMAINS`` that resolves to no permitted account is an **unknown mailbox** and goes to ``UNKNOWN_MAILBOX_STAGE``, which should reach a bounce — relaying it instead would look our own MX up, find this host, and post the message back to ourselves. ``UNKNOWN_MAILBOX_STAGE`` defaults to ``NEXT_STAGE``. * Two addresses for the same local account are delivered only once. * Each local copy gets a ``Return-Path:``, a ``Delivered-To:`` loop guard and a ``Received:`` trace header prepended. Retry, bounce and DSN --------------------- * The helper's exit code decides whether retrying can help. A **transient** failure (a full disk, an I/O error, a helper not yet installed setuid) pauses that recipient with **exponential backoff** up to ``MAX_LIFETIME`` and only then routes it to ``BOUNCE_STAGE``; a **permanent** one (the mailbox itself is unusable — wrong ownership or mode, no home, no such uid) is bounced at once, since no retry can deliver it. A bounce is never re-bounced, and the sender's ``NOTIFY`` is honoured throughout. * An **over-quota** recipient (the helper's own quota exit) is handled per ``[pepsi] MAILBOX_OVER_QUOTA``: ``defer`` (the default) retries it like any transient failure, ``bounce`` routes it to ``QUOTA_LIMIT_STAGE`` with a ``5.2.2`` status. See :doc:`pepsi-quota`. * Originates a positive DSN on successful local delivery when ``[pepsi] ORIGINATE_SUCCESS_DSN`` is set and the recipient asked for ``NOTIFY=SUCCESS``. Privilege model --------------- * The stage binary is installed **setgid** ``pepsi-maildir``, mode ``2550`` ``pepsi:pepsi-maildir``. The dispatcher runs it as the unprivileged ``pepsi`` user; the setgid bit grants the effective gid needed to exec the group-restricted helper — and nothing else on the host gains that ability. That last clause is what the mode buys: at ``2755`` every local user could exec the stage and inherit the same gid, and from there the setuid-root helper. ``pepsi`` cannot take the exec right from the group (it is deliberately not a member), so it takes it from the owner bits instead. Configuration ============= ``[stage-]`` with ``PROGRAM = pepsi-stage-relay-to-maildir``: ``SERVER_NAME`` *(required)*, ``TARGETS``, ``LOCAL_DOMAINS``, ``RECIPIENT_DELIMITER``, ``HELPER`` (default ``pepsi-helper-maildir-writer``), ``NEXT_STAGE``/``BOUNCE_STAGE``, ``UNKNOWN_MAILBOX_STAGE``, ``QUOTA_LIMIT_STAGE`` and the retry policy (``RETRY_INITIAL``/``RETRY_MAX_INTERVAL``/``RETRY_FACTOR``/``MAX_LIFETIME``). ``pepsi-setup`` checks that ``UNKNOWN_MAILBOX_STAGE`` and ``QUOTA_LIMIT_STAGE`` name real stages. Full reference: :manpage:`pepsi-stage-relay-to-maildir(1)`. State ===== * **Inputs:** ``state.dsn`` (per-recipient ``NOTIFY``/``ORCPT``) and ``state.attempts`` (the retry count). * **Outputs:** ``attempts``/``last_error`` on pause; a ``state.bounce`` object on the rows enqueued for the bounce stage; the per-recipient ``state.dsn`` is sliced onto each split row. ``state.dsn``/``state.origin`` are preserved. See also ======== :doc:`pepsi-stage-relay-to-lmtp` (the LMTP alternative), :doc:`pepsi-stage-relay-to-smarthost`, :doc:`pepsi-stage-relay-to-internet`, :doc:`pepsi-stage-bounce`, :doc:`pepsi-quota`, :doc:`../features`, :manpage:`pepsi-stage-relay-to-maildir(1)`, :manpage:`pepsi-helper-maildir-writer(1)`.