5. The Wizard¶
pepsi-setup --wizard runs a short interview and writes a complete,
already-validated pepsi.conf. It is the intended way to produce a first
configuration: the next chapter, Configuration, explains the file the
wizard writes, and this one explains how the answers become that file.
The point of the interview is not to save typing. It is that the stage
pipeline is assembled from the answers — which stages exist, and how their
NEXT_STAGE and BOUNCE_STAGE options wire together, follows
mechanically from the direction the host serves and the features that were
switched on. There is no menu of pipelines to pick from and no template being
filled in; the graph is computed. So the useful way to understand the wizard is
to look at the three pipelines it can build, and then at which question inserts
or removes each stage in them.
Note
This chapter describes what the answers do. The operational detail of the command — every flag, the MTA migration, the readline bindings, the secret-prompt behaviour, the answer-file format — is in pepsi-setup(1), which this chapter cross-references rather than repeats.
5.1. How a run proceeds¶
Import. On a host with no
pepsi.confyet, the wizard detects an existing Postfix or sendmail and offers to read its settings in as the interview’s defaults. Nothing is adopted silently — every imported value is still shown at its own prompt. On a re-run, the[pepsi-wizard]section of the existing file supplies the defaults instead.Interview. The questions below, grouped into numbered steps. Each answer is validated as it is entered, so a malformed domain or port is caught at its own prompt.
Render. The answers are turned into a configuration file — this is where the pipeline is assembled.
Validate. The rendered text is loaded and validated through the very same path
pepsi-setup runuses. If it fails, the wizard prints the fault and walks back through the questions with the previous answers pre-filled, so correcting one option is a press-Enter walk past the rest.Write. The file is written, and the secrets in it (the SRS HMAC key, the smarthost and LMTP passwords, the merchant and
/resumetokens) are moved out into mode-restrictedsecrets.d/*.secretfragments referenced by@inline-secret@directives. What was written is then re-loaded and re-validated, because moving the secrets rewrote it.Offer to run setup. Installing the schema, generating DKIM keys, provisioning TLS certificates and printing the DNS records to publish are
pepsi-setup run’s job, not the interview’s. The wizard offers to chain straight into it.
The same interview is also asked by the browser setup console (see The administration console), described next.
5.2. The same interview in a browser¶
There is no second interview. Every question, its shape, its default, its help
text and the conditions under which it is asked live in one place as data
(pepsi_setup_model::questions), and both front-ends render that model — so a
question cannot be added to one and not the other, and a test asserts the two
identifier sets are equal. What differs is only the presentation: the terminal
asks one question at a time, the console shows a step per page.
The first step. Each field carries the same help the terminal prints, and
— where the answer maps to exactly one option — the [section] OPTION
it will end up in, so the same knob can be found in the file afterwards.
The strip along the top is the whole interview, with the steps that have
been answered marked.¶
The branching is the model’s too, so the console hides what the terminal would not ask. Below, switching language blocking on has revealed the policy, threshold and enforcement fields — and has removed the localize bounce messages question, because blocking already implies detection and the terminal only asks that one when blocking is off:
Content filtering, with blocking switched on.¶
Two things about the console are worth knowing before using it, and both are deliberate:
Answers are drafts. Each step is staged in the database, not written to
/etc; nothing takes effect until the interview is applied. A session that times out half way through has not half-configured a mail server.The console asks; it does not act. It runs unprivileged and cannot write
pepsi.conf, run certbot or install the schema. A save records a request that the separately-started, root-runningpepsi-setup applyvalidates and performs. On a host where that privileged half is not installed — it is its own Debian package — the setup pages render read-only, showing every value with the controls disabled and the reason beside them, rather than accepting answers into a queue nothing drains.
The screenshots above are generated from the shipping templates and stylesheet
by contrib/screenshot-setup.sh, so they can be brought back into agreement
with the code rather than drifting from it.
5.3. The first question decides the shape¶
Before any step banner, the wizard asks:
Mail direction this host serves [both]: inbound | outbound | both
Everything else follows from it. inbound means this host receives mail for
your domains from the Internet; outbound means it relays what your own
users and local programs submit; both — the default — means it does each,
and the two flows are separated at the first stage. The answer decides which
SMTP listeners are written, which of the later steps are asked at all, and
which of the three pipelines below is built.
5.3.1. Pipeline: both¶
The entry stage is a branch on state.local_origin — the flag
pepsi-ingress sets for an authenticated submission — so a message this host
received and a message our own user sent never share a stage. That
separation is not cosmetic: ARC exists to carry an upstream administrative
domain’s authentication verdicts across our forwarding hop, and sealing our own
users’ submissions would publish their SPF/DKIM/DMARC results to the world.
pepsi-ingress
Internet ──▶ :25 :465 / :587 ◀── your users
│ │ (and the local sendmail
└────────┬────────┘ socket, always served)
▼
init pepsi-stage-if on
│ state.local_origin
┌──────────────┴────────┐
false │ │ true (our own submissions)
▼ ▼
the received branch wallet WALLET_SELF_SERVICE
(second panel below) │
▼
edit-settings EDIT_SETTINGS
│
▼
auto-whitelist LEARN_WHITELIST
or ANTI_SPAM
│
▼
encrypt CRYPTO
│
▼
milter-* imported
non_smtpd_milters
│
▼
dkim-sign (always)
│
▼
internet (always)
And the received branch, which is where nearly every feature lives:
(the false branch of the split above)
│
▼
init pepsi-stage-arc
│
▼
decrypt CRYPTO
│
▼
detect-language LANGUAGE_BLOCKING
or I18N_BOUNCES
│
▼
block-language LANGUAGE_BLOCKING
│
▼
milter-* MILTER_* (one per filter found)
│
▼
check-whitelist ANTI_SPAM
│
▼
anti-spam ANTI_SPAM
│
▼
autocrypt-learn AUTOCRYPT_LEARN
│
▼
aliases ALIASES_ENABLED
│
▼
vacation VACATION
│
▼
route ──▶ exchange EXCHANGE (our own domains)
│
▼
dot-forward DOT_FORWARD
│
▼
local LOCAL_METHODS (maildir)
│
▼
local-lmtp LOCAL_METHODS (lmtp)
│
▼
srs (always)
│
▼
dkim-sign-relay SIGN_RELAYED
│
▼
smarthost SMARTHOST_HOST
(else straight to internet)
│
▼
internet (always)
Reading the figures: a stage with (always) is unconditional for this
direction, and every other stage is present exactly when the answer beside it
says so. The stages are strung together in the order shown, each one’s
NEXT_STAGE pointing at the next one that survived — so switching a feature
off does not leave a gap, it shortens the chain.
Two structural facts are worth naming, because they are the reason for the order rather than consequences of it:
decryptis first on the received branch andencryptis last before signing on the submitted one. Everything downstream ofdecrypttherefore sees cleartext (language detection, the whitelist, the paywall), and DKIM signs the bytes that actually go on the wire.srsand the relay destination after it are unconditional on the received branch. Recipients local delivery did not consume are not errors — an alias expanding off-site, a~/.forwardat another provider, or (with no local delivery configured at all) the entire pure-relay path. They leave as a forward, which is why the envelope sender is SRS-rewritten first.
5.3.2. Pipeline: inbound¶
With no submission path there is nothing to branch on, so the if stage
disappears and ARC becomes the entry stage itself. The received branch is
otherwise identical to the one above, minus the questions that were never
asked: no encrypt, no auto-whitelist, no wallet or
edit-settings.
Internet ──▶ pepsi-ingress :25
│
▼
init pepsi-stage-arc (the entry stage)
│
▼
decrypt CRYPTO
│
▼
detect-language LANGUAGE_BLOCKING
or I18N_BOUNCES
│
▼
block-language LANGUAGE_BLOCKING
│
▼
milter-* MILTER_* (one per filter found)
│
▼
check-whitelist ANTI_SPAM
│
▼
anti-spam ANTI_SPAM
│
▼
autocrypt-learn AUTOCRYPT_LEARN
│
▼
aliases ALIASES_ENABLED
│
▼
vacation VACATION
│
▼
route ──▶ exchange EXCHANGE (our own domains)
│
▼
dot-forward DOT_FORWARD
│
▼
local LOCAL_METHODS (maildir)
│
▼
local-lmtp LOCAL_METHODS (lmtp)
│
▼
srs (always)
│
▼
dkim-sign-relay SIGN_RELAYED
│
▼
smarthost SMARTHOST_HOST
(else straight to internet)
│
▼
internet (always)
dkim-sign and internet are still written even though no submission
reaches them: they are the tail every bounce goes down (see
The shared tail and the bounces), and internet is also the relay destination when no
smarthost was configured.
5.3.3. Pipeline: outbound¶
Only the submission branch is built. The if stage is still emitted, because
pepsi-ingress still sets state.local_origin and a message without it
must go somewhere — but on a submission-only host such a message cannot
normally occur, so that branch falls straight through to the signing tail
rather than into an inbound chain that does not exist.
your users ──▶ pepsi-ingress :465 / :587
(and the local sendmail socket, always served)
│
▼
init pepsi-stage-if on
│ state.local_origin
┌────────┴────────┐
false │ │ true
│ ▼
│ wallet WALLET_SELF_SERVICE
│ │
│ ▼
│ edit-settings EDIT_SETTINGS
│ │
│ ▼
│ encrypt CRYPTO
│ │
│ ▼
│ milter-* imported non_smtpd_milters
│ │
└────────┬────────┘
▼
dkim-sign (always)
│
▼
internet (always)
Note what is not here. auto-whitelist is absent even though it is an
outbound stage: it is offered only as the write side of a correspondent
whitelist whose read side (check-whitelist) lives on the inbound path, and
the question that would enable it is asked inside the inbound-only anti-spam
step. An outbound-only host also has no srs: SRS rewrites the sender of
mail we forward, and this host forwards nothing.
5.4. The questions¶
Below, every question the terminal interview can ask, in the order it asks
them, with the [pepsi-wizard] key its answer is remembered under. A step is
shown only when the direction (and, for one step, the presence of a local
Dovecot) makes it applicable; the Step X/Y banner counts only steps that
will really be asked.
5.4.1. Step: Server identity¶
Asked in every direction.
HOSTNAME— Mail server hostname (MX / EHLO name)The identity of the host, as distinct from the domains it serves: the ARC sealing domain, every relay and bounce
SERVER_NAME, and the subject of the fallback TLS certificate. The default comes from reverse DNS, not from/etc/hostname, because receivers compare theEHLOname against thePTRof the connecting address and reject when they disagree. If the offered default contradicts thePTR, the wizard names both and says why before asking.DOMAINS— Domain(s) we accept mail for (space separated)Becomes
[pepsi-ingress] ACCEPTED_DOMAINS, and through it the defaultLOCAL_DOMAINSof the local-delivery stages, the set ofmta-sts.*policy hosts, and the domains routed to Exchange. The first one is the primary domain: the SRS domain (srs.<primary>), the TLS-report addresses, the control addresses of the self-service stages and theSIGNING_DOMAINof the forward-signing stage are all derived from it.POSTMASTER— Postmaster addressNamed by the bounce stages and the direct-to-MX relay.
PUBLIC_IPS— Public sending IP address(es) for SPFAuto-detected and offered for confirmation, from the hostname’s
A/AAAArecords unioned with this host’s globally-routable interface addresses (and, on a NAT host with no public IPv4, the WAN address the local UPnP gateway reports). Only public addresses are ever pre-filled: these end up verbatim in the SPF record, so a private one there makes your own outbound mail fail SPF everywhere. A previous run’s answer is re-checked rather than trusted, since a host may have moved since it was written.DB_CONFIG— PostgreSQL connection stringlibpq form; the default
postgres:///pepsiuses peer authentication over the local socket, which is what the packaged service accounts expect.
5.4.2. Step: Existing mail system¶
Asked on the inbound path only, and asked before local delivery because the answer decides whether there is a local-delivery question at all.
EXCHANGE— Is there an existing Exchange / Microsoft 365 mail system behind this hostDefault no. Answering yes makes this host a transparent gateway in front of Exchange: it becomes the MX, Exchange keeps the mailboxes. It inserts the
routestage and a dedicatedexchangerelay into the received branch (see Pipeline: both), and it suppresses the local-delivery questions entirely — offering to write mailboxes for domains Exchange owns would produce a configuration in which a recipient is delivered twice or not at all. Recipients Exchange does not own (an alias expanding off-site, a forward) still leave through the relay tail. See Microsoft Exchange as a gateway.EXCHANGE_HOST— Exchange host (tenant endpoint, or the on-premises server)The tenant-specific endpoint, not your domain’s public MX. That MX is this host, and pointing Exchange back at it makes every message loop.
EXCHANGE_PORT— Exchange SMTP portDefault
25.EXCHANGE_ADDRESS_FAMILY— IP address family to reach Exchange overany(default),ipv4oripv6. Exchange Online refuses mail from a sending IPv6 address with noPTRrecord, so pinning this one next hop to IPv4 is a common and legitimate answer; other destinations are unaffected.
5.4.3. Step: Local delivery¶
Inbound path only, and the Maildir/LMTP questions are skipped when Exchange was answered yes.
- Maildir — Deliver mail for local system accounts into their Maildir
Adds
localto the received branch. Requires the SGID stage and setuid helpermake installprovisions (grouppepsi-maildir).DOT_FORWARD— Honour per-user ~/.forward files for Maildir accountsDefault no; offered only alongside Maildir, since it is the system accounts’ own home directories that are read. Adds
dot-forwardimmediately before local delivery, so a recipient with a~/.forwardis diverted before the mailbox write. The generated section forwards to addresses only;ALLOW_PIPEandALLOW_FILEare left off, as each would run a command or write a file as the target user.- LMTP — Deliver mail locally via LMTP to an MDA (Dovecot, which runs Sieve)
Adds
local-lmtp. Pepsi implements no Sieve itself; this hands the message to an MDA that does. When a local Dovecot is detected, the follow-up question is just its LMTP socket path (LMTP_SOCKET); otherwise a remote TCP target is collected —LMTP_HOST,LMTP_PORT,LMTP_TLS,LMTP_AUTHand, where the mechanism needs them,LMTP_USERNAMEandLMTP_PASSWORD. Pepsi does not configure Dovecot: if the sockets it will rely on are absent, a suggested10-pepsi.confis printed at the end of the run.- Order — Both local methods are enabled — which is tried first?
Asked only when both were enabled. The methods are chained in the order given, each delivering what it can and forwarding the rest to the next; the last one’s leftovers go to the relay tail. Stored in
LOCAL_METHODS.ALIASES_ENABLED— Enable aliases / mailing lists (expand recipients via a map file)Default no. Adds
aliasesafter the spam gates and just before routing and delivery, so the gates see the address the sender wrote to while the expanded set is routed per recipient. The map file is created next topepsi.confand re-read automatically when its modification time changes.MILTERS_ENABLED— Carry the milters over into the pipelineOnly asked when an MTA import found some. Note the change in timing it warns about: Pepsi runs filters after accepting the message, so one that used to reject in the session now produces a bounce (which is why detected filters are wired to
discard-rejectedinstead — see The shared tail and the bounces).MILTER_GREYLIST,MILTER_REGEX,MILTER_CLAMAV,MILTER_SPAMASSASSIN,MILTER_RSPAMD,MILTER_MIMEDEFANG,MILTER_AMAVISOne yes/no question per filter daemon a scan of this host found installed and answering. Each accepted filter becomes one
milter-*stage, placed by what it does — policy first, then virus, then spam, then the general-purpose frameworks — with imported filters of unknown purpose keeping the relative order their old MTA ran them in. All default to yes exceptMILTER_GREYLIST: greylisting works by refusing delivery in the session and betting a spam engine will not retry, and post-queue there is nothing to refuse and Pepsi is itself what retries, so the bet is always won and only the delay remains. Filters whose function Pepsi already performs (opendkim,openarc,opendmarc, SPF policy daemons, SRS rewriters) are recognised and reported as superseded rather than offered. See pepsi-stage-milter.ALIAS_STYLE— Qualify imported alias namesOnly when a migration supplied bare alias names such as
postmasterorroot, which Pepsi’s keys cannot use because they carry a domain:per-domain(one entry per served domain),wildcard(a single@-wildcard) orprimary.VACATION— Answer mail for recipients who are away (out-of-office replies)Default no. Adds
vacationafter alias expansion and after the spam gates, so a notice is never sent on behalf of an alias or in reply to mail the gates would have refused. Switching it on answers nobody: leave dates are ordinary per-address configuration, set later withpepsi-settings, at domain scope withpepsi-configfor a shared holiday, or by the users themselves by e-mail. On a host with no local delivery the generated section also setsVACATION_TAG = none, because tagging the subject rewrites a header the author’s DKIM signature and our own ARC seal both cover — harmless when the mail stops here, visible to the next hop when it is relayed on.- Smarthost — Also relay recipients local delivery does not handle to a smarthost
Optional when local delivery or Exchange handles your domains, in which case it only serves what neither did; required, and not asked, when neither does, since a pure relay must have somewhere to send. Saying yes collects
SMARTHOST_HOST,SMARTHOST_PORT,SMARTHOST_MODE(starttls/tls/plain),SMARTHOST_AUTH(none/plain/login) and, where authenticated,SMARTHOST_USERNAMEandSMARTHOST_PASSWORD. The credentials are checked on the spot against the real relay: a refusal offers the password again, while an unreachable relay says nothing about the password and does not push you into retyping a working one. Store-and-hope is how a mistyped relay password becomes a silently dead outbound path.
5.4.4. Step: Submission authentication¶
Asked only on the outbound path, and only when a Dovecot is installed on this host.
DOVECOT_SASL— Authenticate submissions against the local Dovecot SASL socketDefault yes. Sets mandatory
AUTHagainst Dovecot’s auth-client socket on the 465 and 587 listeners, so mail accounts and IMAP accounts are the same accounts. Declining leaves the listeners with a commented pointer to the alternatives (Dovecot SASL configured by hand, or TLS client certificates).
5.4.5. Step: Trust loopback¶
Outbound path only, and it is a narrower question than it looks.
TRUST_LOOPBACK— Trust loopback connections on port 25Default no, and the default is the right answer for nearly everyone. The wizard does not ask whether local programs may submit mail — they always can:
pepsi-ingressunconditionally serves the UNIX socket that/usr/sbin/sendmailuses, and the kernel tells it which account opened it, so a caller can only ever send as itself. This question is only about the weaker additional mechanism of trusting an address — aMYNETWORKSentry for127.0.0.0/8 ::1/128on the port-25 listener — which authenticates a network position rather than a user, so any local process, including a compromised web application, can then send as anyone. It is also what lets a message this host relays to itself re-enter as a fresh submission and loop. Say yes only for software that insists on speaking SMTP to 127.0.0.1 and cannot be pointed at the socket.
5.4.6. Step: Signing forwarded mail¶
Inbound path only.
SIGN_RELAYED— DKIM-sign mail this host forwards, as this host’s own domainDefault yes. Mail this host merely forwards — an alias expanding off-site, a
~/.forwardat another provider, the whole pure-relay path — leaves down the received branch, which the outbounddkim-signnever touches; without this it arrives at the next hop with our SRS envelope butdkim=nonefrom us. Answering yes inserts a second signing stage,dkim-sign-relay, betweensrsand the destination, withSIGNING_DOMAINpinned to the primary served domain. The pin is deliberate: signing is fail-closed and the author’s domain belongs to somebody else, so a signing domain derived from a foreignFrom:would fail every forwarded message for want of a key.
5.4.7. Step: Transport security¶
Always asked; the first question only on the inbound path.
MTA_STS— Serve an MTA-STS policy over HTTPSDefault yes. Sets
[pepsi] MTA_STS_MODE = enforceand emitspepsi-httpdwith onemta-sts.<domain>certificate section per accepted domain, provisioned bypepsi-setuplike any other. You must point eachmta-sts.<domain>name’s DNS at this host for the policy to be reachable.TLS_REPORTS— Send and advertise SMTP TLS Reports (TLSRPT, RFC 8460)Default yes; emits
[pepsi-tlsrpt]. Applies to any host that sends, so it is asked in every direction. Add the dailypepsi-tlsrpt reportcron entry the wizard reminds you about.Declining both of these — and not enabling the paywall — produces a minimal host with no HTTP server at all: the
pepsi-httpdsections are written only when something needs them.SHARE_TELEMETRY— Share anonymous feature-usage telemetry with the Pepsi projectDefault no, and it is opt-in in the strict sense: an operator who presses Enter through the entire interview shares nothing. The question explains what would be sent before asking, because a decision is only informed that way. Yes makes
pepsi-setup runmint a random 256-bitSYSTEM_IDand arms thepepsi-telemetry-clientdaemon, which periodically reports which features this deployment has exercised and how often, under that identifier — no addresses, message data, host names or IP addresses. No means no identifier is generated and nothing is sent, and re-running the wizard to answer no stops the daemon rather than waiting for it to notice.
5.4.8. Step: Content filtering¶
Inbound path only.
LANGUAGE_BLOCKING— Reject mail by detected human languageDefault no. Adds
detect-languageandblock-language.I18N_BOUNCES— Localize bounce messages to the sender’s languageAsked only when blocking is off, since blocking already implies detection. Adds
detect-languagealone, which annotatesstate.languageand refuses nothing.DETECT_LANGUAGES— Languages the detector should recogniseAsked when either of the above enabled detection, after printing the full list of supported ISO 639-1 codes.
*(the default) means every language the detector supports; naming fewer costs less worker memory. An unsupported code is rejected at the prompt. Only a detected language can then be allowed or blocked, which is why this comes before the policy.LANG_POLICY— Language policy (+allow / -block, e.g. ‘+en +fr -‘)*One combined answer, split into the stage’s
WHITELISTandBLACKLIST. A single-*or+*wildcard covers every other detected language, so+en +fr -*allows only English and French; the literalnonemay be listed to decide the fate of mail no language could be detected for.LANG_THRESHOLD— Score threshold (mail must score strictly above this)Default
-0.1.LANG_ENFORCEMENT— Enforce the language policy strictly or weaklyhard(default) refuses mail the policy fails, routing it tobounce-language.softmarks exactly the same mail instead — a[!LANG]subject flag and aPepsi-Detected-Languagesheader — which is how the lists and the threshold get tuned against real traffic without anyone’s mail being thrown away in the meantime. The bounce stage is written undersofttoo, so switching over later is a one-word edit rather than a hunt for what else it needs.
5.4.9. Step: Anti-spam paywall¶
Inbound path only.
ANTI_SPAM— Enable the GNU Taler anti-spam paywall (pay-to-send)Default no. Adds two stages to the received branch —
check-whitelistandanti-spam— and, when there is also an outbound path,auto-whitelistto the submitted one. The three are one feature: the outbound stage records everyone you write to, the inbound one recognises their replies, and only what neither vouched for meets the payment gate. It also emits thebounce-paymentstage and givespepsi-httpda/resumewebhook token.MERCHANT_BACKEND_URL— Taler merchant backend URLAsked first and verified on the spot, because its
/configreports the currencies the price may be quoted in — so the backend has to be known before the price can be validated.MERCHANT_ACCESS_TOKEN— Merchant access token (‘secret-token:…’) or the instance passwordEither is accepted: a ready-made access token is verified against the backend, an instance password is exchanged for a scoped access token.
PAYMENT_AMOUNT— Price per message (space-separated Taler amounts)Each amount becomes one choice in the generated order, so
EUR:1 CHF:1 KUDOS:10lets the payer pick a currency. Validated against the currencies the backend advertised.PAYMENT_DEADLINE— How long to hold a message awaiting paymentDefault
48 h. Hours, minutes and seconds only — the duration parser does not accept calendar units.LEARN_WHITELIST— Learn a correspondent whitelist from your outgoing mailAsked instead of the above when the paywall is declined, and only when there is also an outbound path. It adds
auto-whiteliston its own: the correspondents are recorded, and nothing yet consumes the verdict. That is a reasonable thing to switch on early, since a whitelist is only useful once it has some history in it.
5.4.10. Step: Account self-service¶
Outbound path only. Both default to no, and both are stages that pass ordinary mail straight through — they act only on a message a local account sent to their own control address.
EDIT_SETTINGS— Let account owners edit their own settings by e-mailAdds
edit-settings. A message topepsi@<domain>from a local account edits that address’s ownpepsi.settingsoverrides, restricted to an allowlist of stages the wizard derives from the inbound gates you actually enabled. See pepsi-stage-edit-settings.WALLET_SELF_SERVICE— Let account owners operate their GNU Taler wallet by e-mailAdds
wallet. A message topepsi-wallet@<domain>with a command in theSubjectoperates the sender’s own wallet: balance, top-up, peer-to-peer payments. See pepsi-stage-auto-pay.
5.4.11. Step: End-to-end cryptography¶
Always asked — encryption serves what your users send and decryption what arrives for them, and a deployment that does one without the other is rare enough not to be worth two questions. Which halves are actually emitted still follows the direction.
CRYPTO— Encrypt and decrypt mail end-to-end (OpenPGP / S/MIME)Default no. On the inbound path it adds
decryptfirst, so everything downstream sees plaintext; on the outbound path it addsencryptlast before signing, so DKIM covers what actually goes on the wire. Nothing is encrypted until a recipient’s key is known — keys come from discovery (WKD, DANE, VKS, LDAP), frompepsi-keys, or from the mail correspondents send you. The key store, the discovery daemon and the key-encryption key are provisioned by the rest of setup either way; this answer only decides whether the stages are in the pipeline. See Key management.AUTOCRYPT_LEARN— Learn correspondents’ keys from the mail they send usDefault yes, asked only when
CRYPTOis on and there is an inbound path — without a decrypt stage there is no plaintext to read gossip out of, and without an encrypt stage nothing would ever spend a learnt key. Addsautocrypt-learnafter every stage that can form a spam opinion and before anything that answers or delivers, which is exactly what Autocrypt Level 1 requires: a message believed to be spam teaches nothing, and a key learnt after delivery is learnt too late to encrypt the reply with. Learnt keys sit on the lowest rungs of the trust ladder — such a key can never displace one from discovery, and a signature checked against one is never reported as verified.
5.4.12. Step: Expert options¶
Shown only when --expert named some. These are real Pepsi options the
interview does not normally ask about — MAX_MESSAGE_SIZE, MYNETWORKS,
RECIPIENT_DELIMITER, MAX_LIFETIME, DMARC_ENFORCE, HELO_NAME,
TLS_CERT/TLS_KEY, DNS_TIMEOUT, MAX_CONNECTIONS,
MAX_OPEN_SOCKETS, DKIM_SELECTOR, KEY_DIR, MAILBOX_QUOTA,
MAILBOX_OVER_QUOTA, CRYPTO_ALLOW_DOWNGRADE — each of which knows which
section it belongs in. A value already carried in the defaults (from a previous
run, or from an MTA import) is applied whether or not --expert asks about
it; the flag only decides which ones get a prompt. Leaving an answer empty
restores Pepsi’s own default. See pepsi-setup(1).
5.5. What the wizard does not ask¶
Some things are absent from the interview on purpose, and knowing which saves looking for them:
The local submission socket.
pepsi-ingressserves it unconditionally, deriving the path from[pepsi-sendmail] SOCKET, so no listener section is written and there is nothing that can disagree with anything else. It used to be a question, and the only symptom of getting it wrong was that cron mail stopped.SRS. The rewrite is wired automatically wherever mail can be forwarded, with a generated HMAC secret. Nothing about it is a choice.
How the listeners bind. A host running systemd (detected by
/run/systemd/system) gets socket-activated listeners (SERVE = systemd, oneFD_INDEXper listener); anything else gets direct binds. With socket activation you must install matching.socketunits whoseListenStream=order lines up with theFD_INDEXvalues — the wizard prints a reminder, andpepsi-ingresswarns at start-up about any descriptor no section claimed.Keys, certificates, the schema and DNS. All of that is
pepsi-setup run, which the wizard offers to chain into. TLS certificates are provisioned via certbot; a certificate that cannot be obtained defers rather than aborting the run, so the schema, keys and DNS output still happen.
5.6. Re-running it¶
The interview records every non-secret answer in a [pepsi-wizard] section
at the end of the file it writes, and a later --wizard run imports those as
its defaults — so re-running to change one thing is a press-Enter walk down to
that question. Secrets are handled separately and are never written there: a
generated one (the SRS key, the /resume token) is read back and kept,
because rotating the SRS key would invalidate every rewritten sender still in
flight; a typed one (a smarthost or LMTP password, the merchant token) is
offered back at its own prompt as ***, so pressing Enter keeps it without
it ever being echoed or re-typed.
Two non-interactive forms exist for the same interview. --answers FILE
supplies answers by key from a JSON file, short-circuiting every prompt (a
missing or malformed answer is a hard failure rather than a prompt nobody is
there to see), and is how a configuration can be reproduced across hosts.
--import names an MTA to migrate from explicitly, rather than detecting
one. Both are documented in pepsi-setup(1).