Still, a lot of Free and Open Source Software(FOSS) projects use mailing lists as the primary form of communication and more importantly: sending patches. As my new job required following certain Linux mailing lists, it all seemed very new as I never had a mailing list-based workflow before. The key differentiator in a mailing list-based workflow is that there is going to be a huge influx of emails but not all of them are relevant to you. So the challenge that many people face when they start is filtering emails. Letting all emails go to the inbox and then filtering them manually is an arduous task that will soon prove to be futile.

In this article, I will try to cover some tips and tricks to handle mailing lists and make it as usable as a part of the daily workflow.

I use Gmail to subscribe to mailing lists and it was almost impossible to follow things via the web-based Gmail client. I even tried setting up filters but it still didn’t feel “right” to me. After trying multiple clients such as Thunderbird, and talking to people, I finally found the one: NeoMutt + notmuch based on my colleague’s suggestion. Initially, it felt like a daunting task to set it up but the final result gave me that peace of mind that I am never planning to look back. I hope explaining my workflow can help others and make parsing through the mailing list a bit less scary.

NeoMutt is a command-line mail reader (and a fork of Mutt) and notmuch is an awesome Mail Indexer. Mbsync(iSync) will be used as a way to synchronize mails with the mail server through IMAP. As mbsync downloads the email locally, it is very useful for offline viewing. We will not go over mbsync setup here but there is a good ArchWiki page. As a prerequisite, make sure the mails are synced using mbsync locally to a folder in MailDir format.

The basic idea is to filter and tag the incoming emails with notmuch and use Neomutt’s inbuilt notmuch integration to view the emails on a per tag basis.

Notmuch

Notmuch allows to compose logical rules to add tags to an email. My notmuch configuration is very basic and it is as follows:

[database]
path=<path-to-maildir>

[user]
name=<name>
primary_email=<email>

[new]
tags=unread;

[search]
exclude_tags=spam;

[maildir]
synchronize_flags=true

Once this is wired, tags can be applied to the emails based on our custom rules.

My strategy is to apply a unique tag per mailing list. But there could be cases where there is a single mailing list for different topics. I will also show a technique where we can add some filters to only extract relevant emails from that mailing list.

Syncing script

An easy way to manage and apply tags with notmuch is to create a custom script that can run every time we want to download emails locally. The script will run mbsync to synchronize emails and run notmuch to apply tags on them.

Syncing script example:

#!/bin/sh

/usr/bin/mbsync <mbsync-group>

notmuch new

#Example tagging for the linux block layer mailing list
notmuch tag +block -- cc:linux-block@vger.kernel.org or to:linux-block@vger.kernel.org
notmuch tag +io_uring -- cc:io-uring@vger.kernel.org or to:io-uring@vger.kernel.org

Syncing script also allows us to mark some unwanted mails to be marked as read. I follow the development of NVMe emulation in QEMU but there is a single mailing list in QEMU for the whole block layer. notmuch has tagging also based on Subject. As I know the email that is of my interest has the hw/nvme in the Subject line, I do the following in my syncing script to only extract the relevant emails:

notmuch tag +qemu-nvme -- cc:qemu-block@nongnu.org or to:qemu-block@nongnu.org and subject:"hw/nvme"

# I am not interested in anything that is not related to hw/nvme
notmuch tag -unread -- cc:qemu-block@nongnu.org or to:qemu-block@nongnu.org not tag:qemu-nvme

The mails coming from qemu-block@nongnu.org and do not contain the subject:hw/nvme are automatically marked as read. As the reader might notice, this is a very useful feature to declutter the Mailbox from unwanted emails.

Github notifications

This technique can also be extended to following PRs for projects that are hosted on Github. Once the notification via email is enabled for PRs in Github, a custom notmuch tag can be applied on the Subject to filter out PRs that are not interesting.

For example, to follow only the developments in the Kernel in SerenityOS, the following rule can be added:

notmuch tag +serenity-kernel -- to:serenity@noreply.github.com and subject:"Kernel"
notmuch tag +serenity -- tag:personal and to:serenity@noreply.github.com        
                                                                                
# I am not interested in anything that is not related to Kernel and not directed to me
notmuch tag -unread -- to:serenity@noreply.github.com and not tag:serenity-kernel and not tag:serenity

Of course, the project that is being followed should have some sort of a contributing guideline that enforces the subsystem to be mentioned in the Subject or the Body.

Neomutt + Notmuch integration

Neomutt has this concept of virtual-mailboxes that takes description or a notmuch URL as its input. Neomutt has a custom syntax for notmuch search arguments which is used to construct the notmuch URL.

Ideally, it is better to create a virtual mailbox per notmuch tag in neomutt.

This is my configuration for the virtual-mailbox which goes in neomutt config:

#neomuttrc

virtual-mailboxes "block" "notmuch://?query=tag:block%20and%20tag:unread"
virtual-mailboxes "io_uring" "notmuch://?query=tag:io_uring%20and%20tag:unread"

The “block” virtual-mailbox will show only new mails that come from the linux-block mailing list (the same applies to “io_uring” virtual-mailbox). I prefer to only see the new emails from the respective mailing list instead of seeing it along with the old emails from that mailing list.

Pruning and Reading

Not all emails in a mailing list might be of importance so my workflow involves a pruning step where I get rid of uninteresting patches and I mark patches that I want to revisit later with a todo tag. Neomutt allows to easily tag a mail with a shortcut as follows:

macro index,pager tt "<modify-labels>!todo\n" "Toggle the 'todo' tag"

The above macro binds tt with toggling the todo tag on an email.

So while pruning the mails, I tag the important emails with a todo tag so that I can go through them later. The virtual-mailbox configuration with todo tag is as follows:

virtual-mailboxes "todo" "notmuch://?query=tag:todo"
virtual-mailboxes "block" "notmuch://?query=tag:block%20and%20tag:unread%20and%20not%20tag:todo"
virtual-mailboxes "io_uring" "notmuch://?query=tag:io_uring%20and%20tag:unread%20and%20not%20tag:todo"

The above virtual-mailbox rule allows ignoring emails with todo label that are there in the block and io_uring virtual-mailbox. This is useful while pruning the mailing list as I don’t want to see the email with todo tag even if it is unread.

TIP: Add a macro that calls the syncing script from NeoMutt. I have configured S to run the syncing script:

macro index S "<shell-escape><path-to-syncing-script> 2>&1<enter>" "sync email and notmuch"

TIP: Github sends the link of the patch/diff file in the email. A simple macro can be added to download the diff file locally as follows:

bind index,pager O noop
macro index,pager O "| grep \"\^https\.\*diff\$\" | xargs wget "

Conclusion

That is it for this article. I will try to keep this article up-to-date as I learn new tricks to optimize my workflow.

This setup avoids the need to go to the main Inbox folder and rather directly jump into the mails with relevant tags. Personally, this setup creates less cognitive overhead and less context switching because the relevant emails are filtered and organized.

Setup\label{classdiag}
My neomutt + notmuch setup

Useful articles:

Hope you enjoyed the article and found it helpful. Happy mailing!