Many of us have have multiple email accounts, reflecting the different groups and organisations that we're part of. At the very least, it's common to have a work and a personal account. Today we'll look at how to run multiple accounts with NeoMutt. The easiest way to do this is to run separate instances of NeoMutt with one account for each one, but in this post we'll configure the more common method of being able to see multiple accounts in a single instance of NeoMutt. This will also mean we'll have to configure sending through the correct SMTP server for each account.
We'll also explore using maildir and how to make NeoMutt look cooler with themes and colours!
This post builds on part 1 where we configured NeoMutt's basic settings, and part 2 where we set-up NeoMutt's native IMAP. To follow along with this post you'll need two email accounts.
Last time the configuration ended up like this:
# vim: ft=muttrc fdm=marker foldcolumn=2 set header_cache = ~/.cache/neomutt/cache/ # where to store headers set message_cachedir = ~/.cache/neomutt/cache/ # where to store bodies set header_cache_compress_method = "zstd" set header_cache_compress_level = 3 set message_cache_clean = yes # not recommended to set this! set tmpdir = /tmp set from = <username>@<domain> set real_name = "My Name" set use_threads = yes # show email in threads in the Index set sort = reverse-last-date-received set sort_aux = reverse-last-date-received set pager_index_lines = 6 # show this many lines of the Index when # reading email set pager_context = 3 # lines of context between pages set pager_stop = yes # don't scroll of the end of one message onto # the next unset markers # don't show + for wrapped lines in the pager set mark_old = no # don't show 'new' emails as old, if user has set edit_headers = yes # allow user to edit message headers set editor = "vim" # define which editor to use set fast_reply = yes # skip initial prompts when replying set include = yes # include the message we're replying to set sidebar_visible = yes set sidebar_width = 15 # width in screen columns set sidebar_next_new_wrap = yes # wrap around the list when scrolling setenv PINENTRY_USER_DATA curses # ask for the password in the terminal set imap_pass="`gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/sec.gpg`" # new email continues to come from the IMAP server set spool_file = imaps://user@email.domain@mail.runbox.com # default location is set to the local filesystem set folder = ~/mail set record = +Sent set postponed = +Drafts set trash = !Trash set mail_check = 120 # time in seconds between mail checks set timeout = 30 # time to wait for user input set mail_check_stats = yes set mail_check_stats_interval = 120 # calculate every 120 secs set imap_idle = yes set new_mail_command="notify-send --app-name=Neomutt --icon='~/.config/neomutt/NeoMutt.png' \ --urgency=low --expire-time=3000 'New Email in %D' &" mailboxes -label Inbox -notify -poll ! \ -label Drafts -nonotify -nopoll =Sent \ -label Archive -nonotify -nopoll =Archive \ -label Sent -nonotify -nopoll =Sent smtp_url = smtps://user@email.domain@mail.runbox.com smtp_auth = "`gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/sec.gpg`"
Remember, we're only configuring the minimum settings as NeoMutt has a good set of defaults, and we're trying to avoid over-complicating things.
The mbox format can be risky if there are large files for a mailbox as the file could become corrupted. For example lets say you have a Sent folder that has email you've sent from the last 10 years, ideally we don't want to risk all those emails in a single file. I don't have particular issues with mbox, but personally I prefer the Maildir format. It uses one file for each email which means the risk of losing an email is a bit more spread out. It also avoids state so you can easily synchronise email between machines (I don't do this, but it's a nice idea!).
To use maildir set the mbox_type:
set mbox_type = maildir
If it complains that a mailbox doesn't exist (for example Sent) don't worry as it will create it as soon as you initially send an email.
Everybody likes some theming, and NeoMutt has lots of theming features. There are some colour themes bundled with NeoMutt in share/neomutt/colorschemes, on Guix they're in $GUIX_PROFILE/share/neomutt/colorschemes. The ones that are bundled are:
To use them use the source command which includes the configuration from another file. See Figures 1-4 for screenshots of each theme in action!
Using the source command is a great way to break up configuration into logical units and is going to be important for setting up multiple accounts. To use it for setting colours:
source $GUIX_PROFILE/share/neomutt/colorschemes/zenburn.neomuttrc source $GUIX_PROFILE/share/neomutt/colorschemes/vombatidae.neomuttrc
Stefan Huber created a mutt-gruvbox which I also really like. Remember that you have to have a 256 colour capable terminal and that the terminal's $TERM environment variable has to be set. NeoMutt also supports 24-bit TrueColor that relies on both (at least I have to set both!) detecting the right TERM and configuring NeoMutt. There aren't any TrueColor themes in the default bundle but they are some on Github, download NeoMutt Gruvbox Truecolor. Then set the following in neomuttrc:
color_directcolor = yes source ~/.config/neomutt/truecolor-gruvbox.neomuttrc
As color_directcolor is boolean it can be either yes or no. I found I also had to set a TERM variable, by starting XTerm and doing the following:
# set term and start neomutt TERM=xterm-direct neomutt
The best way to configure this is probably to create a shell alias. See Figure 5 for a screenshot of the theme.
It's common to have multiple email accounts, for example a work and personal one. There previously wasn't great support for reading email from multiple accounts, but as NeoMutt has extended the URL syntax to support specifying a remote host and the associated username we can have multiple accounts.
For the purposes of this example we'll pretend that we have one email account on Runbox, and another on Gmail.
Before we set up the mailboxes for the two accounts we have to figure out how to retrieve the passwords for the two different IMAP servers. NeoMutt has an account_command feature which calls an external program to retrieve account credentials. The NeoMutt source code has an option for using a GPG-based JSON database, which would be really nice - but I ran into some problems with it (https://github.com/neomutt/neomutt/pull/4616) which should be fixed in later releases.
For now I've re-used a script that himitsu-mutt created. This uses the format that the account_command variable is expecting. As we know the host part of the URL we're setting in neomuttrc, we look for this and use GnuPG to decrypt the secret. Here's the altered shell script:
#!/usr/bin/env bash set -eu while [ $# -gt 0 ]; do case $1 in --hostname) HOSTNAME="$2" shift # past argument shift # past value ;; --username) USERNAME="$2" shift # past argument shift # past value ;; --type) PROTO="$2" shift # past argument shift # past value ;; *) echo "Unknown argument $1" >> $LOG 2>&1 exit 1 ;; esac done if [ $HOSTNAME == "mail.runbox.com" ]; then PASS=`gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.config/neomutt/runbox-sec.gpg` echo "password: $PASS" fi if [ $HOSTNAME == "imap.googlemail.com" ] || [ $HOSTNAME == "smtp.gmail.com" ]; then PASS=`gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.config/neomutt/gmail-sec.gpg` echo "password: $PASS" fi
After processing the arguments that NeoMutt provides the script checks the $HOSTNAME variable. If it's "mail.runbox.com" it unlocks the runbox secret that was previously encrypted using GnuPG, if it's either "imap.googlemail.com" or "smtp.gmail.com" then it unlocks the gmail secret.
The following configuration is added to neomuttrc:
setenv PINENTRY_USER_DATA curses set account_command = /home/user/bin/neomutt-pw.sh set mbox_type = maildir set spool_file = ~/.mail/inbox set folder = ~/mail set record = +Sent set postponed = +Drafts set trash = !Trash mailboxes -label R:Inbox -notify -poll imaps://user@email.domain@mail.runbox.com/INBOX -label G:Inbox -notify -poll imaps://user@gmail.com@imap.googlemail.com/INBOX \ -label L:Drafts -nonotify -nopoll =Drafts
Remember to remove the old imap_pass setting that's in the current configuration, and replace it with the new account_command which accepts a command (a path to the shell script). Note that spool_file must be set to point to some form of mailbox file otherwise NeoMutt won't start.
The mailboxes line is doing the main work, notice that I'm using a label of R for Runbox (e.g. R:Inbox), G for Google (e.g. G:Inbox), and L for local (e.g L:Drafts). The labels can be anything you want, I've kept them short to stay within the limited number of characters that have been given to the Sidebar.
This is great, we can now read email from multiple accounts by using the mixture of the URL syntax and mailboxes capability. One problem is that we can't actually send email through both accounts!
The reason we can't send email from the two accounts is that we can only have one SMTP server defined at a time (using $smtp_url). To send email through each account requires the $smtp_url to be configured to the SMTP server of that account.
One option to solve this is to have two different configurations and to start two instances of NeoMutt, see ArchLinux Wiki article on NeoMutt - Alternative Way. This would mean having an instance of Mutt for work email with the $smtp_url variable configured to use the work provider's SMTP server. And, in a different terminal an instance running for personal email, where the $smtp_url would point to the personal SMTP server. The upside of this approach is simplicity.
The other way is to use hooks to change NeoMutts behaviour depending on whether we're in one account or another. Both work and personal email will be visible in the same instance of NeoMutt. When we send email NeoMutt will choose which SMTP server to use. The upside of this approach is having all email accounts in one instance of NeoMutt, but it does involve a more complex configuration. To make this work requires NeoMutt's hook capabilities.
NeoMutt uses the concept of a hook to execute user-defined commands before an operation. There are lots of situations where a user can define a hook, for example save-hook, send-hook, startup-hook, and shutdown-hook - for a full list see the NeoMutt Guide's Using Hooks section.
The first step is to define two IMAP servers using the mailboxes command, and use a folder-hook to change settings each time the user moves between the two IMAP server folders. A folder-hook is a hook that's activated when the user switches into a new folder (mailbox). Each time the hook runs we can execute any changes to the configuration that we want, for example changing the $from address.
In the neomuttrc file add the following:
set spool_file = ~/.mail/inbox set mbox_type = maildir # these mailbox shortcuts are used in Local mailboxes set folder = ~/.mail set record = +Sent set postponed = +Drafts set Trash = +Trash # Account 1 (Runbox): mailboxes and folder-hook mailboxes -label R:Inbox -notify -poll imaps://user@email.domain@mail.runbox.com/INBOX \ -label R:Sent -nonotify -poll imaps://user@email.domain@mail.runbox.com/Sent \ -label R:Trash -nonotify -nopoll imaps://user@email.domain@mail.runbox.com/Trash folder-hook imaps://user@email.domain@mail.runbox.com/ 'source ~/config/neomutt/runbox-account-neomuttrc' # Account 2 (Gmail): mailboxes and folder-hook mailboxes -label G:Inbox -notify -poll imaps://user@gmail.com@imap.googlemail.com/INBOX \ -label G:Sent -nonotify -poll imaps://user@gmail.com@imap.googlemail.com/Sent folder-hook imaps://user@gmail.com@imap.googlemail.com/ 'source ~/.config/neomutt/gmail-account-neomuttrc' # Local mailboxes mailboxes -label L:Drafts -nonotify -nopoll =Drafts \ -label L:Sent -nonotify -nopoll =Sent folder-hook ~/.mail 'source ~/.config/neomutt/local-account-neomuttrc'
Each folder-hook is triggered by NeoMutt loading a mailbox that matches. The hook specifies two parts, the first is a folder to match against, the second is a command (or commands) to run. To provide the folder to match against the full path of the IMAP host for each is the easiest way. Getting a match can be opaque (see lower for some ways to debug), using the full server path makes it really specific and the slash (/) at the end is important.
When it matches the mailbox the folder-hook executes the command which is to load the specific settings in each file. Here's the gmail-account-neomuttrc configuration:
# vim: ft=muttrc fdm=marker foldcolumn=2 set folder = imaps://user@gmail.com@imap.googlemail.com set spoolfile = +INBOX unset record # Gmail automatically records sent email # if we set $record we duplicate email set trash = +[Gmail]/Trash set postponed = +[Gmail]/Drafts set from = user@gmail.com set real_name = "Your Name" # set status: black (color0) text, yellow (color11) foreground color status color0 color11
The equivalent runbox-account-neomuttrc file:
set folder = imaps://user@email.domain@mail.runbox.com set spoolfile = +INBOX set record = +Sent set trash = +Trash set from = user@email.domain set realname = "Your Name" # set status: black (color0) text, DeepSkyBlue1 (color39) foreground color status color0 color39
And, the local-account-neomuttrc has
set folder = ~/.mail set spoolfile = ~/.mail/inbox set record = +Sent set postponed = +Drafts set trash = +Trash # set status: black (color0) text, Wheat4 (color101) foreground color status color0 color101
With this in place start NeoMutt and move between folders by using the folder browser (default y). When a folder is opened the folder_hook should match and change the settings.
To test whether that's happening successfully query whether the variables are set correctly by doing:
:set ?variable-name :set ?folder :set ?from # when initially starting NeoMutt :set ?folder # folder="/home/<user>/.mail" :set ?from # from="name@email.domain" # change to the Runbox folder (using 'y') :set ?folder # folder="imaps://user@email.domain@mail.runbox.com/" :set ?from # from="name@email.domain" # change to the Gmail folder (using 'y') :set ?folder # folder="imaps://user@gmail.com@imap.googlemail.com/" :set ?from # from="user@gmail.com" # change to the Local folder Sent :set ?folder # folder="/home/<user>/.mail" :set ?from # from="name@email.domain"
There's also the keyboard shortcut M to show messages from NeoMutt.
One key point to remember with hooks is that the configuration won't change unless there is a hook. That's why there's a local-account-neomuttrc, to change the settings to the local defaults when the user goes to a local folder. Without this, if we went from the Gmail folder and switched to a local folder, the variables would be set incorrectly remaining on the Google settings.
We're now ready to configure how NeoMutt sends email depending on the account. Each account's mail provider uses it's own SMTP server and will only relay email from an account it recognises (so we can't send Gmail email out using Runbox for example).
This is where msmtp is really nice as it can be configured to use the correct SMTP server depending on the from address that NeoMutt provides to it. There's no additional configuration within NeoMutt. And, email can be written and queued when offline (e.g. travelling with a laptop). See my msmtp tutorial for the details.
The alternative is to configure the SMTP smarthost for each account within each account's configuration file. The main downside is that we can't send email when we're not online. Just the same as configuring the IMAP servers make sure there's a default setting in the local-account-neomuttrc file.
Add the following to gmail-account-neomuttrc:
set smtp_url = smtps://user@gmail.com@smtp.gmail.com
Note that we configured the account_command script earlier to recognise smtp.gmail.com and to provide the correct password.
For runbox-account-neomuttrc and local-account-neomuttrc add:
set smtp_url = smtps://user@email.domain@mail.runbox.com
This will mean that NeoMutt will default to using Runbox as the outbound SMTP server to use.
One nice configuration is to switch between accounts using a shortcut, rather than navigating to a folder. Here's a macro:
macro index <f7> '<sync-mailbox><refresh><enter-command>source ~/.config/neomutt/runbox-account-neomuttrc<enter><change-folder>!<enter>' macro index <f8> '<sync-mailbox><refresh><enter-command>source ~/.config/neomutt/gmail-account-neomuttrc<enter><change-folder>!<enter>'
These both sync the current mailbox then source the account's specific configuration and change-folder to the new $spool_file (using the exclamation mailbox shortcut).
If you only want to see the mailboxes associated with a particular account then in each account's configuration file remove the mailboxes and reconfigure them like this:
unmailboxes * mailboxes -label G:Inbox -notify -poll ! \ -label G:All-Mail -nonotify -nopoll "+[Gmail]/All Mail" \ -label G:Sent -nonotify -poll +Sent \ -label G:Trash -nonotify -nopoll +Trash
Remember to do this in all account configuration files, otherwise switching to another account from Gmail won't update the mailboxes list.
NeoMutt will deal with messages differently if it knows whether you sent them or if they were from someone else (see NeoMutt Alternative Addresses. This is particularly important for <group-reply> (g by default) where NeoMutt will exclude 'you' from the reply if it knows the email was sent by 'you'.
To tell NeoMutt about multiple accounts configure the alternates with a list of regular expressions:
alternates = "^name@email.domain$ ^user@gmail.com$" set reverse_name = yes
Notice that each regexp is matching on the start of the email address (using ^) and the end of it (with $), each subsequent email address is separated with a space, and the whole thing is within a string. As it's a regex field it's worth closely matching and the field only has the email address (the name isn't in this field).
There are a lot of configuration examples that use a slightly different format but Kevin McCarthy (maintainer of Mutt) has a useful Mutt MultiAccount Wiki page where he points out that the format of $alternates changed and that the correct form is a list of multiple names.
To exclude emails from yourself in replies NeoMutt uses the me_too variable. The default is not to include yourself, so there's no reason to change it - unless you want to email yourself a lot!
Generally, if we receive an email to our work account we want replies to come from our work email address. NeoMutt will do this if the reverse_name boolean is set to yes. It will look at which address the email is (To:), then check alternates to see if it's a known identity, if it is it builds the from line accordingly. Note that the use_from must be set - this is the default and I have no idea why anyone would unset it!
There's a similar setting for altering the real_name variable, by setting reverse_real_name. The use-case for this might be that on a work account you use a formal name, and on a personal account you use an informal name.
Lots of complex configurations are possible, but hopefully this covers the main use-cases.
In this post we've explored some ways to make NeoMutt look more colourful and gone through operating multiple accounts. We've used folder-hooks and the source command to set-up configuration that's appropriate for each account. There's lots more that can be done with folder-hooks, and NeoMutt has hooks for other situations which are worth exploring.
Our current configuration requires us to be online and able to access the IMAP server to read email. Even if there's lots of bandwidth the latency of operating on each email individually can be annoying. Next time we'll look at having a local copy of all email and synchronising changes (mirroring-imap).