  toggle dark mode toggle dark mode

Creating a local email setup with mbsync + msmtp + neomutt + notmuch.

posted on 2020-02-04T07:25:41Z · last modified on 2020-12-21T09:25:24Z · view page on GitHub
tags: linux (2)

Neomutt is a powerful terminal email client. Using neomutt as my email client has been a real pleasure, however configuring it turns out to be a bit of a pain; there are a lot of pieces that need to fall into place. Consider this post a tutorial on how I configured Neomutt to be my email interface, while I use mbsync for syncing my email, msmtp to send email and notmuch to index my email for efficient searching.

Note: My computer uses the pacman package manager, so every time you see it being used do some googling to find the equivalent package manger command that works for you.

Setting up pass

To be able to store your email passwords securely, you need to setup gpg and pass.

sudo pacman -S gnupg pass

gpg is an executable that creates the public/private key pair, needed to encrypt your password. You can create a keypair as follows:

gpg --full-gen-key

Use the default options (you can set an expiry date on your key if you want) and give your contact information. The email address for the contact information is allowed to be different from the email address you'll be adding into Neomutt. Just remember which email address you picked. We'll call the email provided here gpgemail.

After giving all the information, the key should be automatically created.

Next, initialize pass.

pass init

Now, store a password entry for the email you want to add to mutt. Note again that this email is allowed to be different from your gpgemail. In the following, we will call this email your muttemail.

pass insert <muttemail>

It will ask you for the [imap] password corresponding to the email provided.

Anytime you want to add a new email to mutt, don't forget to add it's password to pass first.

setting up mbsync

To fetch mail from the server using imap, you need isync/mbsync (isync is the name of the project, mbsync is the name of the executable.)

sudo pacman -S isync

Since mbsync is the name of the executable, I prefer to call it like that.

mbsync requires to be configured with a ~/.mbsyncrc. A typical configuration looks as follows (replace the content between <,> with values provided by your email provider; note that muttemail-username, most likely is equal to muttemail.):

IMAPStore <muttemail>-remote
Host <imap.host.tld>
Port <993>
User <muttemail-username>
PassCmd "pass <muttemail>"
CertificateFile /etc/ssl/certs/ca-certificates.crt

MaildirStore <muttemail>-local
Subfolders Verbatim
Path ~/.local/share/email/<muttemail>/
INBOX ~/.local/share/email/<muttemail>/INBOX
Flatten .

Channel <muttemail>
Master :<muttemail>-remote:
Slave :<muttemail>-local:
Patterns INBOX Drafts Sent Trash
SyncState *
Create Both
Expunge Both
MaxMessages 0

Note: Google blocks most external apps by default. Make sure to enable access to less secure apps, or - if you have 2FA enabled - create an app password.

Note 2: The Patterns keyword allows you to choose which imap folders to sync. If you want to sync all folders, use a single * as argument. However, I like to be explicit here, as many email providers (looking at you Gmail 👀), have just way to many folders. Conversely, if syncing with *, you can exclude folders by prepending them with a !.

Note 3: See also the excellent ArchWiki post on isync for more configuration options and ideas.

Finally, create the folder ~/.local/share/email/<muttemail>.:

mkdir -p ~/.local/share/email/<muttemail>

and start syncing your email:

mbsync <muttemail>

Setting up msmtp

While your email is synchronizing, we can go on setting up how to send emails. For this, we will use msmtp (again, replace the content between <,> with values provided by your email provider and note that muttemail-username most likely is equal to muttemail.)

sudo pacman -S msmtp

Next, msmtp is supposed to be configured at ~/.msmtprc. Create and edit this file as follows (as usual, change the values between <,> to sensible defaults):

auth on
tls <on/off>
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.config/msmtp/msmtp.log

account <muttemail>
host <smtp.host.tld>
port <587/465/...>
tls_starttls <on/off>
from <muttemail>
user <muttemail-username> 
passwordeval "pass <muttemail>"

