In one of my first posts about building an optimized workflow, I briefly mentioned neomutt was a program who’s configuration deserved a post all its own. This is that post.

Much like weechat, Neomutt is an extremely powerful tool but it needs a bit of customization to make it more “user friendly”.

On Arch we can install Neomutt with pacman -Syu neomutt

You have probably seen tons of tutorials about setting up offlineIMAP or a similar service. I personally opt to connect directly to the IMAP server as its less of a hassle. Maybe there is a good reason to do the whole offline sync thing but I haven’t found it.

You may have heard of a muttrc or neomuttrc . Like a vimrc , these files define the settings for neomutt. I place my neomuttrc in ~/.config/neomutt/ because its where most programs store their config files.

However much like my custom neovim configuration, the main configuration file will simply be used to source the discrete configuration files containing specific configurations.

# vim: filetype=muttrc source ~/.config/neomutt/settings source ~/.config/neomutt/colors source ~/.config/neomutt/mappings # Accounts source ~/.config/neomutt/accounts/gmail folder-hook $folder 'source ~/.config/neomutt/accounts/gmail' source ~/.config/neomutt/accounts/school folder-hook $folder 'source ~/.config/neomutt/accounts/school' source ~/.config/neomutt/accounts/main folder-hook $folder 'source ~/.config/neomutt/accounts/main'

In the above neomuttrc file, I source three files: settings for general program configuration, colors to adjust colors, and mappings to store custom keybinds.

Additionally, in the accounts folder, I have a configuration file for each of the email accounts I want to use with neomutt. We will get to that configuration later.

General Settings⌗

Here is where we can declare some universal settings for neomutt that change core program behavior.

# vim: filetype=muttrc # set editor to neovim set editor = "nvim" set my_name = "Gideon Wolfe" set imap_check_subscribed # Set preffered view modes auto_view text/html text/calendar application/ics # view html automatically alternative_order text/html text/plain text/enriched text/* # main options set envelope_from set edit_headers # show headers when composing set fast_reply # skip to compose when replying set askcc # ask for CC: set fcc_attach # save attachments with the body set forward_format = "Fwd: %s" # format of subject when forwarding set forward_decode # decode when forwarding set attribution = "On %d, %n wrote:" # format of quoting header set reply_to # reply to Reply to: field set reverse_name # reply as whomever it was to set include # include message in replies set forward_quote # include message in forwards set text_flowed unset sig_dashes # no dashes before sig unset mime_forward # forward attachments as part of body unset help # No help bar at the top of index # set status_on_top # Status bar on top of index set tmpdir = ~/Programs/neomutt/temp # where to keep temp files unset confirmappend # don't ask, just do! set quit # don't ask, just do!! unset mark_old # read/new is good enough for me set beep_new # bell on new mails set pipe_decode # strip headers and eval mimes when piping set thorough_search # strip headers and eval mimes before searching set timeout = 0 # status bar, date format, finding stuff etc. set status_chars = " *%A" set status_format = "[ Folder: %f ] [%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]%>─%?p?( %p postponed )?" set date_format = "%d.%m.%Y %H:%M" set sort = threads set sort_aux = reverse-last-date-received set uncollapse_jump set sort_re set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*" set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+" set send_charset = "utf-8:iso-8859-1:us-ascii" set charset = "utf-8" set arrow_cursor = "no" # Change `color indicator` depending # Pager View Options set pager_index_lines = 10 # Shows 10 lines of index when pager is active set pager_context = 3 set pager_stop set menu_scroll set tilde unset markers set mailcap_path = ~/.config/neomutt/mailcap set header_cache = "~/.cache/mutt" set message_cachedir = "~/.cache/mutt" set query_command = "khard email --parsable --search-in-source-files '%s'"

I’ll go over some of the important parts, and the things people might often want to change:

editor is set to neovim, so I can write all my emails with vim.reaper!

is set to neovim, so I can write all my emails with vim.reaper! query_command hooks in with the contact manager khard , which I wrote about here. Tab complete your contacts!

hooks in with the contact manager , which I wrote about here. Tab complete your contacts! help is unset so the top bar disappears. Just press ? if you need to see keybindings.

is unset so the top bar disappears. Just press if you need to see keybindings. Optionally set status_on_top to see the status bar on top. Personally I like it on the bottom, as that’s where weechat puts it.

