.. 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-bounce ================== *Rewrite a message into a delivery-status notification (DSN).* Role ==== ``pepsi-stage-bounce`` turns a message into an RFC 3464 DSN — a failure bounce, or (when requested) a positive or delay report. A delivery stage routes a failed/delivered message here via its ``BOUNCE_STAGE``. The DSN is produced *unsigned* and advanced to ``NEXT_STAGE`` (normally :doc:`pepsi-stage-dkim-sign`, then a delivery stage). References: :manpage:`pepsi-stage-bounce(1)` / :manpage:`pepsi.conf(5)`. Features ======== * **In-place rewrite into a DSN** (RFC 3464 ``multipart/report``): the envelope sender becomes the null sender ``<>``, the recipient becomes the original sender (``state.srs.original`` when :doc:`pepsi-stage-srs` recorded one, else the ``mail_from`` column), and the body quotes the original headers; RFC 3463 enhanced status codes are used. * **RET=FULL** (RFC 3461 §6.2): when the sender asked for the whole message back, the body is fetched — the one extra round-trip in the tree, made only for such a message — and returned in full, unless it exceeds ``RET_FULL_MAX_SIZE`` (default 256 KiB, ``0`` to disable the limit), in which case the DSN falls back to the headers alone, as §6.2 explicitly permits. * **Operator-supplied prose.** When ``BOUNCE_MESSAGE`` names a template, the human-readable part of the DSN is rendered from ``bounce-..body`` under ``[pepsi] TEMPLATE_DIR`` with the full row ``state``. ```` follows ``state.language`` in ``q`` order, falling back to ``en``: the notice goes to the original sender, and the language detected in their message is the best available proxy for what they read (with no detection on the path, the notice is English). Any render failure falls back to the built-in text, so a bounce is always produced. * **NOTIFY-aware** (RFC 3461): a **failure** report is emitted only when ``NOTIFY`` requested ``FAILURE`` (the default when absent) — ``NOTIFY=NEVER`` (or a list without ``FAILURE``) drops the message silently. * **Three report kinds**, selected by ``state.bounce.kind``: * ``permanent`` → ``Action: failed`` (the default failure bounce); * ``success`` → ``Action: delivered`` (only when a delivery stage originated it under ``ORIGINATE_SUCCESS_DSN`` + ``NOTIFY=SUCCESS``); * ``delay`` → ``Action: delayed`` (a relay stage's ``DELAY_DSN_AFTER`` warning). * **Echoes** the original ``ENVID``/``ORCPT`` into ``Original-Envelope-Id`` / ``Original-Recipient`` when present. * **Never bounces a bounce** (RFC 5321 §6.1): a null-sender message is deleted, not rewritten. * **No network I/O:** the rewritten message is delivered by whatever ``NEXT_STAGE`` names; the bounce is left unsigned for the DKIM-sign stage. Configuration ============= ``[stage-]``: ``PROGRAM = pepsi-stage-bounce``, ``SERVER_NAME`` *(required; used in ``From:``/``Reporting-MTA``/``Message-ID``)*, ``POSTMASTER`` (the bounce ``From:`` and DKIM identity; default ``postmaster@``), ``BOUNCE_MESSAGE`` (the template name, unset for the built-in prose), ``RET_FULL_MAX_SIZE`` (default 256 KiB) and ``NEXT_STAGE`` *(required; normally a DKIM-sign stage — the DSN is built unsigned, so without one every bounce fails after the DSN has already been composed)*. See :manpage:`pepsi.conf(5)`. State ===== * **Inputs:** ``state.srs.original`` (the DSN recipient, when present) and ``state.bounce`` — ``kind``, ``diagnostic``, ``failed_recipient``, the structured next-hop detail the relay stages record (``remote_mta``/``smtp_code``/``enhanced_status``/``phase``/``reply_text``, which also feeds the DSN ``Status:``), and the copied ``notify``/``orcpt``/``envid``/``ret`` (a hand-staged message with no ``state.bounce`` yields a generic failure notice). The header block is loaded; the body only for a ``RET=FULL`` bounce. * **Outputs:** clears ``state`` to null — the bounce is a new null-sender message that inherits none of the original's provenance. This is the **only** stage that does not preserve ``state``. See also ======== :doc:`pepsi-stage-dkim-sign`, :doc:`pepsi-stage-relay-to-internet`, :doc:`pepsi-stage-discard`, :doc:`../features`, :manpage:`pepsi-stage-bounce(1)`, :manpage:`pepsi.conf(5)`.