.. 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-internet ============================= *Direct-to-MX delivery with MTA-STS.* Role ==== ``pepsi-stage-relay-to-internet`` delivers a message directly to the recipient domain's mail exchangers, doing its own MX discovery and TLS policy enforcement. It is one of the two interchangeable delivery stages. Reference: :manpage:`pepsi-stage-relay-to-internet(1)`. Features ======== MX discovery (RFC 5321 / RFC 7505) ---------------------------------- * Own ``MX`` lookup, hosts tried in ascending preference (equal preference in random order); a domain with no ``MX`` falls back to its address records (implicit MX, RFC 5321 §5.1). * **Null MX** (RFC 7505, ``0 .``) and a non-existent domain are permanent failures, never retries. * **Happy-Eyeballs** address selection across A/AAAA, intersected with ``ADDRESS_FAMILY``; resolved addresses are cached per address (with connect health) in the ``pepsi.dns_address`` table, so a working address is preferred until its DNS TTL elapses. Transport security (RFC 8461 / RFC 6125) ---------------------------------------- * **MTA-STS** (RFC 8461) discovery and enforcement (unless ``MTA_STS = no``): an ``enforce`` policy restricts delivery to listed MX hosts over ``STARTTLS`` with a certificate that validates for the host (RFC 6125). A ``testing`` policy is validated the same way and the outcome recorded for TLS Reporting, but a failure falls back to opportunistic ``STARTTLS`` over all MX hosts; with no policy, delivery uses opportunistic ``STARTTLS``. Policy lookups fail open only when nothing is cached. The ``mta-sts`` subcommand prints the applicable policy. * **DANE/TLSA** (RFC 7672), per MX host: ``DANE = off | warn | strict``, default ``warn``. When usable TLSA records exist and the MX RRset is DNSSEC-secure (Pepsi reads the resolver's AD bit; it does not validate DNSSEC itself) they take precedence over MTA-STS for that connection — except that ``warn`` mode never replaces an ``enforce`` MTA-STS policy's PKIX validation. A usable-record mismatch defers delivery under ``strict`` and only warns under ``warn``. A host whose ``TLSA`` records are all unusable must still offer ``STARTTLS`` (RFC 7672 §2.2). Delivery, retry and bounce -------------------------- * Sends with the message's own envelope sender (null sender for bounces), one recipient per attempt: a multi-recipient row is first split into one row per recipient. * On success, finishes the row (or advances to ``NEXT_STAGE``). * **Exponential backoff** on transient failure (``RETRY_INITIAL``/``RETRY_MAX_INTERVAL``/``RETRY_FACTOR``); past ``MAX_LIFETIME`` a transient failure becomes permanent. * **Loop detection** via ``MAX_HOP_COUNT`` ``Received:`` headers. * A permanent failure of an ordinary message routes to ``BOUNCE_STAGE`` (or marks the row ``failed``); a permanent failure of a **bounce** is never re-bounced — a copy goes to ``POSTMASTER`` if set, else it is discarded. DSN propagation and origination (RFC 3461) ------------------------------------------ * Propagates ``RET``/``ENVID``/``NOTIFY``/``ORCPT`` to the MX **only** when it advertises ``DSN``. * On permanent failure, hands the recipient's ``NOTIFY``/``ORCPT``/``ENVID`` to the bounce stage so a failure DSN is generated only when requested. * **Success DSN** (``Action: delivered``) when ``ORIGINATE_SUCCESS_DSN`` + ``NOTIFY=SUCCESS``; **delay DSN** (``Action: delayed``, once) when ``DELAY_DSN_AFTER`` elapses and ``NOTIFY=DELAY``. Content adaptation (RFC 6152 / RFC 6531) ---------------------------------------- * Matches the message to the extensions the MX advertises: re-advertises ``BODY=8BITMIME`` / ``SMTPUTF8`` when supported, otherwise downgrades the body (RFC 2045) and UTF-8 headers (RFC 2047). A non-ASCII address that cannot be represented to a non-``SMTPUTF8`` hop is bounced, and so is a body that is still 8-bit after the downgrade — RFC 6152 §3 permits no attempt to send it. Configuration ============= ``[stage-]`` with ``PROGRAM = pepsi-stage-relay-to-internet``: ``SERVER_NAME`` *(required)*, ``NEXT_STAGE``/``BOUNCE_STAGE``, ``POSTMASTER``, the timeouts (``CONNECT_TIMEOUT``/``COMMAND_TIMEOUT``/``DATA_TIMEOUT``), the retry policy (``RETRY_INITIAL``/``RETRY_MAX_INTERVAL``/``RETRY_FACTOR``/``MAX_LIFETIME``/ ``DELAY_DSN_AFTER``), ``MAX_HOP_COUNT``, DNS (``DNS_SERVERS``/``DNS_TIMEOUT``), MTA-STS (``MTA_STS``/``MTA_STS_TIMEOUT``), ``DANE`` and ``ADDRESS_FAMILY``. Durations must use ``h``/``m``/``s`` units. Full reference: :manpage:`pepsi-stage-relay-to-internet(1)`. State ===== * **Inputs:** ``state.dsn`` (propagation + report gating) and ``state.origin`` (8BITMIME/SMTPUTF8 hints). * **Outputs:** ``attempts``/``last_error``/``delay_sent`` on pause; a ``state.bounce`` object (``permanent``/``success``/``delay``) when routing to or enqueuing for the bounce stage; ``last_error`` on terminal ``fail``. ``state.dsn`` and ``state.origin`` are preserved. See also ======== :doc:`pepsi-stage-relay-to-smarthost`, :doc:`pepsi-stage-bounce`, :doc:`../features`, :manpage:`pepsi-stage-relay-to-internet(1)`.