I've never been a heavy email user, nor have I ever given much thought to the tools I used to handle them. Lately though, as this pandemic carries on, I've been spending a lot more time ‘socially distanced’ in web-based email clients in an attempt to stay in contact with others. Fighting Google logins, account switching, and bouncing between providers is, at best, annoying. I came to the conclusion that it was time to consolidate my numerous email accounts into a single standalone client. I could have chosen the ever popular Thunderbird or some similar GUI client but I really wanted the efficiency and familiarity of a terminal based keyboard-centric solution. I also wanted something that mixed well with my preferred text editor, Vim.

Enter, Mutt. There are other choices of course, but none as configurable or extensible. Plus the tag line is pretty good, and accurate.

“All mail clients suck. This one just sucks less."

Having been around for 25 years and still going strong, Mutt has to be the most well known text based email agent/client in the *Nix world, and even though I've been using Linux for almost as long, I've never spent any time with it. Since Mutt is highly configurable it does make the initial set up a bit laborious but, after spending some time reading through the man pages and skimming through example configurations, I was able to get going fairly quickly. In this post I'll share a basic configuration for Mutt and some detail about the extra steps needed when using a Gmail account.

Assumptions

  • Mutt. I'm using the standard package, not NeoMutt, but the configuration should be interchangeable for the most part.

  • GnuPG for encrypting sensitive data. If you've never used GnuPG before there will be some set up involved but I'll provide a good source to get you through that.

  • If viewing HTML emails within Mutt is a concern w3m, Lynx, and eLinks terminal based browsers are supported. I'll give config options for all three so you can choose which you like best.

  • At least one email account. I'm using Gmail here due to is market dominance and because it requires a few hurdles to be traversed to get working properly.

  • Python2. The OAuth tool provided by Google hasn't been updated to Python3.

Mutt: Basic Configuration

I'm not going to cover any advanced configuration, such as Notmuch for searching mail, or external SMPT clients like msmtp. This is just a basic setup that works well for what I would consider a ‘normal’ use case.

Below is the final file structure you end up with. By default, Mutt's configuration files are located either in your home directory under .mutt or in your ~/.config directory under mutt. I'm using the latter for this tutorial, adjust accordingly on your end. Go ahead and create the accounts and certs sub-directories and touch the mailcap and muttrc files. We'll be obtaining the oauth2.py script later on along with creating the rest of the files.

~/.config/mutt/

  ├── accounts
  │   ├── account-00
  │   ├── account-01
  │   ├── account-02
  │   ├── account-03
  │   └── secrets.gpg
  ├── certs
  │   └── certificates
  ├── mailcap
  ├── muttrc
  └── oauth2.py

Here are the contents of the two files, mailcap and muttrc. Hopefully commented well enough to answer any questions. If not, the man pages for Mutt are excellent and should make up for things I've left out.

~/.config/mutt/mailcap

# Set the terminal browser w3m as our HTML viewer.
text/html; w3m -I %{charset} -T text/html; copiousoutput;

# lynx alternative.
#text/html; lynx -assume_charset=%{charset} -display_charset=utf-8 -collapse_br_tags -dump %s; nametemplate=%s.html; copiousoutput

# elinks alternative.
#text/html; elinks -dump ; copiousoutput;

~/.config/mutt/muttrc

# Secrets
# Decrypting and then sourcing our secrets file containing all personal
# information that will then be available to our individual account config files.
# Sourcing a file in this muttrc is equivalent to appending to the file itself.
source "gpg -dq $XDG_CONFIG_HOME/mutt/accounts/secrets.gpg |"


# General Settings
set editor                  = "vim"
set header_cache            = "$XDG_CACHE_HOME/mutt"
set imap_keepalive          = 60
set imap_passive            = no
set imap_check_subscribed
set imap_idle               = yes
set mail_check              = 60
set mbox_type               = Maildir
set sort                    = threads
set sort_aux                = reverse-last-date-received
set reverse_name            = yes
set reverse_realname        = yes
set wait_key                = no
set delete


