Email triage TUI. Stacks your inbox by sender so you can trash, archive, mark-read, or unsubscribe from hundreds of emails in a few keystrokes. Built for fast inbox-zero over Gmail IMAP, multi-account.
mailprune personal work
┌ stacks (42) · 873 msgs · by sender · sort read rate · 2 marked ─┐┌ DoorDash <[email protected]> · unsub: one-click POST ┐
│▌ 214 0% U DoorDash (12 new) ││ 2026-06-09 ● Your order is on the way │
│▌ 120 2% U Medium Daily Digest ││ 2026-06-08 Craving something new? │
│ 76 31% U LinkedIn ││ 2026-06-07 Weekend deals near you │
│ 31 94% GitHub ││ ... │
└─────────────────────────────────────────────────────────────────┘└───────────────────────────────────────────────────────────┘
j/k · Enter expand · Space mark · a mark all · d trash · e archive · r read · u unsub · s group · o sort · / filter · Tab acct · q quit
macOS and Linux (prebuilt binaries via Homebrew):
brew install niraj8/tap/mailpruneOr grab a tarball from releases (macOS arm64/x86_64, Linux x86_64), or build from source:
make install # cargo build --release && cp to ~/binPasswords are stored in the platform keychain: macOS Keychain, Secret Service
(GNOME Keyring/KWallet) on Linux, Credential Manager on Windows (compiles, untested).
No keyring daemon? Use the MAILPRUNE_PASSWORD_<EMAIL_WITH_UNDERSCORES> env var instead.
-
Enable 2FA on each Google account, then generate an app password at https://myaccount.google.com/apppasswords (also requires IMAP enabled in Gmail Settings → Forwarding and POP/IMAP).
-
Config — create
~/.config/mailprune/config.toml:[[accounts]] name = "personal" email = "[email protected]" [[accounts]] name = "work" email = "[email protected]"
-
Store app passwords (saved in the macOS Keychain):
mailprune auth [email protected]
-
Run:
mailprune(TUI) ormailprune stacks(headless dump of all accounts).
| key | action |
|---|---|
j / k |
move selection |
Enter / Esc |
expand / collapse stack |
d |
trash entire stack (moves to Gmail Trash — recoverable 30 days) |
e |
archive stack (moves to All Mail) |
r |
mark stack read |
u |
unsubscribe — RFC 8058 one-click POST → mailto via SMTP → browser fallback; then offers to trash the stack |
Space |
mark stack for bulk action (auto-advances; d/e/r/u then apply to all marked) |
a |
mark all visible stacks (again to clear) |
s |
toggle grouping: sender ↔ sender+subject |
o |
toggle sort: count ↔ read rate (least-read first — your dead newsletters) |
/ |
filter stacks by sender |
Tab |
next account |
R |
refresh |
g / G |
top / bottom |
q |
quit |
The fastest way to inbox zero:
o— sort by read rate. Stacks you never open float to the top.Spacedown the list to mark the dead newsletters (auto-advances).u— bulk unsubscribe everything marked, one confirm.yagain at the "also trash?" prompt.sto regroup by sender+subject and repeat for noisy notification types from senders you otherwise keep.
- Each stack shows a read-rate % (share of its messages you've opened), red when ≈0 — a 0% stack with 100 messages is a newsletter you should unsubscribe from. Based on messages currently in INBOX only.
- Delete is always move-to-Trash, never permanent — Gmail keeps trash 30 days. That's the undo story.
- Unsubscribe priority:
List-Unsubscribe-Postone-click (silent HTTP POST) →mailto:(sends an email via SMTP with your app password) → opening thehttpslink in your browser. - Passwords live in the Keychain under service
mailprune. Env override:MAILPRUNE_PASSWORD_<EMAIL_WITH_UNDERSCORES>.