to see the status bar on top. Personally I like it on the bottom, as that’s where weechat puts it. arrow_cursor can be enabled to have an arrow point to the currently selected message. I prefer the line as it’s more space efficient.

If you’re curious about any configuration variable, search this page and you can find a description.

This file contains the color settings for various elements within neomutt.

# vim: filetype=muttrc # Header colors: color header blue default ".*" color header brightmagenta default "^(From)" color header brightcyan default "^(Subject)" color header brightwhite default "^(CC|BCC)" mono bold bold mono underline underline mono indicator reverse mono error bold color normal default default color indicator brightyellow default # currently selected message. default makes bar clear, disabled arrow to save space. color sidebar_highlight red default color sidebar_divider brightblack black color sidebar_flagged red black color sidebar_new green black color normal brightyellow default color error red default color tilde black default color message cyan default color markers red white color attachment white default color search brightmagenta default color status brightyellow black color hdrdefault brightgreen default color quoted green default color quoted1 blue default color quoted2 cyan default color quoted3 yellow default color quoted4 red default color quoted5 brightred default color signature brightgreen default color bold black default color underline black default color normal default default color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL color body green default "\`[^\`]*\`" # Green text between ` and ` color body brightblue default "^# \.*" # Headings as bold blue color body brightcyan default "^## \.*" # Subheadings as bold cyan color body brightgreen default "^### \.*" # Subsubheadings as bold green color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow color body brightcyan default "[;:][-o][)/(|]" # emoticons color body brightcyan default "[;:][)(|]" # emoticons color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon? color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon? color body red default "(BAD signature)" color body cyan default "(Good signature)" color body brightblack default "^gpg: Good signature .*" color body brightyellow default "^gpg: " color body brightyellow red "^gpg: BAD signature from.*" mono body bold "^gpg: Good signature" mohttps://neomutt.org/code/config_vars.htmlno body bold "^gpg: BAD signature from.*" color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r

<>\"]" # Default index colors: color index yellow default '.*' color index_author red default '.*' color index_number blue default color index_subject cyan default '.*' # For new mail: color index brightyellow black "~N" color index_author brightred black "~N" color index_subject brightcyan black "~N" color progress black cyan

Here are some of the highlights (pun very intended):

color indicator changes the color of the highlighted message line, or the arrow if arrow_cursor is enabled.

changes the color of the highlighted message line, or the arrow if is enabled. neomutt does colors by layering. For example you might assign one color to the whole index , and then manually add different colors for new mail, from address, etc.

, and then manually add different colors for new mail, from address, etc. The various color body settings assign specific colors to anything matching a given regular expression, from list items to emoticons.

These colors look good with my pywal generated themes, and are easy to read without being too hard on the eyes. Here is a reference for coloring the index page if you want to make any tweaks.

On any page in neomutt, press ? to get a full list of defined mappings for that page.

neomutt assigns mappings on a view basis. For example you could have a specific set of keybinds for when you are viewing an inbox (the index view) and another set for actually reading a message ( pager view).

Many keybinds can be assigned to multiple views by listing the views we want to pick.

Here is the contents of my mappings file:

# vim: filetype=muttrc # General rebindings bind attach <return> view-mailcap bind attach l view-mailcap bind editor <space> noop bind pager c imap-fetch-mail bind index G last-entry bind index g noop bind index gg first-entry bind pager,attach h exit bind pager j next-line bind pager k previous-line bind pager l view-attachments bind index D delete-message bind index U undelete-message bind index L limit bind index h noop bind index l display-message bind browser h goto-parent bind browser l select-entry bind pager,browser gg top-page bind pager,browser G bottom-page bind index,pager,browser d half-down bind index,pager,browser u half-up bind index,pager R group-reply bind index \031 previous-undeleted # Mouse wheel bind index \005 next-undeleted # Mouse wheel bind pager \031 previous-line # Mouse wheel bind pager \005 next-line # Mouse wheel bind editor <Tab> complete-query # sidebar mappings bind index,pager \Ck sidebar-prev bind index,pager \Cj sidebar-next bind index,pager \Co sidebar-open bind index,pager \Cp sidebar-prev-new bind index,pager \Cn sidebar-next-new bind index,pager B sidebar-toggle-visible # global index and pager shortcuts bind index,pager @ compose-to-sender bind index,pager D purge-message bind index <tab> sync-mailbox bind index <space> collapse-thread # Email completion bindings bind editor <Tab> complete-query bind editor ^T complete # Press A to add contact to Khard address book macro index,pager A \ "<pipe-message>khard add-email<return>" \ "add the sender email address to khard" ## Shortcuts macro index,pager <f2> '<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/gmail<enter><change-folder>!<enter>' macro index,pager <f3> '<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/main<enter><change-folder>!<enter>' macro index,pager <f4> '<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/school<enter><change-folder>!<enter>'

