Back to site home

Back to blog index

CLI mail

2021-04-04

I've been using mutt for my email for probably a year and a half now, and I'm a pretty big fan.

There are a whole bunch of benefits:

(If you genuinely enjoy your webmail, or want it to tie directly into other Google or Microsoft tools, or whatever, there are downsides as well--but I definitely prefer the terminal.)

However, it can be intimidating to start using a CLI mail tool. This post is intended to walk through some of the infrastructure you'll need to set up. As always, the Arch Wiki is an excellent source of information on these as well.

All configurations in this post are taken from my dotfiles.

Quick overview

We're going to need three pieces of software for this.

The first is a tool that doesn't seem to have a formal category name, but which I will call a "mail fetcher". It syncs mail between your local machine that you're reading and writing mail on, and the server that is hosting that mail. We'll install mbsync for this purpose.

The second is a "mail transfer agent", which sends mail through a mail server. We'll install msmtp for this purpose.

The third is a "mail user agent", which functions as a mail client where we can read and write mail. We'll install mutt for this purpose.

Mbsync and msmtp should be mostly background tools after they're first set up; you should only rarely need to interact directly with them. The bulk of your interactions as a user will be with the MUA, mutt.

Quick contextual notes: IMAP is a protocol for fetching email from a server. It supplanted the older POP3. SMTP is a protocol for sending email. A MUA is a "mail user agent"; it's basically a mail client that lets you look at and interact with mail. It may or may not have other features, like fetching or sending mail. An MTA is a "mail transfer agent"; it sends mail.

mbsync

Mbsync is a tool for fetching mail to your local computer ("Mail Box Sync"). It can be run on-demand or in a service, and will keep your mailbox up-to-date for you. It also sends your changes (deleting messages, sending messages, etc.) back up to the server. It should be available from your distro's package repository; sometimes, for reasons that are unclear to me, it is called "isync" instead.

The configuration here is intended to establish your authentication information, what email to sync, and how to put it onto your local machine.

This is one account, taken from my config. We'll go through it line-by-line.

~/.mbsyncrc

IMAPAccount migadu
Host imap.migadu.com
User jordan@jnewport.dev
PassCmd "cat ~/.config/passwords/migadu-email"
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore migadu-remote
Account migadu

MaildirStore migadu-local
Subfolders Verbatim
Path ~/Mail/migadu/
Inbox ~/Mail/migadu/INBOX

Channel migadu
Far :migadu-remote:
Near :migadu-local:
Patterns *
Create Both
Remove Both
SyncState *

A couple general notes:

Command line usage

You can run mbsync directly from the command line, to check your config or to check your email before your service is set to trigger. This is easy; you just run "mbsync <your IMAPAccount name>" to check one mailbox or "mbsync -a" to check all of them. The -V flag will give you verbose output, which can help debug issues.

Running as a service

