notmuch setup

I am a terminal enthusiast, and having keyboard bindings to hasten the workflow. When it came to email, I started using pine in college, then later found a great program called sup. Sup had a great design, but had performance and maintenance issues. This lead to a group of folks rewriting the system in a more modular way using C++. There are already articles on the web that describe how to build a system like this on Linux, I’ll focus on how to do this on a MacOS machine in this article.
Why would I want to use a system like this?
At it’s core notmuch is simply an index mechanism for your email. It reads new email into it’s index and applies tags. There are a few different front ends written for notmuch including vim, mutt, and emacs. For the purposes of this article I will focus on emacs.
The main proposition of notmuch is a fast mechanism to search your pile of email. In my previous job I had 200,000 emails in my index, and the search was faster than outlook. The notmuch design makes it possible to build a streamlined workflow based on tags tailored to help the user climb out of their personal email hell.
Installing the tools
First install notmuch. Being on an OS X machine, I used brew.
brew install notmuch
If you don’t already have emacs installed, I suggest using doom emacs. Edit the init.el in the doom.d folder and uncomment the notmuch addition, then run M-x doom/reload.
If you are using a vanilla version of email you’ll need to do something like the following, changing the version to match your environment.
ln -s /usr/local/Cellar/notmuch/0.18.1/share/emacs/site-lisp/* /Applications/Emacs.app/Contents/Resources/site-lisp
Mail delivery
Not much does not retrieve mail for you, it expects that your email is delivered to a maildir via a separate process. In the past I’ve used elaborate systems with procmail, fetchmail, and qmail. These days I choose a simpler system based on the python program called getmail.
We need to tell the MacOS keychain about our passwords. This will enable getmail and emacs to fetch the passwords more securely.
/usr/bin/security add-internet-password -a 'EMAIL_ADDRESS' -s 'POP_SERVER_ADDRESS' -r 'pop3' -w 'PASSWORD'
/usr/bin/security add-internet-password -a 'EMAIL_ADDRESS' -s 'SMTP_SERVER_ADDRESS' -r 'smtp' -w 'PASSWORD'
Install getmail via pipx.
pipx install getmail
Create the directory where email will be delivered.
mkdir -p ~/mail/{cur,new,tmp}
Create the getmail data directory, where it will cache the emails it’s seen and it’s log.
mkdir -p ~/.local/share/getmail
Next we need to configure getmail. Create the file ${HOME}/.config/getmail/getmailrc
[retriever]
type = SimplePOP3SSLRetriever
server = YOUR_POP_SERVER
port = 996
username = YOUR_EMAIL_ADDRESS
[destination]
type = Maildir
path = ~/mail
[options]
read_all = false
delete = false
delivered_to = false
recieved = false
password_command = ("/usr/bin/security")
message_log = ~/.local/share/getmail/getmail.log
The next thing to do is to hook it up as a pre-new hook in notmuch. Meaning, when you tell notmuch to poll for new messages in the maildir it will first exec the pre-new hook. My ~/.config/notmuch/default/hooks/pre-new looks something like the following.
#!/usr/bin/env bash
$HOME/.local/bin/getmail -q -r $HOME/.config/getmail/getmail -g $HOME/.local/share/getmail
Don’t forget to make the pre-new script executable
chmod +x ~/.config/notmuch/default/hoos/pre-new
At this point you should be able to run the command “notmuch new” without errors.
Enabling notmuch in emacs
In doom emacs you’ll want something like ths following:
(require 'notmuch)
(setq user-full-name "whodevil"
user-mail-address "whodevil@offthecob.info"
smtp-server-address "your.smtp.server")
(setq send-mail-function 'smtpmail-send-it
message-send-mail-function 'smtpmail-send-it
smtpmail-starttls-credentials '((smtp-server-address "587" nil nil))
smtpmail-default-smtp-server smtp-server-address
smtpmail-smtp-server smtp-server-address
smtpmail-smtp-service 587
smtpmail-debug-info t
starttls-extra-arguments nil
starttls-gnutls-program "/opt/homebrew/bin/gnutls-cli"
starttls-extra-arguments nil
starttls-use-gnutls t
notmuch-multipart/alternative-discouraged '("text/plain" "text/html"))
For easier navigation I disable evil for the notmuch modes.
(set-evil-initial-state! 'notmuch-hello-mode 'emacs)
(set-evil-initial-state! 'notmuch-show-mode 'emacs)
(set-evil-initial-state! 'message-mode 'emacs)
(set-evil-initial-state! 'notmuch-search-mode 'emacs)
Let’s also enable spell checking.
(add-hook 'message-mode-hook 'flyspell-mode)
After restarting emacs you should now be able to run M-x notmuch-show, then press “G” which exec’s “notmuch new.”
Configuring Tagging
A tagging workflow will be personal. Here is the high level on how it works. Tagging uses the query language defined by the tool. The script ~/.config/notmuch/default/hooks/post-new is called after pre-new during the notmuch new call. Here is an example of what a post-new script might look like.
#!/usr/bin/env bash
notmuch tag +github -inbox 'from:notifications@github.com and tag:inbox'
notmuch tag +github -inbox 'from:noreply@github.com and tag:inbox'
notmuch tag +review_request 'to:review_requested@noreply.github.com'
notmuch tag +cal -inbox 'mimetype:calendar and tag:inbox'
notmuch tag -unread 'tag:cal and tag:unread and subject:Accepted:'
Conclusion
I hope that whoever is reading this finds this information useful. I’m a fan of notmuch mail, and hope that someone can benefit from my experience with the system. The documentation on the notmuch website is great, and they have an active community on the mailing list and libera #notmuch irc channel.