.. 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-smarthost ============================== *Relay through a configured upstream smarthost.* Role ==== ``pepsi-stage-relay-to-smarthost`` relays mail to a configured upstream MTA (smarthost) chosen by recipient domain, instead of contacting MX hosts directly. It is the other interchangeable delivery stage. Reference: :manpage:`pepsi-stage-relay-to-smarthost(1)`. Features ======== Smarthost routing ----------------- * Routes each recipient domain to the ``[…-mta-]`` whose ``DOMAINS`` lists it, or to the single ``CATCH_ALL`` MTA; a domain with no matching MTA is a permanent failure. A domain may be listed by only one MTA. The MTA sections are shared across all smarthost-relay stages. * No MX discovery and no DNS-learned MTA-STS — it speaks only to the configured smarthosts. Transport and authentication ---------------------------- * Per-MTA transport ``plain`` / ``tls`` (implicit) / ``starttls`` (RFC 3207, the default). * Certificate verification against the system store (plus an optional extra ``TLS_CA``), or disabled for testing; an optional client certificate (``TLS_CLIENT_CERT``/``TLS_CLIENT_KEY``). * **SMTP AUTH** (RFC 4954), per MTA: ``none``, ``plain``, ``login``, ``external``, ``cram-md5``, ``digest-md5``, ``scram-sha-1`` / ``scram-sha-256`` and their ``-plus`` channel-binding forms, ``ntlm``, ``gssapi``, ``oauth``, or ``auto`` to pick the strongest password mechanism the server offers. Most take ``USERNAME``/``PASSWORD``; ``gssapi`` takes ``SERVICE_NAME``/``KRB5CCNAME``, ``ntlm`` takes ``NT_DOMAIN``/``NT_WORKSTATION``, and ``oauth`` takes ``USERNAME``/``TOKEN_FILE``. * **DANE/TLSA** (RFC 7672) per MTA section: ``DANE = off | warn | strict``, default ``warn``. * ``HELO_NAME`` per MTA (defaults to ``SERVER_NAME``). Delivery, retry and bounce -------------------------- * Sends with the message's own envelope sender, 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 up to ``MAX_LIFETIME``; **loop detection** via ``MAX_HOP_COUNT``. * A permanent failure (including no matching MTA) routes to ``BOUNCE_STAGE`` (or marks ``failed``); a permanent failure of a **bounce** is discarded, never re-bounced. A rejected credential is a transient failure, never a bounce. DSN and content adaptation -------------------------- * Propagates ``RET``/``ENVID``/``NOTIFY``/``ORCPT`` to the smarthost only when it advertises ``DSN`` (RFC 3461); originates failure/success/delay reports under the same rules as the direct stage. * Per-hop ``8BITMIME``/``SMTPUTF8`` re-advertising or downgrade (RFC 6152 / RFC 6531 / RFC 2045 / RFC 2047). Configuration ============= ``[stage-]`` with ``PROGRAM = pepsi-stage-relay-to-smarthost``: ``SERVER_NAME`` *(required)*, ``NEXT_STAGE``/``BOUNCE_STAGE``, 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``, ``ADDRESS_FAMILY`` (the default every MTA entry inherits) and the DANE resolver settings ``DNS_SERVERS``/``DNS_TIMEOUT``. The upstream MTAs are defined in shared ``[pepsi-stage-relay-to-smarthost-mta-]`` sections: ``HOST``/``PORT`` *(both required)*, ``MODE``, ``TLS_VERIFY``/``TLS_CA``/``TLS_CLIENT_CERT``/ ``TLS_CLIENT_KEY``, ``AUTH`` with its credentials, ``DANE``, ``ADDRESS_FAMILY``, ``HELO_NAME``, and routing via ``DOMAINS`` / ``CATCH_ALL``. Full reference: :manpage:`pepsi-stage-relay-to-smarthost(1)`. Privilege ========= Installed **setgid** ``pepsi-token`` (mode ``2550``, owner ``pepsi:pepsi-token``), and therefore a standalone binary rather than one of the programs folded into the unified ``pepsi`` binary. The dispatcher runs the stage as the unprivileged ``pepsi`` user; the setgid bit gives the worker ``egid=pepsi-token``, which is what lets it read the group-restricted files it needs — the OAuth access tokens :doc:`pepsi-helper-token-refresh` writes (``AUTH = oauth``), a mutual-TLS ``TLS_CLIENT_KEY`` and a Kerberos credential cache (``AUTH = gssapi``) — without making ``pepsi`` a permanent member of that group. The file is not world-executable: the stage accepts ``-c``, so any local user able to run it could point it at a server of their own and send that server the credentials. State ===== Identical to :doc:`pepsi-stage-relay-to-internet`: * **Inputs:** ``state.dsn`` and ``state.origin``. * **Outputs:** ``attempts``/``last_error``/``delay_sent`` on pause; a ``state.bounce`` object when routing to/enqueuing for the bounce stage; ``last_error`` on terminal ``fail``. ``state.dsn``/``state.origin`` preserved. See also ======== :doc:`pepsi-stage-relay-to-internet`, :doc:`pepsi-stage-bounce`, :doc:`pepsi-helper-token-refresh`, :doc:`../features`, :manpage:`pepsi-stage-relay-to-smarthost(1)`.