36. pepsi-stage-relay-to-lmtp

Deliver locally over LMTP to an MDA (Dovecot) that runs Sieve.

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

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

36.3. 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).