Installation
Dependencies
- Go 1.26 or newer
- libnotmuch (the default build links the cgo binding against
libnotmuch.so- install thenotmuchruntime and dev package of your distribution) - a running notmuch setup (
notmuch newwith your maildirs indexed - notmutt is a front-end, notmuch owns the database)
No libnotmuch available, or you prefer not to link it? The CLI backend is one build tag away - the same binary code, the same interface:
cd src
go build -tags cli -o ../notmutt .
Build
git clone git@github.com:fishman/notmutt.git
cd notmutt/src
go build -o ../notmutt .
The binary lands at ./notmutt. Run it from anywhere; your configuration is read from ~/.config/notmutt/config.toml.
Configuration
The client ships with its defaults as data: src/config/base.toml is the reference - every default (keybindings, themes, views, tag groups, pager settings) is visible there. Your user file overlays it; nothing in your file needs to restate a default. Start with an empty file if you want to discover the defaults, or copy base.toml and edit.
Configuration is strict by design: unknown keys are load errors, not silently ignored typos.
Accounts
Run notmutt setup once after indexing your mail. It walks the notmuch mail root, detects each account from its folder structure, and writes ~/.config/notmutt/accounts.toml (0600) with one [accounts.<name>] entry per match:
$ ./notmutt setup
setup: accounts: gmail (gmail), acme (outlook)
setup: no template match: atlas
setup: wrote /home/you/.config/notmutt/accounts.toml
Detection is template-driven. Each built-in provider shape (gmail, exchange, icloud, zoho, outlook) names the folders that must exist at the account root - gmail is gated by a top-level [Gmail], exchange by Sent Items, zoho by Snoozed - then maps the hard tags (inbox, sent, draft, spam, deleted, archive, pending) to that provider’s real folder names: [Gmail]/Drafts, Sent Items, Archives vs Archive. Candidates are priority-ordered, first existing folder wins, and a flat layout falls back to the provider names. Only directory names are read, never mail content.
setup is detection output, not a complete account: from and default_signature are yours to fill in. The [accounts.<name>] table then carries the full surface:
| key | meaning |
|---|---|
from | sender address used to prefill the compose dialogue |
default_signature | signature file name in the account’s signatures dir |
folder | the account’s folder prefix (the account tag); derived by setup |
folders | the hard-tag -> folder map; derived by setup |
no_fcc | skip the sent copy (the provider stores it server-side); setup sets it for gmail/zoho |
readonly | never classify, never move, never tag this account’s mail |
return_inbox | trash returns to inbox instead of staying deleted |
preset | provider preset name for the default move rules |
moves | per-tag move overrides (tag -> folder candidates) |
Accounts drive the compose dialogue: A picks the sender account, reply mode resolves it from the message’s account tag, and the Fcc path derives from the account’s sent-folder map at send time. The generated accounts.toml merges with the rest of your config automatically - edit it freely, re-run notmutt setup to regenerate (a from you typed by hand is overwritten only if you delete the file; regeneration writes the whole file).
Provider-specific setup notes and template shapes (Gmail, Outlook, iCloud, Zoho, Exchange, and the flat layouts) are welcome - if your provider’s folder names do not match, open an issue with its folder list, or contribute a template: drop a lua/templates/<provider>.lua in the config dir, enable it via [setup] templates, and send a PR mirroring it in src/setup/setup.go. A maildir fixture with the provider’s folder names (no mail inside) is all a template test needs.
Terminal requirements
- Truecolor (
COLORTERM=truecolor); the R11 baseline is truecolor, no 256-color mapping - Images: a sixel-capable terminal (foot, mlterm, xterm with
-ti 340, …) outside tmux - tmux does not pass image protocols through. Kitty graphics is opt-in via[pager] image-protocol - The client detects the terminal image protocol from the environment; nothing to configure for text-only use