Reading and writing email in Emacs
My MacBook is long out of warranty and its battery seems to be decaying, so I'm trying to move my personal computer setup to the T430s I've had sitting around as a backup, running Pop!_OS. (Is 2021 the year of the Linux desktop?)
I thought I would use this opportunity to try using Emacs to manage my email, and read a few tutorials for doing that setup. These are my notes, to help remember how I configured this house of dry spaghetti.
Create folders
Trying to keep things clean, I created a separate fastmail
folder within a new mail
folder, in case I wanted to have another folder later for other email accounts.
mkdir -p ~/mail/fastmail
Password management
Having two factor authentication turned on for my Fastmail account means I need to generate an app password.
Since I'm using Lastpass anyway, I stored the app password there and I installed the lastpass-cli package. After logging in, I could retrieve the password with::
lpass show --password <identifier for mail service>
This will work fine, but the Lastpass CLI client will sometimes timeout, and we'll need to log in again, with a graphical prompt for the password. I cam across this tutorial with a lpass-wrapper.sh
script to handle this case:
#!/bin/sh # lpass-wrapper.sh username='$username' status=$(lpass status) if [ $? -ne 0 ] then if [ "$status" = 'Not logged in.' ] then # Make sure DISPLAY is set DISPLAY=${DISPLAY:-:0} lpass login "$username" 1>&2 else echo "Lastpass error: $status" 1>&2 exit 1 fi fi lpass $@
Saving this script somewhere on the path (like ~/.local/bin
) means we can now get the password with:
lpass-wrapper.sh show --password <identifier for mail service>
when the Lastpass client has timed-out, we'll automatically get a prompt for the Lastpass master password to log back in.
retrieving emails
There is no shortage of programs to fetch email from IMAP servers. The notmuch documentation (discussed later) provides a few examples, the first two of which were offlineimap and mbsync.
offlineimap
Many tutorials that I found online use OfflineIMAP, so it looked like the right choice. Unfortunately, manually writing some configuration files based on some tutorials, I got a Python NullPointerException
without explanation and which turned out to be due to my misunderstandings of how to point offlineimap to SSL certificates. After fixing that path, I encountered a str
vs bytes
error, which revealed that OfflineIMAP is written in Python 2, and arguments about porting to Python 3 have caused a split in their community.
I have no snake in this fair, but I don't especially want to have an extra dependency on Python 2, which isn't part of the current standard installation of Ubuntu 20.10. I also encountered other posts complaining about the relatively slow performance of offlineimap, so I'll set this option aside for now and try it again if the others don't work out.
mbsync
mbsync looks like it may not have been updated in a few years, but it seems to still be working ok for now.
My .mbsyncrc
was based on these instructions, with tweaks to the PassCmd
setting:
# First section: remote IMAP account IMAPAccount fastmail Host imap.fastmail.com Port 993 User <username> PassCmd "lpass-wrapper.sh show --password <identifier for mail service>" SSLType IMAPS SSLVersions TLSv1.2 IMAPStore fastmail-remote Account fastmail # This section describes the local storage MaildirStore fastmail-local Path ~/mail/fastmail/ Inbox ~/mail/fastmail/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 *
With this configuration, running:
mbsync -a
downloaded my mail to ~/mail/fastmail
folder. Here, -a
stands for "all defined channels". I could alternatively run mbsync fastmail
to operate the fastmail
channel, which is the only currently defined channel.
indexing and tagging emails and emacs clients
Some of the Emacs clients for mail that I've come across are notmuch and mu4e, both of which seem to be preferred over GNUS. What I didn't understand was that these are both actually frontends to email indexing software, which is a nice bonus for fast searches.
notmuch
notmuch was the first frontend that I tried, following this guide. It indexed the 6,000 messages I had in my Fastmail account pretty quickly.
sudo apt install notmuch
notmuch setup
walks through an interactive setup for generating a .notmuch-config
file, which was nice. I also edited the notmuch hooks in ~/mail/.notmuch/hooks/pre-new
to add a call to retrieve mail using mbsync -qq fastmail
, kind of like the checkmail.sh
file in this tutorial.
notmuch emacs mode
notmuch comes with an Emacs frontend, which is why I started using it in the first place. It works pretty nicely. I configured it with:
I put my mail configuration stuff into an init-mail.el
file, which includes:
(use-package notmuch :disabled :ensure nil :load-path "/usr/share/emacs/site-lisp/elpa-src/notmuch-0.31/" :bind (("<f12>" . 'mu4e)) :commands (notmuch) :config (add-hook 'notmuch-hello-mode-hook (lambda () (display-line-numbers-mode 0))) :custom (notmuch-fcc-dirs "~/mail/fastmail/Sent") (notmuch-crypto-process-mime t) ; Automaticlaly check signatures )
Then in my init.el
file:
(use-package init-mail :ensure nil :custom (user-mail-address "<my email address here>") (user-full-name "<my name here>") (mail-envelope-from 'header) (mail-specify-envelope-from t) (mail-user-agent 'message-user-agent) (sendmail-program "~/.local/bin/msmtp-enqueue.sh") (send-mail-function 'sendmail-send-it) (smtpmail-queue-dir "~/mail/queue/") (message-directory "~/mail/fastmail/Drafts") (message-send-mail-function 'sendmail-send-it) (message-sendmail-envelope-from 'header) (message-kill-buffer-on-exit t) )
As it turned out, notmuch is built around tagging and showing emails matching those tags. I can see how this would be a good fit for Gmail (and I might revisit notmuch if I start using gmail through this set up too), but my Fastmail account uses a more traditional folder-based setup, and I couldn't easily figure out how to get notmuch to show me a view corresponding to my current inbox.
afew
It turns out that notmuch doesn't do much, and relies on something like afew, which can apply a chain of filters to further apply tags to emails that can be read by the notmuch client for further sorting your emails. i tried this out and copied and pasted this into ~/.config/afew/config
:
#default filter chain [SpamFilter] [KillThreadsFilter] [SentMailsFilter] sent_tag = sent [ArchiveSentMailsFilter] [InboxFilter]
This helped a bit, but still wasn't what I was expecting.
maildir-utils
Looking at the other options, maildir-utils or mu seems to be a popular choice too, so why not give it a try?
sudo apt install maildir-utils mu init -m ~/mail/fastmail --my-address=<my email address here> mu index
Seemed to index the emails about as quickly as notmuch. Also started a background process. Do I need to restart it when I reboot? Hmm.
mu4e
Turns out the Emacs frontend mu4e is not automatically installed with maildir-utils:
sudo apt install mu4e
Here's the Emacs configuration code, which I also put into init-mail.el
:
(use-package mu4e :ensure nil :load-path "/usr/share/emacs/site-lisp/mu4e/" :config (add-to-list 'mu4e-bookmarks '(:name "Inbox" :key ?i :query "maildir:/Inbox")) :custom (mu4e-get-mail-command "mbsync -qq fastmail") (mu4e-headers-date-format "%d-%m-%Y %H:%M") (mu4e-change-filenames-when-moving t) (mu4e-drafts-folder "/Drafts") (mu4e-refile-folder "/Archive") (mu4e-sent-folder "/Sent") (mu4e-trash-folder "/Trash") (mu4e-update-interval 300) (mu4e-headers-fields '((:human-date . 20) (:flags . 6) (:from . 22) (:maildir . 8) (:subject))))
This behaves more like what I expected. I added the bookmark for the Inbox folder, because otherwise I would have to manually "jump" to that folder, and Inbox isn't the first on the list.
I also had to set the individual folders because mu4e defaults to lowercase names like "drafts" and "sent".
I had some issues of the form Maildir error: duplicate UID NN
. I found this post by someone who had the same issue, and found that it was because mu4e wasn't renaming files when moving, which causes problems for mbsync. This was fixed by setting mu4e-change-filenames-when-moving
to t
.
Wanderlust
I haven't tried it yet, but another option would be to avoid downloading emails altogether and, instead, use an IMAP client in Emacs that just talks to a remote IMAP server. Wanderlust does this.
sending emails
msmtp
Following these instructions again, I set up msmtp to send mail. The tls_fingerprint
is the SHA-256 fingerprint from Fastmail's page about certificates.
# Set default values for all following accounts. defaults tls on tls_starttls off tls_fingerprint AF:01:8E:7F:FF:36:61:06:C6:F9:D4:38:D1:4E:08:98:78:C8:27:C5:E5:C0:A3:97:49:37:F2:76:90:B1:27:59 logfile ~/.msmtp.log # Fastmail account fastmail host smtp.fastmail.com port 465 from <my from email address here> auth on user <my email provider username here> passwordeval "lpass-wrapper.sh show --password <identifier for mail service> </dev/null" # Set a default account account default : fastmail
msmtpqueue scripts
The instructions refer to using msmtpqueue scripts from the Arch Wiki. As it turns out, these were already installed at /usr/share/doc/msmtp/examples/msmtpqueue/
when i installed msmtp. I copied these to ~/.local/bin
as well. The msmtp-enqueue.sh
script is referred to in the above configuration of the sendmail-program
variable in the init-mail
use-package declaration.
AppArmor woes
Trying ta actually send an email raised a permission denied error. Searching online, I found a relevant StackOverflow question and answer.
So this was solved with:
sudo ln -s /etc/apparmor.d/usr.bin.msmtp /etc/apparmor.d/disable/ sudo apparmor_parser -R /etc/apparmor.d/usr.bin.msmtp