Notmuch


For more information about notmuch, see https://notmuchmail.org.

1 Main configuration

🎯 notmuch/notmuch-config
database
user
new
search
maildir

1.1 Database

The only value supported here is 'path' which should be the top-level
directory where your mail currently exists and to where mail will be
delivered in the future. Files should be individual email messages.
Notmuch will store its database within a sub-directory of the path
configured here named ".notmuch".

For us the database section is empty because we just use the default path ~/mail.

database
[database]

1.2 User

Here is where you can let notmuch know how you would like to be
addressed. Valid settings are

name		Your full name.
primary_email	Your primary email address.
other_email	A list (separated by ';') of other email addresses
		at which you receive email.

Notmuch will use the various email addresses configured here when
formatting replies. It will avoid including your own addresses in the
recipient list of replies, and will set the From address based on the
address to which the original email was addressed.
user
[user]
name=Linus Arver
primary_email=linus@ucla.edu
other_email=linusarver@gmail.com

1.3 notmuch new

Configuration for "notmuch new"

The following options are supported here:

	tags	A list (separated by ';') of the tags that will be
		added to all messages incorporated by "notmuch new".

	ignore	A list (separated by ';') of file and directory names
		that will not be searched for messages by "notmuch new".

		NOTE: *Every* file/directory that goes by one of those
		names will be ignored, independent of its depth/location
		in the mail store.
new
[new]
tags=raw; 1

1 tags all new mails as "raw" (unprocessed).

1.5 Maildir compatibility

The following option is supported here:

	synchronize_flags      Valid values are true and false.

	If true, then the following maildir flags (in message filenames)
	will be synchronized with the corresponding notmuch tags:

		Flag	Tag
		----	-------
		D	draft
		F	flagged
		P	passed
		R	replied
		S	unread (added when 'S' flag is not present)

	The "notmuch new" command will notice flag changes in filenames
	and update tags, while the "notmuch tag" and "notmuch restore"
	commands will notice tag changes and update flags in filenames

We just use the default setting (which is synchronize_flags=true).

maildir
[maildir]

2 Tag handling

This is where we do most of the work. You can think of the settings here as an elaborate script which tags certain emails that match the query, in top-to-bottom order.

tags
🎯 notmuch/tags
tags-trash-from-gui
tags-trash-from-emacs
tags-spam
tags-sent
tags-ml-git
tags-ml-lilac
tags-ml-catchall
tags-read
tags-default-catchall

Recall that at 1 we tagged all new emails as raw. The goal is to get rid of the raw tag for every email (that is, to give them some other tag that is more meaningful that just raw).

2.1 Trash

For emails that were deleted using the web GUI (from the phone or elsewhere) out of band, keep them in the trash.

tags-trash-from-gui
-raw                -- tag:raw and tag:trash

Mark deleted emails (deleted from Notmuch via Emacs) to be moved to the trash. We work with the "deleted" tag because the default d keybinding in Emacs for notmuch adds the "deleted" tag (and we don't want to bother customizing that).

tags-trash-from-emacs
+trash -inbox -deleted -- tag:deleted

2.2 Spam

Skip any processing of all spam emails (by removing their raw tag). In particular, this makes the tags-default-catchall rule avoid considering them, keeping them out of the inbox.

tags-spam
-raw                -- tag:raw and tag:spam

2.3 Sent

Skip tagging of sent emails, just like how we skipped spam emails in tags-spam.

tags-sent
-raw                -- tag:raw and tag:sent

2.4 Mailing lists

Tag all raw mailing list messages as being unread. It's important that we do not tag it as inbox because that'll put it into the Inbox in Gmail the next time lieer syncs.

tags-ml-catchall
+unread -raw -inbox -- tag:raw and tag:list

2.4.1 Git

Tag all messages related to the Git mailing list. Gmail filters will tag these with git and git/ci and so on. Here we additionally give them a list tag so that we can search across all emails related to the mailing list at once.

tags-ml-git
+list +git          -- tag:raw and to:git@vger.kernel.org
+list +git/ci       -- tag:raw and to:ci_activity@noreply.github.com and (to:gitgitgadget/git or to:listx/git)
+list +git/ggg      -- tag:raw and from:gitgitgadget

2.4.2 Lilac

Tag all messages related to the Lilac mailing list.

tags-ml-lilac
+list +lilac -- tag:raw and 'to:"~listx/lilac@lists.sr.ht"'
+list +lilac -- tag:raw and 'from:builds@sr.ht' and 'subject:lilac'

We have to quote it twice like this, probably to get around the shell's interpretation of ~, as well as Notmuch's own special treatment of ~. We don't require the raw tag like we do for Git, because it looks like if we originally send the email to the list, it won't get the raw tag.

2.5 Read emails

Process read emails (don't tag already-read emails as unread).

tags-read
-raw                -- tag:raw and (not tag:unread)

2.6 Default catchall

For all remaining non-mailing list emails, tag them as "inbox" and "unread". This puts the into the Inbox in the web view.

tags-default-catchall
+unread -raw +inbox -- tag:raw and (not tag:list)

3 Sync script

Call lieer to sync local notmuch database (which we processed with Tag handling) with Gmail.

🎯 script/mail-sync.sh
set -euo pipefail

# Be explicit about which Notmuch configuration we're using.
export NOTMUCH_CONFIG="${HOME}/.notmuch-config"

# If we're running inside cron, we might not be aware of the usual paths used by
# Nixpkgs. Enable them here.
export PATH="${HOME}/.nix-profile/bin:/run/current-system/sw/bin:${PATH}" # 2

NOTMUCH_TAGS_FILE="${HOME}/syscfg/notmuch/tags"

main()
{
    cd ~/mail/linusarver@gmail.com

    # "gmi" is a script provided by the "lieer" package. It fetches mail from
    # Gmail to disk.
    gmi sync

    # Re-index new emails.
    notmuch new

    # Tag emails.
    notmuch tag --batch --input="${NOTMUCH_TAGS_FILE}"
}

main "$@"

Call the above script regularly via systemd (like a cronjob) on NixOS. See nixos/k0/configuration.nix.

nix:cron-mail-sync
systemd.user.services.notmuch-sync = {
  description = "Sync Gmail with lieer and update Notmuch index";
  serviceConfig = {
    Type = "oneshot";
    ExecStart = "/home/l/syscfg/script/mail-sync.sh";
    Environment = "PATH=/run/current-system/sw/bin:/usr/bin:/bin"; # 3
  };
};

systemd.user.timers.notmuch-sync = {
  description = "Run mail sync every 15 minutes";
  wantedBy = [ "timers.target" ];
  timerConfig = {
    OnBootSec = "2min";
    OnUnitActiveSec = "15min";
    Persistent = true;
  };
};

Even though the script itself sets up the PATH 2, we still need to give the environment outside of the script the right PATH 3 because the script's first line /usr/bin/env needs to be able to find bash (it won't work without 3).

To make the job run immediately, do

systemctl --user start notmuch-sync.service

To stream the logs, do

journalctl --user -u notmuch-sync.service -f

Page metrics

Tangled files (3)

  1. notmuch/notmuch-config
  2. notmuch/tags
  3. script/mail-sync.sh

Named cells (16)

  1. database
  2. maildir
  3. new
  4. nix:cron-mail-sync
  5. search
  6. tags
  7. tags-default-catchall
  8. tags-ml-catchall
  9. tags-ml-git
  10. tags-ml-lilac
  11. tags-read
  12. tags-sent
  13. tags-spam
  14. tags-trash-from-emacs
  15. tags-trash-from-gui
  16. user