Emacs journey: email with mbsync, mu4e and msmtp
Contents
Finally the day comes when I decided to move another part of my workflow inside Emacs - Email. Before I jumped into the "rabbit hole" of Emacs, I never thought there are other options for handling email than the default email client provided by the OS: Outlook on Windows, Mail on macOS and Thunderbird on Linux. At the first glance, using email in Emacs seems to be a very complicated process to me for two main reasons: 1. there are just too many options such as Gnus, Rmail, NotMuch and mu4e; 2. you need some heavy configurations for either of these approaches work which is discouraging. After a bit or research, I decided to use mu4e as the interface to emails in Emacs. This blog describes how I set up email in Emacs with the help of mbsync, mu/mu4e and msmtp while handling all the passwords using GPG from an encrypted file. Before getting into the details, I would like the show how the email interface of mu4e looks like in the following figure. The email thread is from a Github issue that I followed:
To describe the big picture of handling email locally in Emacs, I shamelessly stole the following figure showing the overall workflow from Adolfo Villafiorita’s blog post. Although there are dozens of blog posts describing how to set up email in Emacs (like this one), Adolfo's post is one of the most comprehensive ones. The other blog post which I would recommend is A Complete Guide to Email in Emacs using Mu and Mu4e from Caches to Caches who's posts are often high quality.

