.. This file is part of PEPSI. Copyright (C) 2026 Pepsi contributors 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-dot-forward ======================= *Process per-user ~/.forward files.* Role ==== ``pepsi-stage-dot-forward`` lets a local account owner redirect their own mail with a ``~/.forward`` file. For each envelope recipient that is *local* (the same ``LOCAL_DOMAINS`` / ``TARGETS`` / ``RECIPIENT_DELIMITER`` test as :doc:`pepsi-stage-relay-to-maildir`) it runs that user's ``~/.forward`` via the setuid-root :manpage:`pepsi-helper-dot-forward(1)` helper, which drops to the user first. Non-local recipients are left untouched. Normally placed just before local delivery. Reference: :manpage:`pepsi-stage-dot-forward(1)`. Features ======== Per-recipient outcomes ---------------------- * **No ~/.forward** — the recipient is a passthrough and advances to ``NEXT_STAGE`` (typically local delivery). * **Forwarded** — the recipient is replaced by the addresses the ``~/.forward`` named; those restart the pipeline at ``RESTART_STAGE`` (default ``init``) so they are re-authenticated and re-routed like fresh mail. An empty result (the message was consumed by a ``|pipe``/``/file`` directive) drops the recipient. * **Failed** — a failed ``~/.forward`` (pipe command error, file write error, or a disabled directive) routes the recipient to ``BOUNCE_STAGE``. A message with several recipients can mix these; the forwarded addresses, the per-recipient bounces and the kept recipients are reconciled in one database round-trip. ~/.forward directives --------------------- The helper acts on each non-empty, non-``#`` line as the user: a bare address (optional leading ``\``) becomes a forwarding address; ``|command`` pipes the message to a shell when ``ALLOW_PIPE`` is on; ``/absolute/path`` appends the message to a file when ``ALLOW_FILE`` is on. When both ``ALLOW_PIPE`` and ``ALLOW_FILE`` are off the message body is not even handed to the helper. Loop prevention --------------- Because forwarding restarts the pipeline, the stage records every processed login in the message ``state["dot-forwarders"]`` array (see :doc:`../state`). A recipient whose user is already listed is dropped without re-running its ``~/.forward``, so a forwarding cycle terminates. Privileges ========== The stage must be installed setgid ``pepsi-forward`` (mode ``2755``); that group membership is what lets the dispatcher's ``pepsi`` worker exec the ``4750 root:pepsi-forward`` helper, which alone runs the ``~/.forward`` as the target user and refuses to act for ``root``.