Quick mu4e notes

· 1636 words · 8 minute read

mu4e is pretty good!

I went into giving mu a shot giving myself a giant side-eye for doing anything that involved running some MDA on a laptop, which is the minimum to use something like mu.

The intensity of the irritation with myself just deepened when my first pick for delivery – offlineimap – didn’t pan out and I found myself configuring isync to see if that would do any better. But isync (dba mbsync) works pretty well. It was easy to configure, I figured out how to gpg-encrypt my credentials, and I got it all set up in mackup such that I only have to configure/reconfigure in one place.

Most of my aversion to fiddling around with mail comes down to the MDA part, either because of the fragility of the component itself, or the flakiness of running these things on a laptop and how they’ll cope with being daemonized in an environment that’s not awake all the time. isync itself seems fine after several days, and it seems to be okay running as a homebrew service (with one minor caveat).

So that’s getting mail down to the machine.

mu itself – the indexing/search service for the maildir that isync creates – is pretty good. I’ve got ~231,000 messages indexed in it, and it’s super fast. As I’ve been working on cleaning up my contacts list it’s been great for just mu find "someone" from the command line. In some ways it’s almost too helpful given the volume of messages, because you get stuff like multiple reply-to’s in headers from Google+ email notifications or whatever, so one name can return 20 or 30 results in an address search.

So that brings us to mu4e.

Most of my aversion to running anything to do with ’net activity on Emacs comes down to blocking the whole app on a slow operation. I used to use GNUS for both IMAP and Usenet, and remember sometimes just having to get up and walk away during a sync until something finally got around to downloading. It was no way to live and I swore off anything to do with mail on Emacs unless I was willing to do it with an MDA of some kind in place (with all the attendant reasons I did not want to do that applying).

mu4e doesn’t even really interact with whatever we could consider a “physical” mail message, though. I mean, yes … when you write a message with it, it is creating a tmp of something that is eventually handed off to an MTA, but for reading and processing it is not touching Maildir messages in the filesystem – it is instead interacting with the mu database as a set of queries. It’s super fast. Fast the way Spotlight can be in Apple Mail, or search can be in Gmail, but consistently so.

UI-wise, mu4e is initially puzzling.

It starts from a place of “every list of mail is just a database query, not a list of files in a Maildir directory.” That’s fine. Lots of things in computing exist as vectorized representations of an object in filesystem. The difference between mu4e and some of these other styles of digital information is that not a ton of work has been done to re-translate these vectorized abstractions back into their old metaphor. So the menus, etc. talk in terms of “lists of headers” and not “folders of messages.”

Broadly, you can tell mu4e started from mu – “let’s make a mail search engine” – and then found expression as an Emacs MUA. While other MUAs include the idea of marking and operating but tend to start from a place of direct operation on a message (mutt’s an exception), mu4e starts from the assumption you’re going to mark and operate. So you don’t “delete a message,” you mark it for deletion (or moving, or whatever) then either execute your marks with the x keystroke, or sign off on executing them when you leave a given header list (i.e. what everyone else calls a folder).

It’s … I hate to even make it sound like this is a thing. If you have room in your life for setting up an MDA, a search engine for mail, and an Emacs MUA, you have whatever it is one needs to interact with a thin layer of abstraction over that whole pile of other abstractions. In some ways, mu4e feels to me like what might have happened if we chucked every innovation in mail interfaces that occurred after mh and went straight to “nah, dawg, your mail is still there on disk, but it also lives in The Matrix.” There’s just a little ramp for your muscle memory, is all.

So, what do you get in exchange, I guess?

First, it overcomes the core objection to running an MUA on Emacs at all: Everything except composing a message is a database operation, so everything is pretty fast.

People report being slowed down when trying to send messages with large attachments, and the proposed workaround (an async method you can configure) reportedly flakes out now and then. A dedicated MUA like Apple Mail might just step over that by backgrounding the send operation and letting you go on your way. Some webmail apps will give you the AJAX-y spinner until they’re done receiving the attachment, but not otherwise lock you out of using your browser. Conceivably, a big attachment with mu4e will still cost you the use of your text editor for the duration of the attachment. People who refuse to use their text editors for things besides just editing text will find that unacceptable and weird, but also know it’s a problem they’ll never have. People who think it’s right and proper to use their text editors to catch up on Mastodon, read RSS, send mail, do their calendaring, track their todos, browse the web … aaaaaaand sometimes edit a text file may be more put off.

By default, at least in Doom, it also hooks its update function into firing off your MDA so it can make sure the database has the latest messages. So when you check your mail with it, it wants to kick off an mbsync run. That doesn’t block it. I think it’s possible to configure it to just prompt a reindexing of your Maildir instead of a whole MDA run. I need to do a little more in-depth investigation of how well isync is working for me because right now I think mu4e and the Homebrew daemonization fight with each other, but the net effect is that one process gets isync to download my mail instead of the other.

Otherwise it is very, very fast, and its keyboard-centric UI is built toward getting at stuff quickly with a bunch of terse keystrokes to navigate to bookmarked mailboxes and canned search queries. Once you get the hang of marking/operating on a list of headers (with equally efficient keystrokes you can also customize) it’s a mail processing machine.

No, sorry, excuse me – it is a mail database processing machine.

I’ve previously named a few of these, but besides speed and efficiency, it offers a few other benefits:

First, I love composing mail in org mode markup. I sent myself a few test mails and loved, for instance, that an org mode src block was correctly colorized. org markup is a little more verbose than Markdown in some places. For instance, a blockquote isn’t done with a leading > but with a +begin_quote and +end_quote block.

Second, it’s easily hooked into org-capture. Here’s a capture template for putting a message in your inbox, marked for action within two days:

'("M" "process-soon" entry (file+headline "inbox.org" "Messages")
        "* TODO %:fromname: %a %?\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))")

In Doom Emacs, you get at that with SPC X M. When it’s time to deal with the message, just tap enter on the heading and mu4e opens the message. Excuse me, no, it retrieves the header from the database.

In terms of drawbacks, setup time and learning curve aside, it has a few downsides:

At least one keymapping doesn’t play well with Doom Emacs. In mu4e, the SPC key is mapped to scroll-up-command to serve as a pager, whereas that’s the leader key for Doom everywhere else. The workaround is to use OPT SPC to get to Doom’s menu, but I’m still baking that into my muscle memory.

While orgmail-mode is cool and all, it interacts weirdly with the rest of the package sometimes, and I wish I could toggle its HTML mail features on and off now and then.

Its HTML mail presentation is as woeful as any mail client that starts from plaintext land, and the remedy is the same as it is in mutt: Learn the shortcut for opening HTML mail of any complexity straight into your browser.

Finally, it doesn’t interact as well with winner mode as I’d like, leaving frames in a weird state after some operations. I did convince ChatGPT to write a hook for me to get mail composer frames to close instead of leaving the view split:

(after! mu4e
(defun my-mu4e-close-frame-after-send ()
  "Close the frame after sending a message in mu4e."
  (when (and (eq major-mode 'mu4e-compose-mode)
             (not (mu4e~message-autopgp-p)))
    (delete-frame)))

(add-hook 'message-sent-hook #'my-mu4e-close-frame-after-send))

org-mail also seems to leave behind spare buffers it uses to put together the plaintext part of its multipart messages.

Net, though, it’s so fast and efficient that I can see past most of that. I’m sort of curious about connecting mutt to notmuch to see how that works, mostly because I know mutt very, very well and feel a little more fluent when it comes to customizing it. Some of the stuff I’ve got set up in mu4e could be done with a little utility scripting in mutt.