40. pepsi-stage-relay-to-maildir

Deliver to local users’ Maildirs; forward the rest.

40.1. Role

pepsi-stage-relay-to-maildir is the local-delivery stage. For each envelope recipient it decides whether the address is local and, if so, writes the message into that user’s Maildir/new/ via the setuid-root pepsi-helper-maildir-writer(1) helper; every other recipient is forwarded to NEXT_STAGE. Reference: pepsi-stage-relay-to-maildir(1).

40.2. Features

40.2.1. Local recipient matching

  • A recipient is local when its domain is in LOCAL_DOMAINS (default [pepsi-ingress] ACCEPTED_DOMAINS), its mailbox name resolves to a passwd entry, and that uid is permitted by TARGETS.

  • TARGETS is an allow-list of user names, uids, and uid ranges (alice, 452, 1000-1100, 10000-); it defaults to the regular (non-system) uid range from /etc/login.defs. The helper refuses any uid below UID_MIN regardless, so a system account listed here is bounced.

  • The mailbox name is the local-part with any RECIPIENT_DELIMITER sub-address (default +) stripped, lower-cased.

40.2.2. Partial delivery

  • Local recipients are written to their Maildirs; the remaining recipients are split onto a new pending row, and where depends on why they are not local. A recipient on somebody else’s domain is a forward and goes to NEXT_STAGE, which should reach the SRS relay tail. A recipient on one of our LOCAL_DOMAINS that resolves to no permitted account is an unknown mailbox and goes to UNKNOWN_MAILBOX_STAGE, which should reach a bounce — relaying it instead would look our own MX up, find this host, and post the message back to ourselves. UNKNOWN_MAILBOX_STAGE defaults to NEXT_STAGE.

  • Two addresses for the same local account are delivered only once.

  • Each local copy gets a Return-Path:, a Delivered-To: loop guard and a Received: trace header prepended.

40.2.3. Retry, bounce and DSN

  • The helper’s exit code decides whether retrying can help. A transient failure (a full disk, an I/O error, a helper not yet installed setuid) pauses that recipient with exponential backoff up to MAX_LIFETIME and only then routes it to BOUNCE_STAGE; a permanent one (the mailbox itself is unusable — wrong ownership or mode, no home, no such uid) is bounced at once, since no retry can deliver it. A bounce is never re-bounced, and the sender’s NOTIFY is honoured throughout.

  • An over-quota recipient (the helper’s own quota exit) is handled per [pepsi] MAILBOX_OVER_QUOTA: defer (the default) retries it like any transient failure, bounce routes it to QUOTA_LIMIT_STAGE with a 5.2.2 status. See pepsi-quota.

  • Originates a positive DSN on successful local delivery when [pepsi] ORIGINATE_SUCCESS_DSN is set and the recipient asked for NOTIFY=SUCCESS.

40.2.4. Privilege model

  • The stage binary is installed setgid pepsi-maildir, mode 2550 pepsi:pepsi-maildir. The dispatcher runs it as the unprivileged pepsi user; the setgid bit grants the effective gid needed to exec the group-restricted helper — and nothing else on the host gains that ability. That last clause is what the mode buys: at 2755 every local user could exec the stage and inherit the same gid, and from there the setuid-root helper. pepsi cannot take the exec right from the group (it is deliberately not a member), so it takes it from the owner bits instead.

40.3. Configuration

[stage-<name>] with PROGRAM = pepsi-stage-relay-to-maildir: SERVER_NAME (required), TARGETS, LOCAL_DOMAINS, RECIPIENT_DELIMITER, HELPER (default pepsi-helper-maildir-writer), NEXT_STAGE/BOUNCE_STAGE, UNKNOWN_MAILBOX_STAGE, QUOTA_LIMIT_STAGE and the retry policy (RETRY_INITIAL/RETRY_MAX_INTERVAL/RETRY_FACTOR/MAX_LIFETIME). pepsi-setup checks that UNKNOWN_MAILBOX_STAGE and QUOTA_LIMIT_STAGE name real stages. Full reference: pepsi-stage-relay-to-maildir(1).

40.4. State

  • Inputs: state.dsn (per-recipient NOTIFY/ORCPT) and state.attempts (the retry count).

  • Outputs: attempts/last_error on pause; a state.bounce object on the rows enqueued for the bounce stage; the per-recipient state.dsn is sliced onto each split row. state.dsn/state.origin are preserved.

40.5. See also

pepsi-stage-relay-to-lmtp (the LMTP alternative), pepsi-stage-relay-to-smarthost, pepsi-stage-relay-to-internet, pepsi-stage-bounce, pepsi-quota, Supported Features, pepsi-stage-relay-to-maildir(1), pepsi-helper-maildir-writer(1).