Updates to my Notes Linking Tools

I recently improved some of my notes tools, most especially around linking to emails.

About a year and a half ago I configured my laptop to let me directly link to an email. I’ve improved on that tooling in a couple of ways since then. In short I changed the schema to mid: instead of email://, which my friend Meredith showed me was kindav a standard. Also instead of having a trailing segment that starts with @ to specify the account that the message is in, I simply search in both of my local mail accounts, assuming the Message-ID is unique. You can see those changes here.

I some software to build these links more simply. I have gotten used to using a tool to build a list of all of my open tabs into my notes system. I recently decided that I wanted to do the same thing for my email, so that I could easily “dump” my email inboxes into my notes inbox, and then just use vim’s built in delete/put functions to either dispatch the item into more contextual next step lists or just open them immediately.

I started off, as I often do, building a tool to export email to json.

Interestingly, to me anyway, this was not as straightforward as I expeced it to be. Mainly because the Go mail parser does not decode headers out of the box, or even have a method to do that. The mail packages is net/mail, but to decode your headers you need to use mime.WordDecoder’s DecodeHeader method:

	e, err := mail.ReadMessage(file)
	if err != nil {
		return errors.Wrap(err, "mail.ReadMessage, path="+path)
	}

	dec := new(mime.WordDecoder)

	s, err := dec.DecodeHeader(e.Header.Get("Subject"))
	if err != nil {
		panic(err)
	}
	fmt.Println(s)

email2json is not perfect; it only handles headers and even then only the first of a given header, but that solves my needs. I use that tool to then generate a markdown list of links based on the inboxes of both of my mail accounts:

#!/bin/sh

email2json \
    '/home/frew/var/mail/INBOX/cur/*' '/home/frew/var/mail/INBOX/new/*' \
    '/home/frew/var/zr-mail/INBOX/new/*' '/home/frew/var/zr-mail/INBOX/cur/*' |
    jq -r \
    '" * ["+.Header.Subject+"](mid:"+(.Header["Message-Id"]|match("<(.*)>")|.captures[0].string)+")"'

That’s great, I love it, but I decided that “clicking” links within vim was too much of a hassle, typically involving visually selecting the target of the link and pressing gx, so I (finally) made a mapping to do that for me.

nmap g<space> mm0f]f(vi(gx`m

Unpacking that, it maps g<space> to mark the location of the cursor into m, jump to the 0 column, find the first ], then the first (, then select all the text inside a pair of parentheses, then gx (click the link), and jump back to wherever the m mark is.

I am really surprised and how natural the g<space> mapping is. I had muscle memory in less than a day.

This has really helped me both maintail inbox zero and ensure that the emails get categorized into some meaningful context (instead of just dealing with all of them immediately.) The main risk right now is that all work emails end up in “work.” I probably need to break up the work next step lists a bit.


If you’re at all interested in the system I use for my notes, it’s based on Getting Things Done, and I’ve found it pretty helpful.

If you are inspired by all these tools that I’ve built, I suggest reading The UNIX Programming Environment.

Posted Tue, Jan 8, 2019

Receive Blog Posts in Your Email