You can run mbsync as a systemd service, cron job, or whatever else, which will keep your inbox perpetually up-to-date and save you time when you want your email. Here are my systemd files (I won't annotate these, because this is less valuable, but they may still be helpful). You may have to fight systemd a little to get user services running; you can't just start them like you can system services.

~/.config/systemd/user/mbsync.service

[Unit]
Description=Mailbox synchronization service

[Service]
Type=oneshot
ExecStart=/usr/bin/mbsync -a

~/.config/systemd/user/mbsync.timer

[Unit]
Description=Mailbox synchronization timer

[Timer]
OnCalendar=*:0/10
Unit=mbsync.service

[Install]
WantedBy=timers.target

msmtp

Msmtp is a tool for sending mail (an MTA) from your local computer using the smtp protocol. It can be run directly or hooked from your email client. I can't imagine a Linux distro that wouldn't provide this in its repo, so install away.

The configuration here is intended to establish which extra SMTP features you need and your authentication information.

Here's part of my config; we'll go through it line-by-line.

~/.msmtprc

# Always use security
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
protocol smtp
timeout 10

account migadu
host smtp.migadu.com
tls_starttls off
port 465
from jordan@jnewport.dev
user jordan@jnewport.dev
passwordeval "cat ~/.config/passwords/migadu-email"

account default : migadu

General notes:

Command line usage

You can test your msmtp config or send simple emails by piping the contents of your email into:

msmtp -a <account> <recipient email address>

There are more complex tasks that can be done from the command line, but that's up to you to figure out.

mutt

Now that we've set up our infrastructure for checking and sending email, we can set up a program to view our emails (a "mail user agent"). This won't go into anywhere near all the features that our chosen program, mutt, possesses, but it should get you far enough that you can see your email (and you can configure further from there). If you want to see a more fleshed-out mutt config, mine is available in my dotfiles. Mutt is available in most distros' package repositories. Be careful to not confuse mutt and neomutt; in my experience, neomutt doesn't work as well as plain old mutt.

The most relevant true quote I can find about mutt is on its homepage:

"All mail clients suck. This one just sucks less." -the creator of Mutt, circa 1995

Mutt's configuration is mostly about usability and pointing it at the right files. In general, mutt will work regardless of its configuration, so long as you point it at a valid maildir.

Here is a simple config, based on mine. A lot of it is centered around making mutt more similar to other mail clients you may have used. We'll walk through it piece by piece. This one was tricky to make, because it's hard to balance which features are needed versus which are just nice to have, but this should get you started.

~/.mutt/muttrc

# set up default folders; this could technically be done in the account-specific config
set mbox_type=maildir
set mbox="~/Mail/migadu/INBOX"
set spoolfile="~/Mail/migadu/INBOX"
set folder="~/Mail/migadu/"
set record="~/Mail/migadu/Sent/"

# default account is migadu
source ~/.mutt/accounts/migadu

# switch between mines and migadu accounts
folder-hook migadu/* source ~/.mutt/accounts/migadu
folder-hook mines/* source ~/.mutt/accounts/mines
macro index M "<change-folder>~/Mail/mines/INBOX<enter>"  "go to Mines Inbox"
macro index I "<change-folder>~/Mail/migadu/INBOX<enter>"  "go to Migadu Inbox"

# never check for email directly from mutt; that's mbsync's job
set mail_check = 0
# set mail to be from me
set envelope_from

# aliases is your address book; mailcap is how to open attachments
set alias_file = ~/.mutt/aliases
set mailcap_path = ~/.mutt/mailcap

# These make mutt behave in a reasonable/expected manner when doing basic mail tasks
unset move
set delete
unset confirmappend
set quit
unset mark_old

# Sort
set sort = threads
set sort_aux = reverse-last-date-received
set sort_re

# HTML
# don't automatically view attachments
unset implicit_autoview
# the preferred text type order
alternative_order text/plain text/enriched text/html
# If there's only an html part and no plaintext, open it automatically
auto_view text/html

# Composing
# use $EDITOR for composing messages
set editor = `echo \$EDITOR`
# unsetting this allows you to forward messages inline rather than as attachments
unset mime_forward
# your forwarded-message subject line
set forward_format = "Fwd: %s"
# includes replied/forwarded message in your message
set include
# Prepends a > to each quoted line
set forward_quote

# Aliases
# Actually use your alias file/address book
source ~/.mutt/aliases

# Handle html attachments better
macro index,pager E "v/html<enter>s<kill-line>/tmp/mutt.html<enter>"  "save html part in /tmp/mutt.html"

I won't discuss all of them in much detail, but it's worth including some other config files sourced by the main muttrc as well.

~/.mutt/aliases

alias Jordan_Newport Jordan Newport <jordan@jnewport.dev>
alias Some_Name Some Name <some.name@example.com>
alias my_friends Jordan_Newport, Some_Name

This is an example of an alias file (analogous to an address book; a defined name "aliases" to an email address or list of addresses). Alias names must be one word. The "body" of an alias must be either a target to send email to (with an optional name and mandatory <email address>) or a list of other aliases. The client will automatically create aliases for you and append them to this file if you hit a on a message.

~/.mutt/mailcap

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

# PDF documents
application/pdf; zathura %s

# Images
image/jpg; feh -. %s
image/jpeg; feh -. %s
image/pjpeg; feh -. %s
image/png; feh -. %s
image/gif; feh -. %s

# Office Suites
application/msword; libreoffice %s;
application/vnd.ms-word.document.12; libreoffice %s;
application/vnd.openxmlformats-officedocument.wordprocessingml.document; libreoffice %s;
application/vnd.oasis.opendocument.text; libreoffice %s;

This mailcap file tells mutt how to open attachments. If a MIME type is not defined here, mutt will try to show the file in the terminal, with typically-bad results. If it is defined here, then mutt will use the specified command. Terminal browsers such as lynx or w3m will typically have specific mailcap lines they want you to use that are documented somewhere.

%s is the filename mutt will supply to the program. copiousoutput means that depending on your config options (particularly implicit_autoview), mutt may open the attachment automatically.

If this all sounds too complicated for you, or if you get an attachment not in your mailcap, mutt can also just save attachments to the filesystem to open elsewhere at your leisure (use the s key in the attachments view).

~/.mutt/accounts/migadu

# vim: ft=muttrc
set realname = "Jordan Newport"
set from = "Jordan Newport <jordan@jnewport.dev>"
set sendmail = "msmtp -a migadu"
set mbox = "~/Mail/migadu/Archive"
set postponed = "~/Mail/migadu/Drafts"
set record = "~/Mail/migadu/Sent"
set signature = "~/.mutt/signatures/migadu"

macro index,pager 's' '<save-message>?<change-dir><kill-line>~/Mail/migadu<enter>/'

macro index 'c' '<change-folder>?<change-dir><kill-line>~/Mail/migadu<enter>/'

macro index,pager d "<save-message>~/Mail/migadu/Trash<enter>" "Move message to the trash"

This file is used for specifying account-specific options, including the name and email address for this account, the particular files to use for some commands, and so on.

The first line is a modeline to tell vim it's editing a mutt config file (vim automatically knows this for files named "muttrc", but otherwise you have to tell it). This gives you syntax highlighting and such.

The next set of lines sets my name, from-line (name and email address for the email to show up with; you can spoof this), the command to send mail, the mail folders to use for this account, and the default signature for the account. The signature is literally just a text file that will be appended to all of your emails; it can contain things like your name, email address, title, or pronouns.

The next few lines set macros to override mutt's default behavior for, respectively, moving an email to a folder ("saving"), changing folders, and deleting. These configurations are nice to have for any account, since mutt defaults to doing these things in a slightly weird way, but absolutely critical for Gmail users since otherwise the Gmail server's default behavior will produce all kinds of weirdness.

General notes:

autocmd BufRead /tmp/mutt-* setlocal tw=72
autocmd BufRead /tmp/mutt-* setlocal spell spelllang=en_us

Usage

Mutt can be run from your command line as mutt. Keybindings are reasonably discoverable (and there are a few tutorials online); if you get lost, you should use the ? key. 90% of the time, you can search for what you want, and the other 10% of the time, you have to read every command until you find one that looks relevant, because mutt predates the commonly used name of the thing you want to do. That's just the way it is. All mail clients suck. Mutt just sucks less. Get ready.

Getting everything setup

So you've installed mbsync, msmtp, and mutt. You've copied the configurations I put here and replaced all the values with the ones associated with your own account.

Great!

To get started, it should be as simple as checking your configs on the command line, running "mbsync -a" once to download your email initially, and opening mutt. The first mbsync will take forever, just FYI. IMAP is not a fast protocol for mass syncs; it's optimized for small updates, not wholesale downloads.

If something doesn't work, it could be anything but is probably related to authentication. Check your passwords and URLs.

Other Topics

That is, strictly speaking, all you need to get started using mutt on the command line for your email. However, if you want more information, read on!

Migadu

Throughout this post, I've used a "migadu" config as my default. Migadu is an email provider I use that is pretty friendly to using alternative clients like mutt. It has great configuration guides for stuff like this. It lets you use your own domain, and tells you how to set up the DNS for that. It has mildly-okay webmail. It's simple, cheap, and has no drama and little confusion. It isn't selling your data. I've never (to my knowledge) had an email get flagged as spam or fail to deliver, which is a problem that people often have when self-hosting email or using small providers. It is hosted in Switzerland (I don't know how you feel about this, but it might be relevant). If you're looking into committing to a terminal-email workflow, I would seriously consider a provider like Migadu. I would recommend them.

Alternative applications

In this post, I discuss mbsync to fetch email, msmtp to send email, and mutt to use as a client/MUA. There are some alternatives to each of these. I don't have any configs to show as examples or much opinion on the user experience, but I'll mention them.

Fetching email: The most common alternative is offlineimap. I have used it; it works (and was the "standard" for many years), but has significantly worse performance than mbsync, particularly if you have a lot of folders.

Sending email: msmtp really is the standard here; a lot of your alternatives will be forks of msmtp that add some specific feature and haven't been merged.

Mail clients: There are a huge amount of alternatives here. Some are listed on Use Plaintext Email; others are listed in all sorts of places. Mutt isn't necessarily the best one to use; it's just popular and not-terrible.

Something that may be useful to know is that when you delete or move emails in mutt, many mail providers misbehave (this isn't the fault of anyone in particular; it's just that "move to Trash" being the common deletion behavior is tricky to get right), so it may be nice to have a phone client that is compatible. The one I use is K-9 Mail.

Total solutions: Mutt (and some other MUAs) can actually be used as the MUA, MTA, and email fetcher by logging into the server during use. The configuration for this looks totally different, I don't have one for you to look at, and it requires that you be online (and on the VPN, and so on) all the time. The advantage here is that you don't need to install a mail fetcher or MTA.


Comments? Questions? Email me at jordan@jnewport.dev!