diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-09 10:21:36 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-09 10:21:36 -0500 |
| commit | f3dc2a905e4328d6fc16aa15d091ec65edcfc120 (patch) | |
| tree | efa7f2678787db43e387968b1bfab72883c9497d /assets | |
| parent | 1b58db366885bf014d14da19d14da8ee68aff9da (diff) | |
| download | archsetup-f3dc2a905e4328d6fc16aa15d091ec65edcfc120.tar.gz archsetup-f3dc2a905e4328d6fc16aa15d091ec65edcfc120.zip | |
feat: add post-install cmail Bridge setup
Bridge first-run is interactive, so I put the cmail wiring in a post-install
helper rather than running it inside archsetup. scripts/cmail-setup-finish.sh
handles the post-first-run steps idempotently: it decrypts the encrypted
cmailpass, copies Bridge's self-signed cert to ~/.config/protonbridge.pem,
symlinks the cmail-action triage helper into ~/.local/bin, and enables the
user-level protonmail-bridge service.
I added loginctl enable-linger in essential_services so the user service
survives logout — without it, triaging cmail from a remote agent or SSH
session has nothing to talk to. outro prints a four-step runbook for the
manual steps after reboot.
Diffstat (limited to 'assets')
| -rw-r--r-- | assets/outbox/2026-05-08-protonmail-bridge-cmail-triage.org | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/assets/outbox/2026-05-08-protonmail-bridge-cmail-triage.org b/assets/outbox/2026-05-08-protonmail-bridge-cmail-triage.org new file mode 100644 index 0000000..8b75c9c --- /dev/null +++ b/assets/outbox/2026-05-08-protonmail-bridge-cmail-triage.org @@ -0,0 +1,198 @@ +#+TITLE: Proton Mail Bridge + cmail-action triage helper +#+DATE: 2026-05-08 + +* What this is + +Notes for folding the Proton Mail Bridge + =cmail-action= triage +helper setup into the archsetup install flow. Reproduces what was +set up on ratio on 2026-05-08. + +* Why + +Proton Mail (=c@cjennings.net=, locally =cmail=) doesn't expose +plain IMAP — it's end-to-end encrypted. Proton Mail Bridge is the +official local daemon that decrypts on-the-fly and presents a +local IMAP/SMTP endpoint at =127.0.0.1:1143= / =1025=. Once Bridge +is running, anything that speaks IMAP (mbsync, mu, mu4e, custom +helpers) talks to cmail the same way it talks to any other IMAP +account. + +The triage workflow at =homelab/.ai/project-workflows/process-unread-emails.org= +previously handled gmail/dmail (via the Gmail MCP server) but had +no equivalent for cmail. The =cmail-action= helper closes that +gap — it talks directly to Bridge's IMAP and provides the same +operations the Gmail MCP gives the other two accounts: list +unread, read body, mark read, star, unstar, trash. Pattern: full +parity, Claude drives end-to-end, no switching to mu4e mid-flow. + +* End state to reproduce + +After the install completes, the system has: + +1. =protonmail-bridge= installed from AUR. +2. First-run done: Proton account logged in, Bridge-generated IMAP + password captured at =~/.config/.cmailpass= (mode 0600). +3. Bridge's self-signed cert at =~/.config/protonbridge.pem=. +4. Bridge running as a systemd user service (autostarts on login). +5. =cmail= account block in =~/.mbsyncrc= pointing at the local + Bridge endpoint. +6. =~/.mail/cmail/= populated by mbsync. +7. =~/.local/bin/cmail-action= symlinked into PATH, pointing at + =~/projects/claude-templates/.ai/scripts/cmail-action.py=. + +* Steps + +Pre-reqs: claude-templates already cloned at +=~/projects/claude-templates= (the cmail-action.py script lives +there), paid Proton plan (Bridge is gated behind paid tier). + +** 1. Install Bridge from AUR + +#+begin_src bash +yay -S protonmail-bridge +#+end_src + +Pulls in =protonmail-bridge= and =protonmail-bridge-core= binaries. +Don't use Flatpak. + +** 2. First-run: log in and capture IMAP password + +This step is interactive and can't be automated — Proton requires +real credentials. Run once on a new install: + +#+begin_src bash +protonmail-bridge --cli +#+end_src + +In the CLI: =login= → enter Proton account credentials → 2FA prompt +if enabled. Bridge stores the account credentials in its own +encrypted state under =~/.config/protonmail/bridge-v3/=. + +Then in the same CLI session, =info= prints the per-app IMAP and +SMTP passwords Bridge generated for this account. Capture the IMAP +password (NOT the Proton account password — these are distinct): + +#+begin_src bash +echo 'BRIDGE_GENERATED_PASSWORD' > ~/.config/.cmailpass +chmod 600 ~/.config/.cmailpass +#+end_src + +The encrypted form lives in +=~/code/archsetup/dotfiles/common/.config/.cmailpass.gpg= for sync +across machines. The plaintext file at =~/.config/.cmailpass= is +gitignored and decrypted locally as needed. + +** 3. Export the Bridge cert + +Bridge ships a self-signed cert that mbsync and =cmail-action= pin +against. Path inside Bridge state varies by version; locate and +copy: + +#+begin_src bash +find ~/.config/protonmail -name 'cert.pem' -print +cp ~/.config/protonmail/bridge-v3/cert.pem ~/.config/protonbridge.pem +#+end_src + +The cert's CN is =127.0.0.1=, so connecting to localhost validates +against the pinned cert. =cmail-action= disables hostname +verification anyway (cert lacks SAN; localhost + pinned cert is +sufficient). + +** 4. Configure mbsync for cmail + +Add the =cmail= block to =~/.mbsyncrc=. The current homelab setup +has it; the canonical version lives in +=dotfiles/common/.mbsyncrc= and is symlinked to =~/.mbsyncrc=. + +Key fields: + +#+begin_example +IMAPAccount cmail +Host 127.0.0.1 +Port 1143 +User c@cjennings.net +PassCmd "cat ~/.config/.cmailpass" +TLSType STARTTLS +CertificateFile ~/.config/protonbridge.pem + +MaildirStore cmail-local +Path ~/.mail/cmail/ +Inbox ~/.mail/cmail/Inbox/ +Trash ~/.mail/cmail/Trash/ +SubFolders Verbatim +#+end_example + +Plus channels for each folder (Inbox / Sent / Trash / Archive / +Starred / Spam — Drafts and All Mail are intentionally omitted +because Bridge has historically had sync issues on those two +folders). + +Initial sync: + +#+begin_src bash +mkdir -p ~/.mail/cmail +mbsync cmail +mu index +#+end_src + +** 5. Enable Bridge as a systemd user service + +The protonmail-bridge AUR package ships a unit at +=/usr/lib/systemd/user/protonmail-bridge.service=. The unit calls +=protonmail-bridge-core --noninteractive= directly (not the +=protonmail-bridge --no-window= wrapper). Enable + start: + +#+begin_src bash +systemctl --user enable --now protonmail-bridge +#+end_src + +Verify: + +#+begin_src bash +systemctl --user status protonmail-bridge +ss -ltn | grep -E '127.0.0.1:(1143|1025)' +#+end_src + +Expected: service active (running), both ports LISTEN. Bridge logs +a non-fatal warning about =pass not initialized= because the +=pass= keychain helper isn't set up — Bridge falls back to its own +encrypted state under =~/.config/protonmail/=. Ignore. + +** 6. Symlink cmail-action into PATH + +The script is the source-of-truth in claude-templates. The PATH +entry is a symlink so updates to claude-templates immediately +take effect: + +#+begin_src bash +ln -s ~/projects/claude-templates/.ai/scripts/cmail-action.py \ + ~/.local/bin/cmail-action +#+end_src + +Verify: + +#+begin_src bash +cmail-action folders # lists Proton IMAP folders +cmail-action list-unread --limit 1 # returns JSON +#+end_src + +* Notes / gotchas + +- *Bridge requires a paid Proton plan.* Bridge auth fails on free + tier. If the install runs on a free-tier account, skip steps 2-6 + with a clear error. +- *Bridge sometimes resets UIDVALIDITY* after upgrades. The + homelab =sync-email.org= workflow documents the recovery steps + (delete =.uidvalidity= and =.mbsyncstate= under + =~/.mail/cmail=, re-run mbsync). Doesn't affect =cmail-action= + because the helper talks to Bridge live and doesn't keep its + own state. +- *The Bridge cert can rotate.* If =cmail-action folders= ever + starts failing with cert errors, re-run step 3. +- *Drafts and All Mail are intentionally omitted from mbsync* per + the comment in =~/.mbsyncrc=. Don't add them back without + testing — historical sync errors. +- *=cmail-action= bypasses mbsync* for triage operations — it + talks to Bridge's IMAP directly. mbsync is still used for + offline reading via mu/mu4e, but the triage workflow doesn't + depend on it. |