The main differences between my config and the default:

vim keybinds! k and j to go up and down, and l and h to move forwards and back pages.

and to go up and down, and and to move forwards and back pages. Open the sidebar with B . Ctrl+j and Ctrl+k to navigate, Ctrl+o to open selection

. and to navigate, to open selection A will attempt to create a new contact with khard .

will attempt to create a new contact with . F2 , F3 , and F4 are used to switch between my three mailboxes

I put the important binds in a little cheatsheet table for myself!

Function Keybind Go to last entry G Go to first entry gg Page down d Page up u Delete message D Delete thread Ctrl+d Mark thread read Ctrl+r Undelete message U Limit/Filter L Open message l , Enter Group reply R Reply r Forward message f New message m View attachments v Compose to Sender @ Resend message Esc+e Save message (to file) s Toggle collapse thread Space , Esc+v Toggle collapse all threads Esc+V Add contact to Khard A Jump to parent message P Email PGP public key Esc+k

Function Keybind Bottom of page G Top of page gg Next line j Previous line k View attachments l Page down d Page up u Group reply R , g Reply r Compose to Sender @ Delete thread Ctrl+d Mark thread read Ctrl+r Mark thread new N

Function Keybind Show sidebar B Up Ctrl+k Down Ctrl+j Open Ctrl+o Open next new Ctrl+n Open previous new Ctrl+p

This file defines which programs should handle various filetypes included in email attachments.

# MS Word documents application/msword; ~/dotfiles/office/view-attachment.sh %s "-" '/Applications/LibreOffice.app' application/vnd.ms-excel; ~/dotfiles/office/view-attachment.sh %s "-" '/Applications/LibreOffice.app' application/vnd.openxmlformats-officedocument.presentationml.presentation; ~/dotfiles/office/view-attachment.sh %s "-" '/Applications/LibreOffice.app' application/vnd.oasis.opendocument.text; ~/dotfiles/office/view-attachment.sh %s "-" '/Applications/LibreOffice.app' # HTML text/html; w3m -I %{charset} -T text/html; copiousoutput; text/plain; nvim %s #PDFs application/pdf; /usr/bin/zathura %s pdf #Images image/png; /usr/bin/feh %s image/jpeg; /usr/bin/feh %s

I use feh as a lightweight image viewer

as a lightweight image viewer All MS office docs are handled by LibreOffice

zathura reads my PDFs (with style)

reads my PDFs (with style) HTML is rendered as text with w3m

I won’t go over the specifics of each account here, because getting neomutt to actually talk to your mailserver is another matter entirely, for which there are dozens of tutorials.

Here is a generic template for hooking up an IMAP account.

# vim: filetype=muttrc unmailboxes * # in/out mail servers set realname = "Firstname Lastname" set imap_pass = "SOME_PASSWORD" set smtp_url = "smtps://you@somedomain.com@mailserver.com:465" set smtp_pass = "SOME_PASSWORD" set folder = "imaps://you@somedomain.com@mailserver.com:993" set spoolfile = "+INBOX" set from = "you@somedomain.com" set envelope_from set use_from = "yes" set record = "+Sent" set trash = "+Trash" set postponed = "+Drafts" set mail_check = 6 # Allow Mutt to open a new IMAP connection automatically. unset imap_passive # Keep the IMAP connection alive by polling intermittently (time in seconds). set imap_keepalive = 300 ## Hook -- IMPORTANT! account-hook $folder "set imap_pass=SOME_PASSWORD"

unmailboxes * hides the inboxes of accounts we are not currently viewing.

hides the inboxes of accounts we are not currently viewing. account-hook is the line that allows us to switch to this account with a keybind.

And that’s basically it. If you have done everything correctly, you should be able to use neomutt to interact with multiple email accounts, switching with just a keypress.

The colors should look good, and the keybinds should feel natural to a vim user. I am constantly improving this setup so don’t hesitate to throw me some suggestions.