aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xarchsetup17
-rw-r--r--assets/outbox/2026-05-08-protonmail-bridge-cmail-triage.org198
-rwxr-xr-xscripts/cmail-setup-finish.sh79
3 files changed, 294 insertions, 0 deletions
diff --git a/archsetup b/archsetup
index 9a1c277..336ba28 100755
--- a/archsetup
+++ b/archsetup
@@ -1367,6 +1367,15 @@ EOF
else
display "task" "ext4/other filesystem detected"
fi
+
+ # User Services Lingering
+ # Keeps user-level systemd services (e.g., protonmail-bridge) running without
+ # an active login session. Needed for headless triage workflows that talk to
+ # user-level IMAP/SMTP daemons over SSH or from remote agents.
+
+ display "subtitle" "User Services"
+ action="enabling user-services lingering for $username" && display "task" "$action"
+ loginctl enable-linger "$username" >> "$logfile" 2>&1 || error_warn "$action" "$?"
}
### Xorg Display Manager
@@ -2187,6 +2196,14 @@ outro() {
fi
printf "\n"
+ printf "If you use Proton Mail Bridge for cmail triage, finish the setup\n"
+ printf "after reboot:\n"
+ printf " 1. Clone claude-templates to ~/projects/claude-templates if missing.\n"
+ printf " 2. Run 'protonmail-bridge --cli', log in, then quit.\n"
+ printf " 3. Run ~/code/archsetup/scripts/cmail-setup-finish.sh\n"
+ printf " 4. First mail sync: mbsync cmail && mu index\n"
+
+ printf "\n"
printf "Please reboot before working with your new workstation.\n\n"
# Completion marker for automated testing
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.
diff --git a/scripts/cmail-setup-finish.sh b/scripts/cmail-setup-finish.sh
new file mode 100755
index 0000000..de99101
--- /dev/null
+++ b/scripts/cmail-setup-finish.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+# cmail-setup-finish.sh — finish Proton Mail Bridge + cmail-action setup after
+# Bridge first-run. Idempotent; safe to re-run after a Bridge cert rotation or
+# a claude-templates re-clone.
+#
+# Pre-reqs (the script aborts if any are missing):
+# - protonmail-bridge installed (archsetup handles it)
+# - You have run 'protonmail-bridge --cli', logged in, and quit at least once
+# (the script looks for state at ~/.config/protonmail/bridge-v3/)
+# - claude-templates cloned at ~/projects/claude-templates
+# - dotfiles stowed (~/.config/.cmailpass.gpg present)
+#
+# What it does:
+# 1. Decrypts ~/.config/.cmailpass.gpg → ~/.config/.cmailpass (mode 0600)
+# 2. Copies Bridge's self-signed cert → ~/.config/protonbridge.pem
+# 3. Symlinks ~/projects/claude-templates/.ai/scripts/cmail-action.py
+# → ~/.local/bin/cmail-action
+# 4. Enables + starts the protonmail-bridge user service
+# 5. Verifies Bridge is listening on 127.0.0.1:1143 / :1025
+
+set -euo pipefail
+
+err() { printf 'error: %s\n' "$*" >&2; exit 1; }
+info() { printf '==> %s\n' "$*"; }
+ok() { printf ' %s\n' "$*"; }
+
+# 1. Pre-reqs
+command -v protonmail-bridge >/dev/null 2>&1 \
+ || err "protonmail-bridge not found in PATH — install via archsetup first"
+
+bridge_state="$HOME/.config/protonmail/bridge-v3"
+[ -d "$bridge_state" ] \
+ || err "Bridge has no state at $bridge_state — run 'protonmail-bridge --cli' and log in first"
+
+cmail_action_src="$HOME/projects/claude-templates/.ai/scripts/cmail-action.py"
+[ -f "$cmail_action_src" ] \
+ || err "cmail-action.py not found at $cmail_action_src — clone claude-templates first"
+
+cmailpass_enc="$HOME/.config/.cmailpass.gpg"
+[ -f "$cmailpass_enc" ] \
+ || err "$cmailpass_enc not found — ensure dotfiles are stowed"
+
+# 2. Decrypt cmailpass
+info "decrypting $cmailpass_enc"
+cmailpass_plain="$HOME/.config/.cmailpass"
+gpg --quiet --yes --decrypt --output "$cmailpass_plain" "$cmailpass_enc"
+chmod 600 "$cmailpass_plain"
+ok "wrote $cmailpass_plain (mode 0600)"
+
+# 3. Bridge cert
+info "exporting Bridge cert"
+cert_src="$(find "$bridge_state" -name 'cert.pem' -print -quit 2>/dev/null)"
+[ -n "$cert_src" ] || err "no cert.pem found under $bridge_state — Bridge state is incomplete"
+cert_dst="$HOME/.config/protonbridge.pem"
+cp "$cert_src" "$cert_dst"
+ok "copied $cert_src → $cert_dst"
+
+# 4. Symlink cmail-action
+info "symlinking cmail-action"
+mkdir -p "$HOME/.local/bin"
+ln -sf "$cmail_action_src" "$HOME/.local/bin/cmail-action"
+ok "linked $HOME/.local/bin/cmail-action → $cmail_action_src"
+
+# 5. Enable + start systemd user service
+info "enabling protonmail-bridge user service"
+systemctl --user enable --now protonmail-bridge
+ok "service active"
+
+# 6. Verify
+info "verifying Bridge is listening"
+if ss -ltn 2>/dev/null | grep -qE '127\.0\.0\.1:(1143|1025)'; then
+ ok "127.0.0.1:1143 + :1025 LISTEN"
+else
+ err "Bridge isn't listening on the expected ports — check 'systemctl --user status protonmail-bridge'"
+fi
+
+echo
+echo "cmail setup complete."
+echo "Next: 'mbsync cmail && mu index' for the first sync."