Make the configuration only readable by the owner (only msmtp refuses to work):

chmod 600 ~/.msmtprc

Test the configuration by sending an email to another emailadress you own:

echo "this is some content" | msmtp -a <muttemail> -- <recipient>

If the email arrives, everything is configured correctly.

Setting up neomutt

We have email sync working with mbsync and we can send emails with msmtp. Now the only thing that needs setting up is the interface: neomutt, which is an improved fork of the mutt email client.

sudo pacman -S neomutt

neomutt can be configured in ~/.config/mutt/muttrc. The basic configuration for our setup looks as follows:

## Account settings
set from = <muttemail>
set realname = "<Your Name>"

set mbox_type = Maildir
set folder = "~/.local/share/email/<muttemail>"

set sendmail = "msmtp -a <muttemail>"

# cache settings
set header_cache = "~/.cache/mutt/<muttemail>/header_cache"
set message_cachedir = "~/.cache/mutt/<muttemail>/message_cache"

# mailbox settings
set spoolfile = +INBOX
set postponed = +Drafts
set record = +Sent
set trash = +Trash

# navigation settings
bind index,pager g noop
macro index,pager gi "<change-folder>=INBOX<enter>" "go to inbox"
macro index,pager gs "<change-folder>=Sent<enter>" "go to sent"
macro index,pager gd "<change-folder>=Drafts<enter>" "go to drafts"
macro index,pager gt "<change-folder>=Trash<enter>" "go to trash"

# synchronization settings ['s' to sync]
macro index S "<shell-escape>mbsync -V <muttemail><enter>" "sync email"

These are what I call the account synchronization settings. They tell mutt who you are, where your mail is stored and cached, what the names of your most important folders are (INBOX, Drafts, Sent and Trash in this case). How to navigate between these folders (gi, gs, gd and gt respectively) and finally it defines a keyboard shortcut to sync your email (s in this case).

However, this is a bare minimum rcfile. You can configure it more. The rest of my configuration looks as follows. These settings are all independent from my account, which is why i originally called them "Other Settings".

## Other Settings
set mail_check_stats
set sort = 'reverse-date'
set sidebar_visible = no
set sidebar_width = 20
set sidebar_short_path = yes
set sidebar_next_new_wrap = yes
set sidebar_format = '%B%?F? [%F]?%* %?N?%N/? %?S?%S?'
bind index,pager \Ck sidebar-prev
bind index,pager \Cj sidebar-next
bind index,pager \Cl sidebar-open
bind index,pager b sidebar-toggle-visible
set markers = no # Disables the `+` displayed at line wraps
set mime_forward = yes # attachments are forwarded with mail
set wait_key = no # mutt won't ask "press key to continue"
set fast_reply # skip to compose when replying
set fcc_attach # save attachments with the body
set forward_format = "Fwd: %s" # format of subject when forwarding
set forward_quote # include message in forwards
set reverse_name # reply as whomever it was to
set include # include message in replies
color header blue default ".*"
color header brightgreen default "^(From)"
color header brightcyan default "^(Subject)"
color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses
color header brightwhite default "^(To|CC|BCC)"
color body brightblue default "(https?|ftp|file)://[\-\.,/%~_:?&=\#a-zA-Z0-9;+]+" # URL

These settings allow you to toggle a sidebar (by pressing b) and navigate the sidebar (<control>+j/k/l). In addition to that, some basic settings (see comments) and some basic coloring of emails based on regular expressions were also added.

Integration with Lynx for html view

Finally we can choose for a barebones html view (many emails are html only nowadays). For this we need to download lynx

sudo pacman -S lynx

then make a mailcap file at ~/.config/mutt/mailcap with contents:

text/html; <your-preferred-gui-browser> %s;
text/html; lynx -assume_charset=%{charset} -display_charset=utf-8 -dump %s; nametemplate=%s.html; copiousoutput

