70.1.25. pepsi-stage-edit-settings

change per-address settings from a control e-mail

Manual section:

1

70.1.25.1.1. Name

pepsi-stage-edit-settings - the settings-by-e-mail stage of the Pepsi pipeline.

70.1.25.1.2. Synopsis

pepsi-stage-edit-settings [GLOBAL-OPTIONS] worker

70.1.25.1.3. Description

pepsi-stage-edit-settings is a stage program run by pepsi-dispatch(1) as a persistent worker reading message ids on standard input. It loads that pepsi.ingress row (refusing to act unless its status is running), reads its [stage-<stage>] section, and decides whether the message is a settings-control message an account owner sent to change their own per-address settings (the pepsi.settings overrides described in pepsi-settings(1)).

A message is a control message only when all of these hold:

  • it is locally originated (state.local_origin is true);

  • its Subject: is exactly SUBJECT (default Pepsi); and

  • one of its envelope recipients is <CONTROL_LOCAL_PART>@<domain> (default local part pepsi) for a domain the instance accepts ([pepsi-ingress] ACCEPTED_DOMAINS).

Any other message is advanced unchanged to NEXT_STAGE, so the stage is safe to place anywhere on the local-submission path.

Deciding whether a message is a control message — locally originated, the right Subject, addressed to the control local part at an accepted domain — needs only the message metadata, never the body. This stage therefore takes part in stage fusion (see pepsi-dispatch(1)) with a data-dependent gate: it defaults to FUSION = yes and a predecessor fuses it in-process for every non-control message (which it just advances), but declines fusion for a genuine control message, which is then committed and dispatched as its own worker so the full body is loaded for parsing. The optimisation is thus free for the common case and never skips the body when it is actually needed; set FUSION = no to opt out.

The address whose settings are edited is the envelope sender — the owner edits their own settings, and the reply is mailed back to them. (The operator’s submission authentication must therefore bind the envelope sender; otherwise an authenticated user could edit another address’s settings.)

70.1.25.1.4. The body

The message body is read as a lenient INI snippet: [stage-<name>] section headers and OPTION = value assignments. Blank lines, comments (#/%/;), a leading greeting, and a trailing signature (a -- line) are ignored, so an ordinary e-mail containing the configuration works. Each assignment adds or overrides the stored override for that stage’s option; an assignment whose value is empty (OPTION =) removes the override, reverting the option to its INI default.

Only sections whose stage name appears in EDITABLE_STAGES may be changed; a body addressing any other section is rejected.

For safety, an assignment that sets a stage’s PROGRAM is only accepted when its value is a pepsi-stage-* command (with no path component), so an account owner cannot redirect a stage at an arbitrary executable. Setting UNRESTRICTED_UNSAFE_STAGES = YES in the stage’s configuration lifts this restriction (unsafe; the default is NO).

The resulting combined settings — the INI defaults, plus the address’s existing overrides, plus the new assignments — are validated by running each affected stage’s own configuration parser. If anything is invalid, no change is made and a human-readable reply explains every problem. If everything is valid, the merged overrides are stored and a reply quotes the full effective option set (defaults plus overrides) of every editable stage, in INI syntax.

Either reply carries Subject: SUBJECT, the null envelope sender <> (RFC 3834, so it is never itself gated or bounced), and is injected at RESPONSE_STAGE (where it is DKIM-signed and relayed like any outbound mail). The control message itself is then removed.

The framing prose of both replies is localised: it is rendered from the operator-customizable edit-settings.<lang>.body Mustache template under [pepsi] TEMPLATE_DIR, choosing <lang> from the sender’s detected language(s) (the state.language Accept-Language string set by pepsi-stage-detect-language) and always falling back to English (edit-settings.en.body). The template’s {{#success}} / {{^success}} branches frame, respectively, the effective-settings echo and the problem list.

This stage loads the message body but does not modify it.

70.1.25.1.5. Configuration

Options live in the stage’s own [stage-<name>] section (PROGRAM = pepsi-stage-edit-settings): the EDITABLE_STAGES allowlist, the RESPONSE_STAGE the reply is injected at, a NEXT_STAGE for ordinary mail, the SUBJECT/CONTROL_LOCAL_PART/RESPONSE_FROM control parameters, and the UNRESTRICTED_UNSAFE_STAGES safety switch. They are documented in pepsi.conf(5).

70.1.25.1.6. State

Inputs: state.local_origin (gates whether the message is a control message), and the envelope sender/recipients and Subject: header.

Outputs: the stage rewrites the pepsi.settings row of the envelope sender and injects a reply; it does not modify the state of the original message (which it removes). The state layout is described in pepsi.state(7).

Transitions:

  • an ordinary message (not locally originated, or not matching SUBJECT / CONTROL_LOCAL_PART) → advance to NEXT_STAGE unchanged;

  • a control message → inject the reply (the INI echo on success, or the error on a rejected/invalid edit) at RESPONSE_STAGE and finish (the original row is deleted).

The stage never pauses, fails or reroutes.

70.1.25.1.7. Commands

worker

Run as a persistent pepsi-dispatch(1) worker, reading message ids on standard input.

70.1.25.1.8. Global Options

-c FILE, –config FILE

Read the configuration from FILE instead of searching the default locations.

-L LOGLEVEL, –log LOGLEVEL

Set the logging verbosity (default info).

-v, –verbose

Show log messages from all sources.

-h, –help; -V, –version

Print a usage summary / the version and exit.

70.1.25.1.9. Exit Status

0

The message was processed (passed through, or applied/rejected with a reply).

1

An error occurred (message not found or not running, misconfigured stage, or a database error). The reason is written to the log.

70.1.25.1.10. Examples

A pipeline section that lets owners edit their whitelist and language policy, replying via the outbound path:

[stage-edit-settings]
PROGRAM = pepsi-stage-edit-settings
EDITABLE_STAGES = check-whitelist, block-language
RESPONSE_STAGE = dkim-sign
NEXT_STAGE = srs

A control e-mail body (Subject: Pepsi, To: pepsi@example.org) that sets a whitelist and clears a language blacklist:

[stage-check-whitelist]
WHITELIST_NAME = my-contacts

[stage-block-language]
BLACKLIST =

70.1.25.1.11. See Also

pepsi-settings(1), pepsi-config(1), pepsi-dispatch(1), pepsi-stage-check-whitelist(1), pepsi-stage-block-language(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)

70.1.25.1.12. Bugs

Report bugs to the Pepsi issue tracker.