-
Emails in the servers are synced to a local folder through a sync software. There are several options for this purpose, with two of the most popular ones being offlineimap and mbsync.
-
The local messages, which are stored in a particular format like maildir, are indexed through an indexing tool like mu or Notmuch.
-
A user interface to interact with local messages and reading/composing new messages. Available options in Emacs Notmuch and mu4e from mu.
-
Another step which is not shown in the above figure is the handling of email passwords. I will use GnuPG to retrieve passwords for the different programs from an encrypted file.
Configure mbsync (isync)
The package providing mbsync is actually called isync. First installed the relevant packages. On my Linux (Ubuntu/Pop OS):
|
|
The configuration for mbsync is stored in a file .mbsync
in the home folder.
For each email account, we need to specify the remote account information, local storage directory, channels (what folder to be synced) and groups.
As always, much more detailed information can be found on the excellent Arch wiki page so I just provide below my mbsync configuration for Gmail as an example.
Notice how we use the gpg -q --for-your-eyes-only --no-tty -d ~/.authinfo.gpg | awk '/machine imap.gmail.com login your_name@gmail.com/ {print $NF}'
to get the password from the encrypted .authinfo.gpg
instead specifying the raw password.
More details on this will be discussed in the later section.
############################################ # Gmail ############################################ # ACCOUNT INFORMATION IMAPAccount gmail # Address to connect to Host imap.gmail.com User your_name@gmail.com PassCmd "gpg -q --for-your-eyes-only --no-tty -d ~/.authinfo.gpg | awk '/machine imap.gmail.com login your_name@gmail.com/ {print $NF}'" AuthMechs LOGIN SSLType IMAPS # SSLVersions SSLv3 # The following line should work. If get certificate errors, uncomment the two following lines and read the "Troubleshooting" section. CertificateFile /etc/ssl/certs/ca-certificates.crt # THEN WE SPECIFY THE LOCAL AND REMOTE STORAGE # - THE REMOTE STORAGE IS WHERE WE GET THE MAIL FROM (E.G., THE # SPECIFICATION OF AN IMAP ACCOUNT) # - THE LOCAL STORAGE IS WHERE WE STORE THE EMAIL ON OUR COMPUTER # REMOTE STORAGE (USE THE IMAP ACCOUNT SPECIFIED ABOVE) IMAPStore gmail-remote Account gmail # LOCAL STORAGE (CREATE DIRECTORIES with mkdir -p Maildir/gmail) MaildirStore gmail-local Path ~/Maildir/gmail/ Inbox ~/Maildir/gmail/INBOX # CONNECTIONS SPECIFY LINKS BETWEEN REMOTE AND LOCAL FOLDERS # # CONNECTIONS ARE SPECIFIED USING PATTERNS, WHICH MATCH REMOTE MAIl # FOLDERS. SOME COMMONLY USED PATTERS INCLUDE: # # 1 "*" TO MATCH EVERYTHING # 2 "!DIR" TO EXCLUDE "DIR" # 3 "DIR" TO MATCH DIR Channel gmail-inbox Master :gmail-remote: Slave :gmail-local: Patterns "INBOX" Create Both Expunge Both SyncState * Channel gmail-trash Master :gmail-remote:"[Gmail]/Trash" Slave :gmail-local:"[Gmail].Trash" Create Both Expunge Both SyncState * Channel gmail-sent Master :gmail-remote:"[Gmail]/Sent Mail" Slave :gmail-local:"[Gmail].Sent Mail" Create Both Expunge Both SyncState * Channel gmail-all Master :gmail-remote:"[Gmail]/All Mail" Slave :gmail-local:"[Gmail].All Mail" Create Both Expunge Both SyncState * Channel gmail-drafts Master :gmail-remote:"[Gmail]/Drafts" Slave :gmail-local:"[Gmail].Drafts" Create Both Expunge Both SyncState * # GROUPS PUT TOGETHER CHANNELS, SO THAT WE CAN INVOKE # MBSYNC ON A GROUP TO SYNC ALL CHANNELS # # FOR INSTANCE: "mbsync gmail" GETS MAIL FROM # "gmail-inbox", "gmail-sent", "gmail-trash" and # "gmail-drafts" Group gmail Channel gmail-inbox Channel gmail-sent Channel gmail-trash Channel gmail-all Channel gmail-drafts
msmtp
msmtp allows delivery of emails using different SMTP servers which makes sense if you have multiple email accounts.
The configuration for msmtp is stored in .msmtp
in the home folder and again detailed explanation can be found on the relevant Arch wiki page.
It is worth to mention that you can actually achieve the same goal by using the Emacs SMTP library (as I did initially).
Below is my msmtp configuration for the Gmail account.
Note the similar way to retrieve password from the encrypted .authinfo.gpg
file for the passwordeval
line.
# Set default values for all following accounts. defaults # Use the mail submission port 587 instead of the SMTP port 25. port 587 # Always use TLS. tls on # Set a list of trusted CAs for TLS. You can use a system-wide default file, # as in this example, or download the root certificate of your CA and use that. tls_trust_file /etc/ssl/certs/ca-certificates.crt # Additionally, you should use the tls_crl_file command to check for revoked # certificates, but unfortunately getting revocation lists and keeping them # up to date is not straightforward. #tls_crl_file ~/.tls-crls logfile ~/.msmtp.log ############################################ # Gmail ############################################ account gmail host smtp.gmail.com from your_name@gmail.com auth on user your_name@gmail.com passwordeval "gpg -q --for-your-eyes-only --no-tty -d ~/.authinfo.gpg | awk '/machine smtp.gmail.com login your_name@gmail.com/ {print $NF}'" port 587
mu4e
There are more detailed documentation on how to configure mu4e from either the official documentation or other online posts. I have about 350 lines of elisp for my mu4e configuration so it does not make sense to list them all here. Below are the most core parts to get the basic email workflow working:
|
|
Password handling with GnuPG
The easiest way is to specify password in plain text directly in the configuration files, which may be a bad example for security reasons. The second one is to specify the password in a file, e.g. .authinfo
and then encrypt the file with GnuPG. When needed, a gpg decryption command can be used to retrieve the password from the encrypted file (.authinfo.gpg
).
First, I created a file .authinfo
with the following content in the home folder (notice how they match our previous password retrieval commands in .mbsync
and .msmtp
).
machine imap.gmail.com login your_name@gmail.com port 993 password your_password machine smtp.gmail.com login your_name@gmail.com port 587 password your_passward
Then encrypt the file with GnuPG to generate the encrypted file .authinfo.gpg
.
Now you can safely delete the .authinfo
file consisting of the raw password content from your computer.
If you need to modify part of the .authinfo.gpg
file, just decrypt, modify and encrypt again.
Sounds rather tedious, right?
Again Emacs comes to the rescue.
Using the Emacs Easy PG library, you can actually work on the encrypt .authinfo.gpg
file directly while let the library handles the decryption/encryption.
They are completely transparent to the users.
Since I want to sync my emails automatically every several minutes in mu4e, it would be ridiculous if I need to enter the passphrase each time. gpg-agent can solve the problem by remembering the keys in background so that I only need to type the passphrase once when I started my computer. Unfortunately, offlineimap does not play well with gpg-agent and mu4e and that is exactly why I settled down on mbsync finally.
References that helped me during my attempts
Author Fanpeng Kong
LastMod 2016-10-22