And add the following lines to your muttrc:

auto_view text/html
set mailcap_path = ~/.config/mutt/mailcap

Mutt will now choose to view the text/html entry of the email by default, however it will not be able to do so with the first entry in the mailcap, since this is a GUI browser. It will opt for the second entry instead: lynx. However, the latter does not display any images and styles, so it might still be valuable to be able to open them using the specified GUI browser. This can be done by tapping v to open the attachments of the email, selecting text/html and finally pressing m to open with the preferred mailcap method: your browser.

If this is too much effort, you can add the following macro:

macro index,pager B "<view-attachments><search>html<enter><view-mailcap><exit>"

which will open the e-mail using the default browser specified in mailcap by pressing <shift>+b.

Multiple Accounts

The above setup configured Mutt for a single account. If you have multiple email adresses, you can configure mutt to work with multiple accounts.

To do this, you first have to go to the process of setting up pass, mbsync, and msmtp for your <new-muttemail>.

Next, you need to isolate the account-specific settings (everything in the ## Account settings section, up until ## Other settings) from the muttrc into a seperate account-specific rcfile. let's call those files


And replace the account section in your main muttrc file by:

## Account settings
source ~/.config/mutt/<muttemail>.rc
bind index,pager a noop
macro index,pager a1 '<sync-mailbox><enter-command>source ~/.config/mutt/<muttemail>.rc<enter><change-folder>!<enter>;<check-stats>' "switch to <muttemail>"
macro index,pager a2 '<sync-mailbox><enter-command>source ~/.config/mutt/<new-muttemail>.rc<enter><change-folder>!<enter>;<check-stats>' "switch to <new-muttemail>"

This makes sure that at startup the mailbox for <muttemail> is opened and that you can switch between mailboxes with a1 for <muttemail> and a2 for <new-muttemail>.

Mail indexing with notmuch

In fact, after everything we've don so far, you should have a functional email setup. You can check it out for yourself by typing neomutt in a terminal. Syncing your email can be done with shift+S (this is a custom keyboard shortcut we defined in our muttrc). Sending a new email can be done with m. Type ? to see the complete list of keyboard shortcuts.

However, when you have a lot of emails, one thing that's not yet completely working as we'd like is searching for emails. For this, we'll use the email indexer notmuch:

sudo pacman -S notmuch

To configure notmuch, create and edit ~/.notmuch-config as follows (replace <username> by your unix username):


then type

notmuch new

To initialize the notmuch database. Finally, muttrc needs to be updated. First of all, edit the following line:

macro index S "<shell-escape>mbsync -V <muttemail><enter>" "sync email"

into this one:

macro index S "<shell-escape>mbsync -V <muttemail><enter><shell-escape>notmuch new<enter>" "sync email"

This way, the notmuch email index will be updated every time you sync your email through neomutt. Also, the following line should be added to have a ctrl+f keyboard shortcut to search for email with notmuch (which is the whole point of adding notmuch in the first place):

macro index \Cf "<enter-command>unset wait_key<enter><shell-escape>read -p 'Enter a search term to find with notmuch: ' x; echo \$x >~/.cache/mutt_terms<enter><limit>~i \"\`notmuch search --output=messages \$(cat ~/.cache/mutt_terms) | head -n 600 | perl -le '@a=<>;s/\^id:// for@a;$,=\"|\";print@a' | perl -le '@a=<>; chomp@a; s/\\+/\\\\+/ for@a;print@a' \`\"<enter>" "show only messages matching a notmuch pattern"

This line was litterally copied from the mutt-wizard.


A lot of this post was inspired by the procedure implemented by the mutt-wizard. My personal preference is to do this procedure manually, as it gives me a lot more control over the exact settings I want to use. However, if you're looking for a tool that does most (but not all) of the above configuration automatically, it's worth checking it out.

If you like this post, consider leaving a comment or star it on GitHub.