# Handle HTML
# Prefer text if available but auto view HTML as a second choice.
set mailcap_path            = "$XDG_CONFIG_HOME/mutt/mailcap"
auto_view text/html
alternative_order text/plain text/html

# Create a macro to open the selected email when viewed on the 'Attachments'
# screen. "O" will save the HTML in cache and open it in your default GUI
# web browser, determined by the enviroment variable $BROWSER.
macro attach 'O' "<pipe-entry>iconv -c --to-code=UTF8 > $XDG_CACHE_HOME/mutt/mail.html<enter><shell-escape>$BROWSER $XDG_CACHE_HOME/mutt/mail.html<enter>"


# Status Bar
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 )?───"


# Sidebar
set sidebar_visible         = yes
set sidebar_width           = 20
set sidebar_delim_chars     = "/"
set sidebar_short_path      = yes
set sidebar_folder_indent   = yes
set sidebar_next_new_wrap   = yes
set mail_check_stats


# SSL & Certs
# Force strong SSL and disable system certs. Force manual approval of all
# certs used.
set ssl_force_tls           = yes
set ssl_starttls            = yes
set ssl_use_sslv2           = no
set ssl_use_sslv3           = no
set ssl_use_tlsv1           = no
set ssl_use_tlsv1_1         = no
set ssl_use_tlsv1_2         = no
set ssl_use_tlsv1_3         = yes
set ssl_verify_dates        = yes
set ssl_verify_host         = yes
unset ssl_usesystemcerts
set certificate_file        = "$XDG_CONFIG_HOME/mutt/certs/certificates"


# Default account - Select on startup.
source "$XDG_CONFIG_HOME/mutt/accounts/account-00"


# Folder hooks for all accounts. Can be changed or added to but a hook is
# required for each account.
folder-hook "account-00" "source $XDG_CONFIG_HOME/mutt/accounts/account-00"
folder-hook "account-01" "source $XDG_CONFIG_HOME/mutt/accounts/account-01"
folder-hook "account-02" "source $XDG_CONFIG_HOME/mutt/accounts/account-02"
folder-hook "account-03" "source $XDG_CONFIG_HOME/mutt/accounts/account-03"


# Macros for changing between accounts. Using F5-F8 here for four accounts, can
# be changed, added to, or removed all together if only using one account.
macro index,pager <F5> '<sync-mailbox><enter-command>source $XDG_CONFIG_HOME/mutt/accounts/account-00<enter><change-folder>!<enter>'
macro index,pager <F6> '<sync-mailbox><enter-command>source $XDG_CONFIG_HOME/mutt/accounts/account-01<enter><change-folder>!<enter>'
macro index,pager <F7> '<sync-mailbox><enter-command>source $XDG_CONFIG_HOME/mutt/accounts/account-02<enter><change-folder>!<enter>'
macro index,pager <F8> '<sync-mailbox><enter-command>source $XDG_CONFIG_HOME/mutt/accounts/account-03<enter><change-folder>!<enter>'


# Bind "G" to fetch imap on demand. Set to auto fetch every minute in General
# Settings above but can be manually fetched anytime with this.
bind index "G" imap-fetch-mail


# Other binds to make mutt behave more like Vim, optional.
bind pager j next-line
bind pager k previous-line
bind attach,index,pager \CD next-page
bind attach,index,pager \CU previous-page
bind pager g top
bind pager G bottom
bind attach,index g first-entry
bind attach,index G last-entry


# vim:ft=muttrc

Gmail: Getting Credentials

It's time to get your credentials from Google, create your secret config file, and download the utility script. It may sound like a lot of work but it is relatively painless.

Head over to the Google API Console and sign in with the Gmail account you want to get credentials for. Once signed in and at the dashboard run through the following steps.

  1. Open the ‘Select a project’ drop down menu at the top left of the page, this will open a pop-up window.

  2. In the top right of the window select ‘NEW PROJECT’. This will take you to the project creation page.

  3. You can leave the default name if you choose but I recommend giving it a descriptive name, then select ‘CREATE’. It might take a few seconds but you should get a notification telling you the project has been created.

  4. Now, on the left menu bar, select ‘OAuth consent screen’. This will take you to another page with a ‘User Type’ option. Choose ‘External’ and then ‘CREATE’.

  5. You will now be on a new page with a few more options. You only need to fill in the application name and then click the save button at the bottom of the page.

  6. Next, go back the menu on the left and select ‘Credentials’. This will take you to the credentials page where you can select ‘CREATE CREDENTIALS’ at the top. Choose ‘OAuth client ID’.

  7. On the next page choose ‘Desktop app’ and give it a name. Once you select ‘CREATE’ you will be presented with your Client_id and Client_secret. Copy these into your ~/.config/mutt/accounts/secrets file.

