Your inbox, on your computer.
mxr ◈ say it Mixer
works with Gmail, any IMAP server, any SMTP relay ◈ tested with Fastmail, Migadu, Proton Bridge
Homebrew
brew install planetaryescape/mxr/mxrCargo
cargo install --git \ https://github.com/planetaryescape/mxr \ --locked mxrNot ready to hand over your inbox? Run mxr demo. It uses a separate demo config, database, and daemon so you can explore search, labels, threads, attachments, newsletters, analytics, and keyboard triage safely.
offline
Section titled “offline”No signal. No problem.
Open mxr on a plane with the wifi off. Triage. Reply. Draft. Snooze. Opening a message is a SQLite read, not a fetch, so there is no network round trip waiting on you. When you land and your laptop reconnects, mxr finishes everything you queued.
Your archive is on disk, not in someone else’s cloud. Years of email, every attachment, every label: local, indexed, yours.
search like it’s local
Section titled “search like it’s local”Find a 2019 contract by the supplier’s name. Pull every receipt from a vendor. List the apology email you sent in March. mxr indexes your mail with Tantivy, the BM25 engine behind Quickwit, with field boosts on subject, body, sender, and attachment names. Optional local hybrid retrieval when you turn it on. No round trips, no rate limits, no “loading more.”
mxr storage --by sender --limit 20mxr stale --mine --older-than-days 14mxr wrapped --year 2025mxr search "subject:invoice" --format json | jq -r '.[].from' | sort -uemail your agent can operate
Section titled “email your agent can operate”Anything you can do with email, your agent can do. Not “compose a draft and stop.” Actually run the workflow.
mxr subscriptions —rank —format jsonmxr stale —within-days 90 —format idsmxr search “from:sarah OR to:sarah after:2026-04-23” —format jsonmxr draft-assist <thread-id> “1:1 agenda”mxr search “from:ci@github.com after:2026-04-30” —format idsgit log —since=1.week —pretty=%H %secho <ids> | xargs mxr archive —yesThis works because mxr isn’t a GUI with an API bolted on. The CLI is the interface. Most reads return —format json, mutations support —dry-run and accept piped IDs, and every command composes with the rest of your shell. Your agent doesn’t need browser automation, screen scraping, or a provider-specific SDK.
mxr search "from:sarah after:2026-04-23" --format json | jq '.[0]'{ "message_id": "01JFQ7K3M2X8N5R0VYZA9CTBPE", "from": "Sarah Chen <sarah@example.com>", "subject": "1:1 prep, Friday", "date": "2026-04-30T15:42:11+00:00", "read": false, "starred": false, "score": 12.4}when gmail dies, you don’t
Section titled “when gmail dies, you don’t”Each had millions of users when it shut down.
If your provider goes dark tomorrow, an outage, a lockout, a deprecation, an account flag, you lose a day or two of new mail. Everything else is on your laptop. You keep your archive, your search, your drafts, your filters. Re-point mxr at a different provider; carry on.
Your email is data. It belongs on a disk you own.
not a lock-in
Section titled “not a lock-in”mxr is a client, not a replacement. It keeps a live two-way sync with your provider so changes flow both directions within seconds.
- → read a thread in Gmail web on your phone
- → apply a label in Apple Mail
- → archive a newsletter from your watch
+ IDLE
- ← mxr marks the thread read
- ← the label appears in mxr’s sidebar
- ← the newsletter disappears from inbox
You’re not locked in either direction. Stop using mxr tomorrow and your mail is still in Gmail or your IMAP server, exactly where it was. The local archive on disk is yours to keep.
principles
Section titled “principles”One daemon, many surfaces.
The TUI, CLI, and HTTP bridge are clients of the same process. Sync, indexing, rules, snoozing, and analytics self-healing run in the background. Close the TUI; nothing stops.
mxr # TUI (auto-starts daemon)
mxr search ... # CLI
mxr web # HTTP bridgeA real search engine, not a filter.
Tantivy gives you sub-second BM25-ranked full-text search across your entire mailbox, with field boosts on subject, body, sender, and attachment filenames. Saved searches sit in the sidebar as programmable lenses. Optional local hybrid retrieval when you opt in.
mxr search "subject:invoice from:vendor"
mxr search "has:attachment larger:5M"
mxr search "is:unread label:client/acme"Compose where you already write.
$EDITOR opens with markdown and YAML frontmatter. Your keybindings, your plugins, your muscle memory. mxr handles parsing, markdown to multipart conversion, and sending. No second editor, no janky web textarea.
---
to: team@example.com
subject: ship plan
---
Hi team,
We're cutting v0.5 on Friday.Provider-agnostic by construction.
Gmail, IMAP, SMTP all normalise into one internal model. Mix providers freely; mxr handles the per-provider quirks behind a clean Rust trait. A conformance suite validates new adapters before they ship.
mxr accounts add gmail
mxr accounts add imap # work
mxr accounts add gmail # personal
# one mailbox, one searchDistraction-free reader mode.
Reader mode strips tracking pixels, banners, signatures, quoted text. You see what the email says, not what it is selling. One key to unsubscribe; one key to mark read and archive.
D unsubscribe
e archive
m mark read + archive
R toggle reader mode
L open links pickerPipeable by default.
Reads support —format json|jsonl|ids|csv|table. Mutations support —dry-run, —search for batch ops, and accept piped IDs from stdin. See the automation contract for per-command capabilities.
mxr search "from:noreply" --format ids \
| xargs -n1 mxr archive
mxr stale --mine --format json \
| jq '.[] | select(.days_stale > 30)'surfaces
Section titled “surfaces”mxr is a daemon plus clients. Three ship today; the daemon speaks JSON over a Unix socket and HTTP, so anything that can open a socket can drive your inbox.
Vim-native keys, Gmail-style chords. Six top-level screens including a full Analytics view (storage, contacts, stale, response-time, subscriptions, wrapped). Compose in $EDITOR.
mxrEvery TUI action has a CLI equivalent. Pipe through jq, xargs, anything Unix. Use it from a shell, a Makefile, your prompt, your editor, your agent.
mxr archive --search "from:noreply older:30d" --dry-run
would archive 142 messages.mxr web exposes the daemon over HTTP and WebSocket. Bearer-token auth, OpenAPI-described, generates typed SDK clients. Use the browser app we ship, or build your own client against the same API.
curl -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:42829/api/v1/mail/search?q=is:unread"
{"results": [...]}A Raycast extension. A phone app. A Slack bot. A custom dashboard. The OpenAPI spec is the contract; your agent can write the rest.
standing on
Section titled “standing on”Each predecessor taught us something we kept. Read down. It is a commit log of the genre, with mxr as HEAD.
Everything below, synthesised. One daemon underneath; many surfaces on top.
- + daemon-backed: TUI, CLI, HTTP bridge, your agent share one engine
- + eager body fetch: opening a message is a SQLite read, not a fetch
- + Tantivy BM25 with field boosts; optional local hybrid retrieval
- + agent-native pipeable JSON across every command
- + OpenAPI HTTP bridge for browser apps, mobile, custom clients
- + analytics that self-heal post-sync
Practical Gmail scripting from the shell.
- → CLI flows are usable even for cloud-only providers
The CLI is the primary surface, not a debugging fallback.
- → scriptability as a first-class feature
- → JSON-aware output
- → engine and view split, clients are clients
The terminal can host a genuinely modern MUA.
- → tabbed compose, embedded HTML rendering
- → ex-commands and pipe-to-shell
- → filter and search split for navigation vs. discovery
Carry the work forward. Don’t let good code die.
- → sidebar with system + user labels
- → packaging discipline; “just install it” works on every distro
A real search engine belongs inside the mail client.
- → local indexing as a primary feature, not an afterthought
- → tag-driven query language
”All mail clients suck. This one just sucks less.”
- → keyboard-first navigation
- → terminal as home; no GUI tax
- → macros, the original “scriptability”
Compose small tools. Pipe text. Get out of the user’s way.
Built in Rust: one binary, no runtime, runs everywhere. No analytics, no phone-home, no third-party services in the hot path. The architecture is designed for contribution: clean crate boundaries, compile-time-checked SQL via sqlx, a conformance test suite for provider adapters. Whether it’s a bug fix, a new provider adapter, a CLI improvement, or an idea, we want to hear from you.