NeoMutt is a fork of Mutt that started in 2016. For years, many popular Mutt features (sidebar, notmuch integration, compressed folders, nested conditional format strings, and more) existed only as out-of-tree patches that distributions applied inconsistently. NeoMutt collected them into one actively developed codebase. Some of those features were later merged back into Mutt itself (the sidebar is the best-known example), but NeoMutt has kept adding its own since.
Both projects are alive. Mutt is conservative and stable, with infrequent releases. NeoMutt moves faster and releases several times a year with date-based versions (neomutt -v prints something like NeoMutt 20250905).
Should I use Mutt or NeoMutt?¶
| Choose NeoMutt if you want… | Choose Mutt if you want… |
|---|---|
| notmuch full-text search and tag-based virtual folders | The most conservative, slowest-changing option |
Lua scripting, ifdef conditional config, named-mailboxes |
Behaviour that matches a decade of existing Mutt documentation exactly |
| Modern header-cache backends (LMDB, RocksDB) with compression | A package available on almost every OS, including very old ones |
| IMAP QRESYNC/CONDSTORE for faster resyncs on large mailboxes | |
Secure defaults out of the box (e.g. ssl_force_tls on) |
Everything in the Mutt and Mutt and GPG guides applies to NeoMutt. This guide covers only what's different or extra.
Installing¶
sudo dnf install neomutt # Fedora / RHEL (EPEL)
sudo apt install neomutt # Debian / Ubuntu
brew install neomutt # macOS
Check what's compiled in. Optional features vary by distribution build:
neomutt -v | sed -n '/Compile options/,/^$/p'
Look for +notmuch, +lua, +gpgme, +sasl, and the header-cache backends (+lmdb, +tokyocabinet, +kyotocabinet, +rocksdb).
Configuration files and migrating from Mutt¶
NeoMutt looks for its own files first, then falls back to Mutt's:
~/.neomuttrc
$XDG_CONFIG_HOME/neomutt/neomuttrc (usually ~/.config/neomutt/neomuttrc)
~/.neomutt/neomuttrc
…then the Mutt locations (~/.muttrc, ~/.mutt/muttrc, ~/.config/mutt/muttrc)
So an existing Mutt config usually just works. To migrate deliberately:
mkdir -p ~/.config/neomutt
cp -r ~/.config/mutt/* ~/.config/neomutt/
mv ~/.config/neomutt/muttrc ~/.config/neomutt/neomuttrc
# fix any paths inside that still point at ~/.config/mutt
grep -rl '\.config/mutt' ~/.config/neomutt | xargs sed -i 's#\.config/mutt#.config/neomutt#g'
# Start with only this config and read any warnings
neomutt -n -F ~/.config/neomutt/neomuttrc
NeoMutt reports unknown or removed variables at startup instead of silently ignoring them. What usually needs changing:
- Deprecated synonyms that Mutt still tolerates (for example
pgp_autosign,pgp_replysign,pgp_replyencrypt) should be updated to theircrypt_*names. - Patch-era variable names from distro-patched Mutt builds (old sidebar patch names,
nm_*from early notmuch patches) may have been renamed. Check the startup messages. - Debug flags: Mutt's
-d LEVELwrites~/.muttdebug0; NeoMutt takes-d LEVEL -l FILE.
Sharing one config between Mutt and NeoMutt¶
NeoMutt's ifdef/ifndef let one file serve both clients, or degrade gracefully when an optional feature isn't compiled in. Mutt doesn't understand these commands, so keep NeoMutt-only blocks in a separate file that only NeoMutt sources:
# neomuttrc
source ~/.config/mutt/muttrc # the shared, Mutt-compatible config
source ~/.config/neomutt/extras.rc # NeoMutt-only features
# extras.rc: only apply settings if the feature exists in this build
ifdef sidebar_visible 'set sidebar_visible = yes'
ifdef nm_query_type 'source ~/.config/neomutt/notmuch.rc'
ifndef lua-source 'echo "built without Lua"'
finish (stop reading the current file) is also available, for guard clauses like ifndef nm_query_type finish.
Sidebar and mailbox naming¶
set sidebar_visible = yes
set sidebar_width = 30
set sidebar_short_path = yes
set sidebar_folder_indent = yes
set sidebar_format = "%D%?F? [%F]?%* %?N?%N/?%S"
set sidebar_non_empty_mailbox_only = no
set mail_check_stats = yes # needed for the counts in sidebar_format
# Friendly names instead of raw IMAP paths (NeoMutt only)
named-mailboxes "Inbox" "+INBOX"
named-mailboxes "Work" "+Folders/Work"
named-mailboxes "Archive" "+Archive"
bind index,pager \CP sidebar-prev
bind index,pager \CN sidebar-next
bind index,pager \CO sidebar-open
bind index,pager B sidebar-toggle-visible
In sidebar_format: %D is the descriptive name, %N new count, %S total, %F flagged, %* padding to the right edge, and %?X?…? shows … only when X is non-zero.
notmuch: search and tag-based folders¶
notmuch indexes a local Maildir (typically kept in sync by mbsync, see Mutt → Offline mail) and makes full-text search across years of mail instant. NeoMutt can browse notmuch queries as if they were folders.
sudo dnf install notmuch # or apt install notmuch
notmuch setup # point it at ~/Mail, set your name and addresses
mbsync -a && notmuch new # sync then index; run both from a timer
# notmuch.rc
# Point NeoMutt at the database. Depending on your NeoMutt version this is
# $nm_default_url or a notmuch:// $folder. `neomutt -D | grep '^nm_'` shows what your build has.
set nm_default_url = "notmuch:///home/you/Mail"
# Virtual mailboxes are saved notmuch queries
virtual-mailboxes \
"Inbox" "notmuch:///home/you/Mail?query=tag:inbox" \
"Unread" "notmuch:///home/you/Mail?query=tag:unread" \
"Flagged" "notmuch:///home/you/Mail?query=tag:flagged" \
"Last 7d" "notmuch:///home/you/Mail?query=date:7d..&limit=500"
set nm_query_type = threads # show whole threads, not just matching messages
set nm_record = yes # index mail you send
set nm_record_tags = "-inbox +sent"
# \ = ad-hoc search, + = expand the full thread from the archive
macro index \\ "<vfolder-from-query>" "notmuch search"
bind index,pager + entire-thread
# Tag editing
macro index,pager A "<modify-labels>-inbox -unread<enter>" "archive (notmuch)"
macro index,pager S "<modify-labels>+spam -inbox<enter>" "mark spam (notmuch)"
Query syntax is notmuch's own: from:alice subject:invoice date:2025.., tag:inbox and not tag:lists, attachment:pdf, "exact phrase". Run notmuch search on the command line to try a query before saving it.
Header cache and IMAP performance¶
set header_cache = "~/.cache/neomutt/headers/"
set header_cache_backend = lmdb # fastest common choice; must be compiled in
set header_cache_compress_method = zstd # if built with zstd; shrinks the cache a lot
set message_cachedir = "~/.cache/neomutt/bodies/"
set imap_qresync = yes # fast resync on servers supporting QRESYNC (Dovecot, Fastmail, …)
set imap_condstore = yes
set imap_idle = yes # push notifications instead of polling, where supported
A trailing / on header_cache makes it a directory holding one cache per mailbox, which is the right choice for IMAP.
Other NeoMutt-only conveniences¶
- Conditional date formats:
%<X?then&else>blocks (which can nest) make a date column show the time for today's mail and the date otherwise:set index_format = "%4C %Z %<[1d?%[%H:%M]&%[%b %d]> %-20.20F %s" index-format-hook: compute a column from a pattern (for example, show a tag only on list mail).cd: change the working directory from inside NeoMutt (where saved attachments go).$new_mail_command: run a command (a desktop notification, for example) when new mail arrives:set new_mail_command = "notify-send 'New mail' '%n new in %f'"- Lua (if built with
+lua):lua-source ~/.config/neomutt/init.luagives scriptable access to config and commands. This is useful for logic that's awkward in muttrc syntax. - Richer colour objects: individual index columns (
index_author,index_subject,index_date,index_flags…) can be coloured separately.
Debugging¶
neomutt -v # version + compile options
neomutt -D # dump the effective configuration
neomutt -n -F /dev/null # start with no config at all
neomutt -d 2 -l ~/neomutt-debug.log # debug log at level 2 (1–5)
As with Mutt, debug levels of 3 and above can capture credentials and message contents. Delete the log afterwards.
Inside NeoMutt, :set ?var shows a value and :set var=value tries a change live. The <show-log-messages> function displays the recent message history. Bind it to a key (bind index,pager <f12> show-log-messages) for warnings that flash past on the status line.