Text-based email setup with mbsync and mu
Composing mail without the assistance of emacs is painful for serious emacs users. KMail (supplemented with emacsclient) had been my email client of choice for more than a decade. While KMail continues to be an excellent mail client, I started looking more into moving my entire email flow into emacs. Sending mail from emacs is pretty easy with smtpmail; so the only issue was finding a way to fetch and display email. After trawling The Interwebz, mu4e seemed to fit in best with my workflow.
1. Initial setup
Setting up mu4e was pretty easy since its parent package mu can be set up as a git submodule (or as a git subtree) of an emacs initialization directory and can then be compiled in place. Most of the initial setup is straightforward since the built in manual is pretty comprehensive; Rob Stewart's excellent guide is a handy summary for the impatient. The only other initial setup choice was between offlineimap and mbsync. After initial attempts at setting up both, I ended up choosing mbsync.
1.1. Fetching email with mbsync
While the mbsync man page is pretty comprehensive, it can be a little intimidating to set it up for use with mu4e. The basic setup for one email account is similar to the following:
IMAPAccount MyAccountName
Host imap.gmail.com
User MyAccountName@gmail.com
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d ~/.authinfo.gpg | awk '/machine imap.gmail.com login MyAccountName@gmail.com/ {print $NF}'"
# Use SSL
UseIMAPS yes
CertificateFile /etc/pki/tls/certs/ca-bundle.crt
IMAPStore MyAccountName-remote
Account MyAccountName
MaildirStore MyAccountName-local
# The trailing "/" is important
Path ~/.mail/MyAccountName/
Inbox ~/.mail/MyAccountName/Inbox
Channel MyAccountName
Master :MyAccountName-remote:
Slave :MyAccountName-local:
# Exclude everything under the internal [Gmail] folder, except the interesting folders
Patterns * ![Gmail]* "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail" "[Gmail]/Drafts"
# Or include everything
#Patterns *
# Automatically create missing mailboxes, both locally and on the server
Create Both
# Save the synchronization state files in the relevant directory
SyncState *
The set up above is typical for Google mail. There are a couple of
interesting bits, however. First, the use of SSL requires that
certificate bundles be available to mbsync. On Fedora Linux 19 and
later, the easiest way is to install ca-certificates.noarch using the
package manager. The location of installed certificates is provided to
mbsync via the CertificateFile directive.
The second and more interesting part is the handling of passwords.
1.1.1. Using GPG for mbsync passwords
The basic idea is that every time a password is needed, an particular
file is decrypted and loaded. The key for the decryption can be
prompted for and be stashed by gpg-agent. The first step is to create
a GPG key, which is covered very well elsewhere. The standard
authentication mechanism for gnus and smtpmail can be reused to store
login information for mbsync. For any one account, the password for
IMAP access and the password for sending email (usually the same) can
be added to ~/.authinfo.gpg:
machine imap.gmail.com login MyAccountName@gmail.com password MYPASSWORD machine smtp.gmail.com login MyAccountName@gmail.com password MYPASSWORD
The first line is used by mbsync and the second by smtpmail. The
line:
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d ~/.authinfo.gpg | awk '/machine imap.gmail.com login MyAccountName@gmail.com/ {print $NF}'"
automatically fetches the password for the given account from
authinfo.gpg. It is easy now with a couple of simple modifications
to ~/.gnupg/gpg-agent.conf to make sure that the password prompt
appears under X and that the key is stashed:
pinentry-program /usr/bin/pinentry-qt4 default-cache-ttl 720000 max-cache-ttl 720000
The stash time for passwords is set to 200 hours.
1.2. Initial mu4e setup
I chose to set up mu4e sources as a git submodule in my emacs
directory with path site-lisp/mu, which necessitated the following
changes to my emacs start up code:
(add-to-list 'Info-additional-directory-list (ravi/emacs-file "site-lisp/mu/mu4e")) (setq mu4e-mu-binary (ravi/emacs-file "site-lisp/mu/mu/mu"))
The next part ensures that the main mu4e window is quickly accesible
from a key binding without opening duplicate buffers:
(defun ravi/switch-to-mu4e () (interactive) (let ((buf (or (and (boundp 'mu4e~headers-buffer-name) (get-buffer mu4e~headers-buffer-name)) (get-buffer "*mu4e-main*")))) (if buf (if (get-buffer-window buf t) (select-window (get-buffer-window buf t)) (switch-to-buffer buf)) (mu4e)))) (bind-key "C-'" 'ravi/switch-to-mu4e)
That's all for now. We will cover setting up multiple accounts with different polling intervals in a future post.