.. 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-relay-to-lmtp ========================= *Deliver locally over LMTP to an MDA (Dovecot) that runs Sieve.* Role ==== ``pepsi-stage-relay-to-lmtp`` is a local-delivery stage that hands each message to a Mail Delivery Agent — typically **Dovecot** — over **LMTP** (RFC 2033). The MDA files the message and, in doing so, runs the recipient's **Sieve** (RFC 5228) script, so server-side filtering is delegated to the MDA instead of being implemented in Pepsi. It is an alternative to ``pepsi-stage-relay-to-maildir``: LMTP gains Sieve and a clean per-recipient delivery status, and needs **no** setuid helper (the MDA performs the per-user delivery), at the cost of running a local IMAP/LMTP server. LMTP-native delivery, deliver-and-route ======================================= All envelope recipients are offered in one LMTP transaction; the MDA returns one reply per recipient after end-of-DATA (RFC 2033 §4.2). The stage **never builds a delivery-status notification itself** — it delivers, and otherwise *routes* each recipient onward by reason, recording why under ``state.bounce`` for a downstream **pepsi-stage-bounce** (or a relay) to act on: * ``2xx`` — delivered; a ``NOTIFY=SUCCESS`` notification (and ``DELAY`` warnings) is routed to the optional ``NOTIFY_STAGE``; * a permanent reject is routed by its RFC 3463 enhanced status — a bad mailbox (``x.1.x`` / bare ``550``) to ``NEXT_STAGE``, over-quota (``x.2.2``) to ``QUOTA_LIMIT_STAGE`` (else ``NEXT_STAGE``), a Sieve / policy reject (``x.7.x``) to ``SIEVE_REJECT_STAGE`` (else ``NEXT_STAGE``), anything else to ``NEXT_STAGE``; * ``4xx`` — transient: retry that recipient (exponential backoff) until ``MAX_LIFETIME``, then route by the same classification. Delivered, routed and still-deferred recipients are reconciled in one fan-out: the delivered recipients leave the row, each routed recipient becomes a sibling ``pending`` row sliced to itself (so a relay target never re-delivers to the others) at its target stage, and the row is reduced to the deferred recipients for the next retry. Because the MDA is the authority on which addresses are local, the stage does no locality check of its own — place it after alias expansion so only intended-local recipients reach it. ``NEXT_STAGE`` is **mandatory** (set it to a **pepsi-stage-bounce** to bounce, or to a relay stage to forward off-site); a message reaching the stage without one is marked ``failed``. Transport ========= The target is a UNIX-domain socket (``SOCKET``, the common Dovecot layout: no TLS, no credentials) or TCP (``HOST``/``PORT``, ``PORT`` default 24) with optional ``TLS = off|starttls|tls`` and ``AUTH = none|plain|login|external``. Authentication is refused over cleartext, so any ``AUTH`` other than ``none`` requires TLS. The shared LMTP client reuses the SMTP client's transport, TLS and SASL machinery (``pepsi_common::smtp::deliver_lmtp``). Configuration is documented in **pepsi.conf**\ (5); the manual page is **pepsi-stage-relay-to-lmtp**\ (1).