Some Uses for Org-Protocol

I have been an org-mode user for a decent amount of time (years? decades? What even is time these days?) Not quite the grandpa “back in my day” length of time that makes people roll their eyes and immediately go back to browsing Reddit on their phones, but I have done a decent amount of customization and adaptations in my workflow over time.

One issue I frequently ran into when integrating org-protocol into my workflow is that several configuration examples lying around the web simply did not work for me. Org-protocol seems to be finicky based on tool versions and system configurations.

This post is an attempt to outline how I use it on my system and to hopefully help anyone with similar problems to solve. It focuses on integrating org-protocol into a workflow along with Firefox and Mutt. Org-protocol obviously integrates with other tools as well, but I do not have experience with anything else at the moment … so here we are. This post is written with the assumption that the system has Emacs installed and that the reader has at least minimal familiarity with org-mode. It is also written from the perspective of a GNU/Linux system, so there may be some adjustments required for other types of environments.

Setup of org-protocol

The first step needed in Emacs itself is to enable org-protocol as a component of org-mode. Modern versions of org-mode ship with org-protocol. It can be enabled either by adding it to the org-modules variable in your .emacs file, or via the customization dialog accessible by invoking M-x customize-group and selecting org.

Emacs Customize GroupOrg

Org-protocol works by intercepting messages from emacsclient. In order for this work (at least in my experience), the Emacs daemon must be running on the system. There are fancier ways to set this up as a system service on startup or on user login, but I just start it with following in my .xinitrc. Since I am usually in a GUI environment anyway it has not caused any issues. As long as it is running in some capacity you should be good to go.

emacs --daemon

There are a few default handlers that org-protocol can use to process incoming data. These are outlined here.

My setup uses org-protocol-capture since it allows for capture templates, but org-protocol-store-link also works well for grabbing links and other information from a web browser.

To keep things simple I have two capture templates specifically for use with org-protocol - one for website links and one for e-mails. They both file the item as a new TODO item in my Inbox for later processing.

(setq org-capture-templates
    (quote (
        ...other capture templates...
        ("w" "web site" entry (file+headline org-default-notes-file "Inbox")
         "* TODO [[%:link][%:description]] :@web:\n\n %i" :immediate-finish t)
        ("e" "email" entry (file+headline org-default-notes-file "Inbox")
         "* TODO Read/Reply: %:description :@email:" :immediate-finish t))))

To break these down a little:

w: Adds a new TODO item with a link to the web site, using the title of the web site for the name of the link. If any text is currently selected on the page, it will be added to the body of the TODO item.

e: Adds a new TODO item prefixed with “Read/Reply:”. The headline also includes the e-mail subject and the sender.

Usage with Firefox (web browsing)

For Firefox we need to both set up the “bookmarklet” (a bookmark that executes JavaScript) to store the link, and configure Firefox to use emacsclient as the external application with which to open that type of link. I have found that the following works for links - create a new bookmark with something like this as the url:

javascript:location.href='org-protocol:/capture?template=w&url='+encodeURIComponent(location.href)+
'&title='+encodeURIComponent(document.title)+'&body='+encodeURIComponent(window.getSelection()

Note the “template=w” section. Replace “w” with whatever you named the corresponding capture template for web sites in your org-mode configuration. When used with the “w” template above, this bookmarklet will create a link with the page title as the description. If any text is selected when the bookmark is invoked, that will be added to the body of the TODO item. If no text is selected, the body will be empty.

Note that there are some other formats for bookmarklets that can be used (links at the end of this post).

Once a bookmark has been created (I recommend adding it to your bookmarks toolbar for easy access), clicking it while on a website will cause Firefox to ask you to associate an external application with “org-protocol” links. Depending on your system that may be in /usr/bin/emacsclient (or you know … somewhere else).

org-protocol Bookmark Button

After that is selected, it can be changed at any time from the Firefox settings:

Firefox Application Settings

Assuming the Emacs daemon is running, invoking that bookmark should add a new capture entry to your org-mode files per the specifications of your capture template. It can then be refiled/edited/etc. like any other entry in org-mode. For example, here is an entry in mine for this post that was made with some text selected on the page:

Capture Example Web

Note: Depending on your version/build of Firefox, there may be an additional step required. If the capture does not appear to be working, add the following option to firefox using the about:config URL to expose handling for org-protocol:

network.protocol-handler.expose.org-protocol true

Usage with Mutt (e-mail)

The setup for Mutt is more generalized and can be adapted to other input sources you may want to use with org-protocol. There are three components to it (although the first two could easily be combined) - a shell script to actually call the emacsclient executable with the appropriate arguments, an Awk script to pull the subject/sender information out of the e-mail, and of course the modifications to muttrc.

The shell script (POSIX) that calls emacsclient is straightforward. It takes one argument and uses emacsclient to send that to org-protocol. The script below uses the e template, but it can be anything as long as there is a corresponding named capture template in your org-mode configuration.

#!/bin/sh

if [ -z "${1}" ]; then
    echo "The name of the subscript to execute is required."
fi

subscript_result=$(${1})
if [ -z "${subscript_result}" ]; then
    echo "The script called did not send anything to stdout."
    return 1
fi

emacsclient "org-protocol:/capture?template=e&title=${subscript_result}"

The second script (Awk) extracts header information from the e-mail to send to the script above.

#!/usr/bin/awk -f

BEGIN {
    FS=":"
}

/^Subject:/ {
    gsub(/^[ \t]+/, "",  $2)
    subject = $2
}

/^From:/ {
    gsub(/^[ \t]+/, "", $2)
    from = $2
}

END {
    headers = subject " - " from
    print headers
}

The remaining piece is the assignment of shortcuts in the muttrc configuration. In my case the first script is called ec-helper.sh and the second is called extract-email-headers.awk.

macro index <F9> "<pipe-message>/scripts/ec-helper.sh
/scripts/extract-email-headers.awk<Enter>" "Send Message Information to Emacs"

macro pager <F9> "<pipe-message>//scripts/ec-helper.sh
/scripts/extract-email-headers.awk<Enter>" "Send Message Information to Emacs"

With this setup, hitting F9 while using the index or pager in Mutt will add the e-mail subject and sender to the org-mode Inbox similar to the capture from Firefox. For example:

Capture Example E-mail

Closing

Hopefully this gives you some ideas for incorporating org-protocol into your workflow. I have found this setup useful for quickly noting websites and videos to be viewed later with minimal disruption. Since the captured item is an org-mode task, it can be searched/edited/expanded as needed.

The Mutt integration is similarly great for tracking e-mails that need some type of follow-up, especially if there is research or information gathering involved since keeping related items in one place follows pretty naturally.

Other Resources

Below are some other resources that I have found useful while setting up and troubleshooting org-protocol.

Org-mode Documentation

Firefox Integration

Chrome Integration (not tested for this post)