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:
- 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.
- Enough HDD space for the full mailbox sync.
The setup consists of the following parts:
- IMAP server. This doesn't require any special configuration.
- 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.
- 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!
- mu4e — Emacs package that comes with mu. Provides an interface to mu.
If you use Gmail, you need to set the following things first:
- Enable IMAP.
- Use two factor authorization?
brew install isync
~/.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 firstname.lastname@example.org # 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:
Patterns *— sync all folders. Alternatively, you can select only certain folders to sync.
Expunge None— don't destroy messages neither locally, nor remotely. Details later.
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.
Create Slave— when new folders are added on server, create them locally.
mbsync and wait for it to download messages:
With a normal internet connection, around 50k messages sync in a few minutes.
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
→ 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.
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)
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