Automatic Calendar Management — Notmuch + Calypso
One of the big “features” of outlook/exchange in my world is automatically merging of incoming calendar updates from email. This makes my calendar actually useful in knowing what meetings people have asked me to attend. As I'm not willing to otherwise tolerate outlook, I decided to try and provide that in my preferred environment; notmuch and calypso.
Identifying calendar updates
The first trick is how to identify incoming messages with calendar updates. I'd love to be able to search for specific mime content types, but I haven't been able to construct such a search. Failing that, I'm just looking for messages containing the string 'text/calendar':
notmuch search --output=messages tag:inbox AND text/calendar
Next, I want to skip over previously scanned calendar updates, so I'll plan on tagging messages that have been scanned with the 'calendar' tag and skip those:
notmuch search --output=messages tag:inbox AND text/calendar AND not tag:calendar
jq — sed for json
With the messages containing likely calendar entries identified, the remaining task is to extract the MIME section containing the actual calendar data. Notmuch can generate json for the message, leaving us only needing to parse the json and extract the relevant section. I found the 'jq' tool in the archive, which looks like a rather complicated parsing and reformatting tool for json data. It took a while to understand, but I managed to generate a command string that takes a notmuch message and pulls out the content for all text/calendar elements:
jq -r '..| select(."content-type"? == "text/calendar") | .content'
This is a recursive walk over the data structure. It looks for structures with "content-type": "text/calendar" and dumps their "content" elements in raw text form.
Putting it all together
Here's the complete script:
#!/bin/bash
SEARCH="tag:inbox AND not tag:calendar AND text/calendar"
TMP=`mktemp`
trap "rm -r $TMP" 0 1 15
notmuch search --output=messages $SEARCH | while read message; do
notmuch show --format=json $message |
jq -r '.. | select(."content-type"? == "text/calendar") | .content' > $TMP
if [ -s $TMP ]; then
calypso --import private/calendar $TMP && notmuch tag +calendar $message
else
notmuch tag +calendar $message
fi
done
I'd love to fix calypso's --import operation to talk to the local calypso daemon with the database loaded; the current mechanism actually loads the entire database into a new process and then applies the new data to that. With my calendar often containing hundreds of entries, that takes a while.