Email with mu4e

This article is published ahead of its scheduled time. Thus, some pre-requisites (like installing packages) are not yet covered in the previously published chapters.

Zawinski's law of software envelopment (also known as Zawinski's law) comments on the phenomenon of software bloating with popular features: "Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can."

Naturally, Emacs can handle email. One popular extension is mu4e, an Emacs interface to mu email client. Today we'll set up an email workflow with the following assumptions:

  1. Standard IMAP email provider. If you use Gmail, everything in this article will work, but since Gmail uses its own, non-standard implementation of IMAP when it comes to labels and folders, you may get unexpected results in certain situations.
  2. Enough HDD space for the full mailbox sync.

The setup consists of the following parts:

  1. IMAP server. This doesn't require any special configuration.
  2. mbsync — a command-line utility which syncs IMAP server with a local directory in Maildir format. This has nothing to do with Emacs. Even if you're not interested in doing email in Emacs, having a full local copy of your mailbox may be a good idea. mbsync does exactly that. In can sync both ways, so if you just move a file (which corresponds to a single message) from folder to folder, and then run mbsync again, this change will propagate to the server.
  3. mu — a command line email client which works with Maildir storage. It doesn't deal with the server directly, instead, it just read your local file system. It's very fast!
  4. mu4e — Emacs package that comes with mu. Provides an interface to mu.

Gmail

If you use Gmail, you need to set the following things first:

  1. Enable IMAP.
  2. Use two factor authorization?

Installing and configuring mbsync

Install mbsync with your OS package manager or build from source. Confusingly, the package is called isync, but the binary is called mbsync. MacOS users should use homebrew:

brew install isync

Mbsync uses ~/.mbsyncrc for configuration. This page describes all options. Here's a simple, with comments:

# First section: remote IMAP account
IMAPAccount fastmail
Host imap.fastmail.com
Port 993
User myemailaddress@mydomain.com
# For simplicity, this is how to read the password from another file.
# For better security you should use GPG https://gnupg.org/
PassCmd "cat ~/.mbsync-fastmail"
SSLType IMAPS
SSLVersions TLSv1.2

IMAPStore fastmail-remote
Account fastmail

# This section describes the local storage
MaildirStore fastmail-local
Path ~/Maildir/
Inbox ~/Maildir/INBOX
# The SubFolders option allows to represent all
# IMAP subfolders as local subfolders
SubFolders Verbatim

# This section a "channel", a connection between remote and local
Channel fastmail
Master :fastmail-remote:
Slave :fastmail-local:
Patterns *
Expunge None
CopyArrivalDate yes
Sync All
Create Slave
SyncState *

Few details about the channel options worth mentioning:

  1. Patterns * — sync all folders. Alternatively, you can select only certain folders to sync.
  2. Expunge None — don't destroy messages neither locally, nor remotely. Details later.
  3. CopyArrivalDate — makes sure the date of the arrival stays the same when you move messages around. Without this option, moving a message to another folder will reset the date of the message.
  4. Create Slave — when new folders are added on server, create them locally.

Now run mbsync and wait for it to download messages:

mbsync -a

With a normal internet connection, around 50k messages sync in a few minutes.

Installing and configuring mu and mu4e

First, verify that which emacs points to a valid Emacs executable, and emacs --version shows the correct version:

→ which emacs
/usr/local/bin/emacs

→ ls -la /usr/local/bin/emacs
/usr/local/bin/emacs -> /Applications/Emacs.app/Contents/MacOS/Emacs.sh

→ emacs --version
GNU Emacs 26.3

Now, install mu. On macOS:

brew install mu

And let it index the Maildir:

mu index --maildir=~/Maildir

Now you can check if everything worked by trying a command-line search:

mu find hello

mu comes with mu4e by default. To verify, check for presence of elisp files in /usr/local/share/emacs/site-lisp/mu/mu4e:

→ ls /usr/local/share/emacs/site-lisp/mu/mu4e
mu4e-actions.el   mu4e-contrib.elc  mu4e-main.el  ...

Now load these files in Emacs and enable mu4e. Put the following in your Emacs config:

(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu/mu4e")
(require 'mu4e)

And add some configuration.

(setq
 mue4e-headers-skip-duplicates  t
 mu4e-view-show-images t
 mu4e-view-show-addresses t
 mu4e-compose-format-flowed nil
 mu4e-date-format "%y/%m/%d"
 mu4e-headers-date-format "%Y/%m/%d"
 mu4e-change-filenames-when-moving t
 mu4e-attachments-dir "~/Downloads"

 mu4e-maildir       "~/Maildir"   ;; top-level Maildir
 ;; note that these folders below must start with /
 ;; the paths are relative to maildir root
 mu4e-refile-folder "/Archive"
 mu4e-sent-folder   "/Sent"
 mu4e-drafts-folder "/Drafts"
 mu4e-trash-folder  "/Trash")

;; this setting allows to re-sync and re-index mail
;; by pressing U
(setq mu4e-get-mail-command  "mbsync -a")

That's it! Run M-x mu4e and after a few final setup questions mu4e should be running. Check out keybindings for it.

Caveat: deletion vs. expunge

By default, when you mark a message to be deleted, mu4e will apply the "Trashed" flag. Fastmail and other standard IMAP providers automatically destroy the messages flagged this way.

If instead of total deletion you want to move messages to the "Trash" folder, there are several options. You can simply use "move" command of mu4e, but it'd be nicer to use d button (deletion) for that. The following piece of elisp remaps the d button to "move to Trash folder" action. This way, neither mu4e nor your email provider destroy the message.

(fset 'my-move-to-trash "mTrash")
(define-key mu4e-headers-mode-map (kbd "d") 'my-move-to-trash)
(define-key mu4e-view-mode-map (kbd "d") 'my-move-to-trash)

Sending mail

mu4e re-uses Gnus’ message-mode for writing mail and inherits its configuration. For sending via SMTP, mu4e uses smtpmail. Minimal configuration looks like this:

(setq
   message-send-mail-function   'smtpmail-send-it
   smtpmail-default-smtp-server "smtp.fastmail.com"
   smtpmail-smtp-server         "smtp.fastmail.com")

When using SMTP for the first time, Emacs prompts you for the user name and password to use, and then offers to save the information. By default, Emacs stores authentication information in a file ~/.authinfo.

  1. Emacs SMTP Library (smtpmail) documentation
  2. Mu4e user manual
  3. List of mu4e tutorials
  4. mu email client
  5. isync / mbsync