36. pepsi-stage-bounce

Rewrite a message into a delivery-status notification (DSN).

36.1. 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 pepsi-stage-dkim-sign, then a delivery stage). References: pepsi-stage-bounce(1) / pepsi.conf(5).

36.2. 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 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-<NAME>.<lang>.body under [pepsi] TEMPLATE_DIR with the full row state. <lang> 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.

36.3. Configuration

[stage-<name>]: PROGRAM = pepsi-stage-bounce, SERVER_NAME (required; used in ``From:``/``Reporting-MTA``/``Message-ID``), POSTMASTER (the bounce From: and DKIM identity; default postmaster@<SERVER_NAME>), 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 pepsi.conf(5).

36.4. 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.

36.5. See also

pepsi-stage-dkim-sign, pepsi-stage-relay-to-internet, pepsi-stage-discard, Supported Features, pepsi-stage-bounce(1), pepsi.conf(5).