Previously I had been using Thunderbird for all my desktop email. It's nice. It has good PGP support (via enigmail). Just one thing really irked me: Search sucked. It was aweful. It was slow, it barely ever found what I was searching for without manually adjusting search parameters like ordering.

I am a fan of emacs. I use a heavily modified version of Spacemacs and I have tried to setup e-mail for it multiple times and never achieved what I wanted to. Most recenly I tried to setup mew but didn't get very far without being really annoyed.

Enter nix

Nix is a functional language designed to describe dependencies and software packages. It's also a package manager with the same name, as well as the namesake for NixOS, the Linux distribution I use. There is a wonderful tool based on nix called home-manager. It is inteded manage and replace your dotfiles. Besides doing what a normal dotfile manager (most likely a shell script) would do, symlinking dotfiles into place, it also offer so called modules.

Modules accept configuration as nix expressions and generate the resulting files automatically. Here is a module describing my git config:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  programs.git = {
    enable = true;
    userName = "Ben Bals";
    userEmail = "benbals@posteo.de";

    signing = {
      key = "F9119EC8FCC56192B5CF53A0BF4F64254BD8C8B5";
      signByDefault = true;
    };

    extraConfig = {
      core = {
        editor ="nvim";
      };
    };
  };
}

You might ask: Why is this better than keeping my normal gitconfig file in my dotfiles repo? Home-Manager modules all share nix syntax. That meens I can use the same language to configure my e-mail as I do to configure git or my status bar. And this languge is powerful. It has many of the niceties you would expect of a modern programming language.

Home-Manager's E-Mail module

Home-Manager allows you to declaratively configure your email setup. That makes it really easy. For example: You can set options on the module once and home-manager will take care of including them in all config files necessary. It also awards you of a common interface to change the email config without the chance of it getting out of sync.

Let's look at my email config:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{ pkgs, ... }:

{
  programs.mbsync.enable = true;
  programs.msmtp.enable = true;
  programs.notmuch = {
    enable = true;
    hooks = {
      preNew = "mbsync --all";
    };
  };

  accounts.email = {
    accounts.posteo = {
      address = "benbals@posteo.de";
      gpg = {
        key = "F9119EC8FCC56192B5CF53A0BF4F64254BD8C8B5";
        signByDefault = true;
      };
      imap.host = "posteo.de";
      mbsync = {
        enable = true;
        create = "maildir";
      };
      msmtp.enable = true;
      notmuch.enable = true;
      primary = true;
      realName = "Ben Bals";
      signature = {
        text = ''
          Mit besten Wünschen
          Ben Bals
          https://keybase.io/beb
        '';
        showSignature = "append";
      };
      passwordCommand = "mail-password";
      smtp = {
        host = "posteo.de";
      };
      userName = "benbals@posteo.de";
    };
}

Most options (like imap.host) are self explainatory, but there are some hurdles I would like to mention:

You have to install the programs necessary outside your accounts.email config. Setting accounts.email."name".mbsync.enable = true does not install mbsync. You have to install seperately. The easiest way is by setting programs.mbsync.enable = true. That's why I have that at the top of the file. That tripped me off and I had to ask the home-manager IRC channel. (Which was a quick and delightful experience.)

The parts

Managing your email this way is not a one-stop solution even though home-manager makes it seem that way a bit. Your mail is managed by a number of different programs. Let's walk through how it all works.

mbsync

This programs knows how to deal with IMAP. It fetches mail from the server and places it in a special folder called your maildir. This is where it's stored to be processed by the other tools in our chain.

The most important command is mbsync -a which syncs email for all configured accounts.

One thing I tripped over as well, is that you should set mbsync.create = "maildir" this means that folders existent on the server (like trash, archvies or whatever you have) will be created in and synced to your local maildir.

notmuch

Not much is a mail searching and indexing software. It looks and your maildir and lets you search though it extremely fast and precisely. It's called notmuch because that's what it thinks of your mail: One million messages? Not much mail! (Yes, it's that performant.)

When you get new mail (via mbsync or the programm you choose) you run notmuch new to tell it to index your maildir and make it searchable via notmuch search. It it advisable to look at the options of that command even though I ended up searching via the emacs frontend mostly.

One thing to note: I set porgrams.notmuch.hooks.preNew to mbsync -a. That means that whenever I run notmuch new it will fetch all mail via mbsync first. That makes that a lot more convenient.

notmuch-emacs

This package is a frontend built by the notmuch developers for emacs. It lets you view, search and send email from emacs. If you use spacemacs (like I do) you can simply add the notmuch layer to install it. If you have setup notmuch correctly, you should be able to hit SPC a n and have the notmuch hello screen come up.

From there you can either search your mail or enter the inbox or all mail and go from there. Either way, you're gonna end up with a list of mail. Here is a list of mail I sent to myself:

from here you can tag emails: the most important feature of notmuch. It doesn't use folders (you can force it to). The inbox folder maps to a inbox tag, spam is a tag and so on (it will sync to the server correctly, but that's not how it appears). That's what makes notmuch such and effective search and organisation tool for email.

Before I had an inbox and an archive (to keep only unanswered or emails requiring some kind of action in my inbox). With notmuch I can have that too, but also include more things. I can tag something as to-do or as pertaining to a certain project or whatever without having to build a complicated folder structure and maintain that.

Notmuch also allows you to send mail via emacs' message mode. You can configure it to use pretty much any sending program you want, even Thunderbird! A logical choice is a commandline based tool adhering to the sendmail protocol. I chose msmtp. It's easy to setup via home-manager and does it's job well.

You can configure notmuch to you liking. I have made two nice adjustments. First I have set some saved searches. These are things like "Show me me all my work email" or "show everything that is unread" you can do everything you would ever want to query your email for. You could even do something like "show me all the mails containing the word cookie in the subject line".

1
2
3
4
5
6
7
8
(setq notmuch-saved-searches
          '((:name "inbox" :query "tag:inbox" :key "i")
            (:name "unread" :query "tag:unread" :key "u")
            (:name "archive" :query "tag:archive" :key "r")
            (:name "arbeit" :query "from:@company-name.de")
            (:name "hpi" :query "to:ben.bals@student.hpi.de", :key "hpi")
            (:name "all" :query "*" :key "a"))
          )

You can open a transistent buffer with a list of these by pressing j in notmuch mode or from your hello screen. Some of the searches have shortcuts assigned to them. (j i takes me directly to me inbox.)

The other thing is a shortcut for archiving messages from the message list. I really need this in my workflow. (I do get a ton of email from uni that I have to look through. Most of it is unimportant, but not all.) Thankfully it was easy to setup:

1
2
3
4
5
(define-key notmuch-show-mode-map "a"
      (lambda ()
        "archive message"
        (interactive)
        (notmuch-show-tag (list "+archive" "-inbox" "-unread"))))

Be sure the tips and tricks page on the official notmuch site.

msmtp

I don't much to say about this one. It was configured automatically by home-manager and I don't have direct contact with it.