A year with Notmuch mail
For a little longer than a year now, I have been using Notmuch as my primary means of reading email. Though the experience has not been without some annoyances, I feel that it has been a net improvement and expect to keep using Notmuch for quite some time. Undoubtedly it is not a tool suitable for everyone though; managing email is a task where individual needs and preferences play an important role and different tools will each fill a different niche. So before I discuss what I have learned about Notmuch, it will be necessary to describe my own peculiar preferences and practices.
Notmuch context
I can identify three driving forces in my attitude to email. First there is a desire to be in control. I want my email to be stored primarily on my hardware, preferably in my home. For this reason, various popular hosted email services are of little interest to me. Second is the difficulty I have with throwing things away; I'm sure I'll never want to look at 99.999% of my email a second time, but I don't know which 0.001% will interest me again, and I don't want to risk deleting something I may someday want. Finally, I am somewhat obsessive about categorization. "A place for everything, and everything in its place" is a goal, but rarely a reality, for me. Email is one area where that goal seems achievable, so I have a broad collection of categories for filing incoming mail, possibly more than I need.
My most recent experience before committing to Notmuch was to use Claws Mail as an IMAP client that accessed email using the Dovecot IMAP server running on a machine in my home. This was sufficient for many years, mostly because I work at home with good network connectivity between client and server. On those rare occasions when I traveled to the other side of the world, latency worsened and the upstream bandwidth over my home ADSL connection was not sufficient to provide acceptable service; it was bearable, but that is all. Using procmail to filter my email into different folders met most of my obsessive need to categorize, but when an email sensibly belonged in multiple categories, there wasn't really any good solution.
I think the frustration that finally pushed me to commit to the rather large step of transitioning to Notmuch was the difficulty of searching. Claws doesn't have a very good search interface and Dovecot (at least in the default configuration) doesn't have very good performance. I knew Notmuch could do better, so I made the break.
A close second in the frustration stakes was that I had to use a different editor for composing email than I used for writing code. Prior to choosing Claws, I used the Emacs View Mail mode; it had been difficult giving up that seamless integration between code editor and email editor. Notmuch offered a chance to recover that uniformity.
Notmuch of a mail system
Notmuch has been introduced and reviewed (twice) in these pages
previously so only a brief recap will be provided here. Notmuch describes
itself as "not much of an email program"; it doesn't aim to
provide a friendly user interface, just a back-end engine that indexes and
retrieves email messages. Most of the user-interface tasks are left to a
separate tool such as an Emacs mode that I use. In this
vein of self-deprecation, the web site states that
even "for what it does do, that work is
provided by an external library, Xapian
". This is a little unfair as
Notmuch does contain other functionality. It decodes MIME messages in
order to index the decoded text with the help of libgmime. It manages a
configuration file with the help of g_key_file
from GLib. And it will decrypt encrypted messages, using GnuPG. It even
has some built-in functionality for managing tags and tracking message
threads.
The genius of Notmuch is really the way it combines all these various libraries together into a useful whole that can then be used to build a user interface. That interface can run the Notmuch tool separately, or can link with the libnotmuch library to perform searches and access email messages.
Notmuch need for initial tagging
Notmuch provides powerful functionality but, quite appropriately, does not impose any particular policy for how this functionality should be used. It quickly became clear to me that there is a tension between using tags and using saved searches as the primary means of categorizing incoming email. Tags are simple words, such as "unread", "inbox", "spam", or "list-lkml", that can be associated with individual messages. Saved searches were not natively supported by Notmuch before version 0.23, which was released in early October (and which calls them "named queries"), but are easily supported by user-interface implementations.
Using tags as a primary categorization is the idea behind the "Approaches to initial tagging" section of the Notmuch documentation. This page provides some examples of how a "hook" can be run when new mail arrives to test each message against a number of rules and then to possibly add a selection of tags to that message. The user interface can then be asked to display all messages with a particular tag.
I chose not to pursue this approach, primarily because I want to be able to change the rules and have the new rule apply equally to old emails, which doesn't work when rules are applied at the moment of mail delivery. The alternative is to use fairly complex saved searches. This ran into a problem when I wanted one saved search to make reference to another, as neither the Emacs interface nor the Notmuch backend had a syntax including one saved search in another search. For example, I have one saved search to identify email from businesses (that I am happy to receive email from) whose mail otherwise looks like spam. So my "spam" saved search is something like:
tag:spam and not saved:commercial
The new "named queries" support should make this easy to handle but, until I upgrade my Notmuch installation, I have a wrapper script around the "notmuch" tool that performs simple substitutions to interpolate saved searches as required.
It also causes a minor problem in that I have several saved searches that are intermediaries that I'm not directly interested in, but which still appear in my list of saved searches. Those tend to clutter up the main screen in the Emacs interface.
Unfortunately, the indexing that Notmuch performs is not quite complete, so some information is not directly accessible to saved searches, resulting in the need for some limited handling at mail delivery time. Notmuch does not index all headers; two missed headers that are of interest to me are "X-Bogosity" and "References".
I use bogofilter to detect spam, which adds the "X-Bogosity" header to messages to indicate their status. Further, when someone replies to an email that I sent out, I like that reply to be treated differently from regular email, and particularly to get a free pass through my spam filter. I can detect replies by simple pattern matching on the References or In-reply-to headers. While Notmuch does include these values in the index so that threads can be tracked, it does not index them in a way that allows pattern matching, so there is no way for Notmuch to directly find replies to my emails.
To address this need, I have a small procmail filter that runs bogofilter and then files email in one of the folders "spam", "reply", or "recv" depending on which headers are found. Notmuch supports "folder:" queries for searches, so that my saved search can now differentiate based on these headers that Notmuch cannot directly see.
I find that tags still are useful, but that use is largely orthogonal to classification based on content. When new mail arrives, it is automatically tagged as both "unread" and "inbox". When I read a message, the "unread" tag is cleared; when I archive it, the "inbox" tag is cleared. I would like an extra tag, "new", which would be cleared as soon as I see the subject in a list of new email, but the Emacs interface I use doesn't yet support that.
There are other uses for tags, such as marking emails that I should review when submitting my tax return or that need to be reported to bogofilter because it guessed wrongly about their spam status, but they all reflect decisions that I consciously make rather than decisions that are made automatically.
Notmuch remote access
Remote access via IMAP can be slow, but that is still faster than not having remote access at all, which is the default situation when the mail store only provides local access. I have two mechanisms for remote access that work well enough for me.
When I am in my home city, I only need occasional remote access; this is easily achieved by logging in remotely with SSH and running "emacsclient -t" in a terminal window. This connects to my running Emacs instance and gives me a new window through which I can access Notmuch almost as easily as on my desktop. A few things don't work transparently, viewing PDF files and other non-text attachments in particular, but as this is only an occasional need, lack of access to non-text content is not a real barrier. Here we see again the genius of Notmuch in making use of existing technology rather than inventing everything itself. Notmuch isn't contributing at all to this remote access but, since it supports Emacs as a user-interface, all the power of Emacs is immediately available.
For times when I am away from home and need more regular and complete remote access, there is muchsync, a tool that synchronizes two Notmuch mail stores. All email messages are stored one per file, so synchronizing those simply requires determining which files have been added or removed since the last synchronization and copying or deleting them. Tags are stored in the Xapian database, so a little more effort is required there but, again, muchsync just looks to see what has changed since the last sync and copies the relevant tags. I don't know yet if muchsync will synchronize the named queries and other configuration that can be stored in the database in the latest Notmuch release. Confirming that is a major prerequisite to upgrading.
Before discovering muchsync, I had used rsync to synchronize mail stores; I was happy to find that muchsync was significantly faster. While rsync is efficient when there are small changes to large files, it is not so efficient when there are small changes to a large list of files. The first step in an rsync transaction is to exchange a complete list of file names, which can be slow when there are tens of thousands of them. Muchsync doesn't waste time on this step as it remembers what is known to be on the replica, so it can deduce changes locally.
With muchsync, reading email on my notebook is much like reading email on my desktop. Unfortunately, I cannot yet read email on my phone, though I don't personally find that to be a big cost. There is a web interface for Notmuch written in Haskell, but I have not put enough effort into that to get it working so I don't know if it would be a usable interface for me.
When Notmuch mail is too much
As noted above, I don't like deleting email because I'm never quite sure what I want to keep. Notmuch allows me to simply clear the inbox flag; thereafter I'll never see the message again unless I explicitly search for older messages, as my saved searches all include that tag. As a result, I haven't deleted email since I started using Notmuch and have over 600,000 messages at present (528,000 in the last year, over half of that total from the linux-kernel mailing list). The mail store and associated index consume nearly ten gigabytes. I'm hoping that Moore's law will save me from ever having to delete any of this. This large store allows me to see if very large amounts of email is too much or if, as the program claims, "that's not much mail".
As far as I can tell, the total number of messages has no effect on operations that don't try to access all of those messages, so extracting a message by message ID, listing messages with a particular tag, or adding or clearing a tag, for example, are just as fast in a mail store with 100,000 messages as in one with 100 messages. The times when a lot of mail can seem to be too much is when a search matches thousands of messages or more. There are two particular times when I find this noticeable.
As you might imagine, given my need for categorization, I have quite a
few saved searches. The Emacs front end for Notmuch has a
"hello" page that helpfully lists all the saved searches
together with the number of matching messages. Some of these searches are
quite complex and, while the complexity doesn't seem to be a particular
problem, the number of matches does. Counting the 217,952 linux-kernel messages
still marked as in my inbox takes
four to eight seconds, depending on the hardware. It only takes a few saved
searches that take more than a couple of
seconds for there to be an irritating lag when Emacs wants to update the
"hello" page. Similarly, generating the list of matches for a
large search can take a couple of seconds just to start producing the list,
and much longer to create the whole list.
None of these delays need to be a problem. Having precise up-to-the-moment counts for each search is not really necessary, so updating those counts asynchronously would be perfectly satisfactory and rarely noticeable. Unfortunately, the Notmuch Emacs mode updates them all synchronously and (in the default configuration) does so every time the "hello" window is displayed. This delay can become tiresome.
When displaying the summary lines for a saved search, the Emacs interface is not synchronous, so there is no need to wait for the full list to be generated, but one still needs to wait the second or two for the first few entries in a large list to be displayed. If the condition "date:-1month.." is added to a search, only messages that arrived in the last month will be displayed, but they will normally be displayed without any noticeable delay as there are far fewer of them. The user interface could then collect earlier months asynchronously so they can be displayed quickly if the user scrolls down. The Emacs interface doesn't yet support this approach.
Notmuch locking
As a general rule, those Notmuch operations that have the potential to be slow can usually be run asynchronously, thus removing much of the cost of the slowness. Putting this principle into practice causes one to quickly run up against the somewhat interesting approach to locking that Xapian uses for the indexing database.
When Xapian tries to open the database for write access and finds that it is already being written to, its response is to return an error. As I run "notmuch new" periodically in the background to incorporate new mail, attempts to, for example, clear the "inbox" flag sometimes fail because the database cannot be updated, and I have to wait a moment and try again. I'd much rather Notmuch did the waiting for me transparently.
If one process has the database open for read access and another process wants write access, the writer gets the access it wants and the reader will get an error the next time that it tries to retrieve data. This may be an appropriate approach for the original use case for Xapian but seems poorly suited for email access. It was sufficient to drive me to extend my wrapper script to take a lock on a file before calling the real Notmuch program, so that it would never be confronted with unsupported concurrency.
The most recent version of Xapian, the 1.4 series released in recent months, adds support for blocking locks, and Notmuch 0.23 makes use of these to provide a more acceptable experience when running Notmuch asynchronously.
Working with threads
One feature of Notmuch that I cannot quite make my mind up about is the behavior of threads. In a clear contrast to my finding with JMAP, the problem is not that the threads are too simplistic, but that they are rich and I'm not sure how best to tame them.
As I never delete email, every message in a thread remains in the mail store indefinitely. When Notmuch performs a search against the mail store it will normally list all the threads in which any message matches the search criteria. The information about the thread includes the parent/child relationship between messages, flags indicating which messages matched the search query, and what tags each individual message has.
The Emacs interface uses the parent/child information to display a tree structure using indenting. It uses the "matched" flag to de-emphasize the non-matching messages, either greying them out in the message summary list or collapsing them to a single line in the default thread display, which concatenates all messages in a thread into a single text buffer. It uses some of tags to adjust the color or font such as to highlight unread messages.
This all makes perfect sense and I cannot logically fault it, yet working with threads sometimes feels a little clumsy and I cannot say why. The most probable answer is that I haven't made the effort to learn all the navigation commands that are available; a rich structure will naturally require more subtle navigation and I'm too lazy to learn more than the basics until they prove insufficient. Maybe a focus on some self-education will go a long way here. Certainly I like the power provided by Notmuch threads, I just don't feel that I personally have tamed that power yet.
Notmuch of a wish list
Though I am sufficiently happy with Notmuch to continue using it, I always seem to want more. The need for sensible locking and for native saved searches should be addressed once I upgrade to the latest release, so I expect to be able to cross them off my wish list soon.
Asynchronous updates of the match-counts for saved searches and for the messages in a summary is the wish that is at the top of my list, but my familiarity with Emacs Lisp is not sufficient to even begin to address that, so I expect to have to live without it for a while yet.
One feature that is close to the sweet spot for being both desirable and achievable is to support an outgoing mail queue. Usually when I send email it is delivered quite promptly, thought not instantly, to the server for my email provider. Sometimes it takes longer, possibly due to a network outage, or possibly due to a configuration problem. I would like outgoing email to be immediately stored in the Notmuch database with a tag to say that it is queued. Then some Notmuch hook could periodically try to send any queued messages, and update the tag once the transmission was successful. This would mean that I never have to wait while mail is sent, but can easily see if there is anything in the outgoing queue, and can investigate at my leisure.
There are plenty of other little changes I would like to see in the user interface, but none really interesting enough to discuss here. The important aspect of Notmuch is that the underlying indexing model is sound and efficient and suits my needs. It is a good basis on which to experiment with different possibilities in the user interface.
| Index entries for this article | |
|---|---|
| GuestArticles | Brown, Neil |
Posted Nov 9, 2016 20:03 UTC (Wed)
by josh (subscriber, #17465)
[Link] (1 responses)
Posted Nov 10, 2016 2:36 UTC (Thu)
by drag (guest, #31333)
[Link]
That's what I would like to see.
A IMAP server were the folders are logically constructed based on notmuch queries. No editing or moving or copying around of the original emails at all.
Posted Nov 9, 2016 20:24 UTC (Wed)
by tnoo (subscriber, #20427)
[Link]
As for asynchronous mail delivery: since notmuch does not deliver email, you could use something like msmtp, and the scripts to queue mail delivery.
Posted Nov 9, 2016 20:31 UTC (Wed)
by adirat (subscriber, #86623)
[Link] (1 responses)
Posted Nov 10, 2016 8:52 UTC (Thu)
by kzar (guest, #89626)
[Link]
Posted Nov 9, 2016 22:13 UTC (Wed)
by tridge (guest, #26906)
[Link]
Posted Nov 10, 2016 7:02 UTC (Thu)
by mones (subscriber, #59698)
[Link] (2 responses)
Posted Nov 10, 2016 8:02 UTC (Thu)
by neilbrown (subscriber, #359)
[Link] (1 responses)
The syntax for describing a search is rather cryptic. The pop-up cheat-sheet helped but I have a memory that it didn't always help enough. Possibly it didn't make clear to me how quoting works - i.e. how to search for a string containing a space.
I like saved searches. Claws does provide a recent history in a drop-down which helps, but doesn't help very much.
If the window which listed all mailboxes included some widget which meant "select this and apply the current search", and if you selected anywhere else it would select the mailbox without the current search, that might have felt easier to work with.
Posted Nov 10, 2016 8:24 UTC (Thu)
by mones (subscriber, #59698)
[Link]
Anyway, these you wrote are interesting points, thanks!
Posted Nov 10, 2016 9:57 UTC (Thu)
by jani (subscriber, #74547)
[Link] (1 responses)
While working on Notmuch, I've perceived everyone has their very own and personal way of managing email. Instead of forcing people into some workflow, we need to give people tools to support their workflows. Mechanism, not policy, if possible. That said, I like to encourage people to try and improve their workflows when switching to Notmuch, because there's so much more to it than your traditional mail client. One of the things I keep repeating is, folders are so 90s, tags are so 00s, saved searches are 10s. Personally, I don't understand the desire to categorize and label and tag a lot of stuff up front, manually or automatically, when in the end you can often just search for it, and have aliases for those queries. Giving up the, in my experience, futile attempts to categorize the firehose of email pointed at my general direction has been very liberating. But, as I said, your mileage *does* vary.
There's another alternative to remote access with the Notmuch Emacs interface. Because the UI uses the Notmuch command-line interface, you can create a wrapper for the notmuch binary that runs it over ssh. So you'll have the Notmuch UI in local Emacs, but have your mail store, Notmuch database and Notmuch CLI on a remote machine. This allows you to e.g. save attachments on the local machine transparently. I use this on a daily basis, and IMHO it really works quite well. Details at https://notmuchmail.org/remoteusage/.
I see the problem with the Notmuch Emacs main screen ("notmuch hello") being slow with plenty of searches. I think most of the developers have moved on to using the "jump menu" where you can access your saved searches using 'j' key binding from basically any Notmuch buffer, without going through hello. You can define the shortcut keys for the jump menu through the customization interface. That said, we should fix this. In the mean time, saved searches also allow you to define your own function to use for counting the number of matches in hello; depending on your elisp-fu, you can do clever things there.
For viewing threads, there are two alternatives, called show view and tree view. The former is a bit Gmail like, with the thread structure done using indentation. You can change the indentation according to your preferences, also to 0 if you like a flat view like Gmail. The latter is similar to mutt, with a thread structure pane and a message pane for showing a single message at a time. You can usually switch between the two by hitting 'Z' or 'S'. See https://notmuchmail.org/screenshots/. Does this help with the thread structure woes?
With Notmuch 0.23 I think you could hack up the mail queue thing. We've switched to using 'notmuch insert' for Fcc, which indexes the outgoing messages, and lets you tag them. So you could build something around that. But, as you know, only the Emacs interface sends mail, and all of that is offloaded to what's available in Emacs already.
Posted Nov 10, 2016 12:35 UTC (Thu)
by jani (subscriber, #74547)
[Link]
Please send your feature requests and bug reports to the Notmuch mailing list. We track them as email, naturally. (If the only tool you have is a mail client, all problems look like email.)
You could try turning off notmuch-hello-auto-refresh option to speed up notmuch hello.
Posted Nov 10, 2016 18:34 UTC (Thu)
by sagi (subscriber, #64671)
[Link] (1 responses)
The only current notmuch nit I have is MDA integration, e.g. direct delivery from postfix with notmuch insert --keep to avoid having to "poll" using notmuch new. You run into the same locking issues there, worst case communicating back delivery failures. Though I reported a bug and wrote a hacky patch, I have been too lazy to finalize and upstream it.
Afew is worth checking out for automated tags based on e.g. List-Id. It also provides functionality to move mails between folders based on tags, which makes your backup IMAP able to show say just your inbox.
Posted Nov 10, 2016 20:49 UTC (Thu)
by jani (subscriber, #74547)
[Link]
Posted Nov 12, 2016 14:50 UTC (Sat)
by lmb (subscriber, #39048)
[Link] (5 responses)
For syncing mails, I currently use offlineimap (I need to evaluate isync), and for outgoing mails msmtp with those queuing scripts. That all works together with mobile clients too.
But, yes, notmuch is awesome!
Posted Nov 14, 2016 9:33 UTC (Mon)
by peterhoeg (guest, #4944)
[Link] (4 responses)
1) it is MUCH faster
2) it doesn't hang the way that offlineimap does
It was item 2 that drove me to isync - item 1 was simply an unexpected benefit.
Posted Nov 14, 2016 12:06 UTC (Mon)
by mathstuf (subscriber, #69389)
[Link] (3 responses)
Posted Nov 16, 2016 15:59 UTC (Wed)
by k8to (guest, #15413)
[Link] (2 responses)
In older versions of offlineimap, it at least had the good behavior to bail out on ctrl-c, so I could just cancel/restart it on trouble, nowadays it blocks that in some weird attempt to "complete" the sync operation, when there's this extremely commonly known hang behavior. So I have to carry patches around to unbreak it.
I didn't know about isync, probably will move to it if it works.
Posted Aug 12, 2017 23:13 UTC (Sat)
by lsl (subscriber, #86508)
[Link] (1 responses)
Recent versions let you force quit using an additional pair of INTs.
Posted Aug 13, 2017 2:41 UTC (Sun)
by mathstuf (subscriber, #69389)
[Link]
Posted Nov 30, 2016 2:01 UTC (Wed)
by donio (guest, #94)
[Link]
1. The new Glass backend in Xapian 1.4+ speeds up searches and reduces the index size. Switching to this requires re-indexing all the mail which took several hours but was well worth it. (Make sure to backup and restore your tags)
2. Recent notmuch versions can take advantage of the new XAPIAN_DB_RETRY_LOCK feature to wait for the xapian db lock instead of exiting with an error. This got rid of some annoying search failures that sometimes happened when indexing a large batch of new mail. Enabling this just requires a recent enough notmuch compiled against a recent enough libxapian.
A year with Notmuch mail
A year with Notmuch mail
bonus: integration with org-mode
A year with Notmuch mail
A year with Notmuch mail
notmuch and mail.runner
I use it with mail.runner, a shell script wrapper around rsync for grabbing mail efficiently over ssh
https://github.com/tridge/junkcode/blob/master/mail.runner
A year with Notmuch mail
A year with Notmuch mail
I also would often like a search to cross-over mailboxes. I don't think Claws supports that.
You can set up a search, then move from mailbox to mailbox and keep the search active which is sometimes nice, and sometimes annoying. I think it is configurable whether the search stays active when you switch mailboxes. Sometimes I want it to, sometimes not. Sometimes when I switch away, then switch back I want the old search to still be active, sometimes not.
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
A year with Notmuch mail