Repeat the above for as many Gmail accounts as you have, keep adding the IDs and secrets into your secrets file, making sure to label each one so you don't get them mixed up.

Now it's time to get the OAuth script, it can be found at the address below. You can use wget, curl, or simply open in your browser and ‘save as’ to download the script.

https://raw.githubusercontent.com/google/gmail-oauth2-tools/master/python/oauth2.py

For the next step you first need to find out if you have Python2 installed. Most distributions have moved on to Python3 as default now due to Python2 reaching end of life January 1, 2020. Some distros, such as the latest release of Ubuntu, have removed Python2 from its default installation so you might have to install it first. A good guide for this can be found here. Run python2 --version in a terminal. If you get a result of anything resembling ‘Python 2.7.x’ you're good to go.

Now open up the script in you favorite editor and add a 2 to the end of the first line. This will make sure the script gets called with Python2 in the case Python3 is set as your default version, as is most likely the case. Below is what the line should look like when done.

#!/usr/bin/python2

The script needs to be set as executable. Run the following command and you'll be set.

chmod +x oauth2.py

You can now run the following command for each of your accounts. You will be given a link to a Google page for verification. Follow that link and get your verification to enter back into the terminal. The result will contain a ‘refresh_token’ that you need to add to your secrets file.

./oauth2.py --user=<xxx@gmail.com> --client_id=<client_id> --client_secret=<client_secret> --generate_oauth2_token

Below is what your secrets file should look like after formatting. It will need to be in the muttrc config syntax as it will be decrypted and sourced by the main muttrc file shown above. Any variable starting with my_ is considered a custom variable and can be referenced throughout the configuration files when sourced.

# First account variables labeled with '_00'.
set my_email_00             = "<your.address@gmail.com>"
set my_name_00              = "<Your Name>"
set my_client_id_00         = "<client_id>"
set my_clinet_secret_00     = "<client_secret>"
set my_refresh_token_00     = "<refresh_token>"

# Second account the variables are incremented to '_01'.
set my_email_01             = "<other.address@gmail.com>"
set my_name_01              = "<Your Name>"
set my_client_id_01         = "<client_id>"
set my_clinet_secret_01     = "<client_secret>"
set my_refresh_token_01     = "<refresh_token>"

# Continue this pattern for any other accounts, incrementing the number of each
# variable as you go. Make note of which account relates to the number if the
# order of accounts is important to you.

# vim:ft=muttrc

GnuPG: Keeping Your Secrets Safe

All that's left now is to encrypt your secrets file. If you've used GnuPg before this will be a simple process. If not, a little set up will be needed. Head over the GnuPG page of the Arch Linux wiki and work through the Installation, Configuration, and Usage sections. You should now be able to encrypt the file using the following command. Be sure to delete the original plain text file afterwards. If you need to make modifications you can always decrypt the file, make your changes, then re-encrypt.

gpg --recipient <recipient> --encrypt secrets

# Get rid of original file.
rm secrets

# To decrypt
gpg --output <file-name> --decrypt <secrets.gpg>

That should get you going. Upon first run of Mutt you will be asked to confirm certificates by allowing them once or for all time. This will create the final certificates file. Switching accounts is achieved through the shortcut keys assigned in the muttrc file and the y key will let you move between mailboxes.

Now would be a good time to sit down with a cup of coffee and browse through the Mutt man pages. There is a lot to take in and a ton of customization available to you. Hope this helped to get you started with Mutt!

Feel free to send me an email with any questions, comments, or requests and if you're feeling generous, help keep me caffeinated.