Notmuch mail integration

notmuch (http://notmuchmail.org/) is a local mail indexer that lets you organize your mail via tags, which can be manipulated using various interfaces. It's like using gmail but much more unixy :) Although notmuch is build around a single xapian-index for each user, it doesn't loch this index completely, as sup (http://sup.rubyforge.org/) does for instance. Apart from the Emacs mode and cli binary you can manipulate your mails using go/python or ruby bindings.

Here is a starting point how you can get notmuch mail integrated in your desktop.

Pre-Awesome 3.5
I wrote a little vicious worker function to update widgets, you can get it here: https://github.com/pazz/configs/raw/master/.config/awesome/notmuch.lua It requires the json module however, which is packaged as "liblua5.1-json" in debian/ubuntu.

I put it next to my rc.lua and use it to update mail widgets this way: --rc.lua require('notmuch') ... mailicon = widget({ type = 'imagebox', name = 'mailicon'}) mailtext = widget({ type = "textbox" }) querystring = "is:inbox and not tag:killed" vicious.register(mailtext, vicious.contrib.notmuch, function (widget, args)   if args["count"] > 0 then            mailicon.image = image(beautiful.widget_mail)    else            mailicon.image = image(beautiful.widget_nomail)    end    return args["latest"]["tags"] end, 10, querystring) mailbuttons = awful.util.table.join( awful.button({ }, 1, function  awful.util.spawn("urxvt -T alot -e alot '"..querystring.."'") end) ) mailicon:buttons(mailbuttons)

the worker takes a querystring, in my case "is:inbox and not tag:killed" and returns an as "count", the number of matching messages and as "latest", a lua table that represents the latest message. Particularly, we can read the follwing keys from "latest": from, subject, id, timestamp, tags, and date_relative. That means that if you want to display the subject of the latest mail on a textwidget somewhere, read args["latest"]["subject"]

I adjusted the my maildir hoover script Email_maildir_naughty_hoover to query notmuch for messages: grap it here: https://raw.github.com/pazz/configs/master/.config/awesome/notmuchhoover.lua place it next to your rc.lua and attach it to a widget like this: require('notmuchhoover') notmuchhoover.addToWidget(mailicon, "is:inbox", 30) The first argment is your widget, the second the querystring and the last one is the maximal number of matches you want displayed. Full esample: mailicon = widget({ type = 'imagebox', name = 'mailicon'}) mailtext = widget({ type = "textbox" }) querystring = "is:inbox and not tag:killed" vicious.register(mailtext, vicious.contrib.notmuch, function (widget, args)   if args["count"] > 0 then            mailicon.image = image(beautiful.widget_mail)    else            mailicon.image = image(beautiful.widget_nomail)    end    return args["latest"]["tags"] end, 10, querystring) mailbuttons = awful.util.table.join( awful.button({ }, 1, function  awful.util.spawn("urxvt -T alot -e alot '"..querystring.."'") end) ) mailicon:buttons(mailbuttons) notmuchhoover.addToWidget(mailicon, querystring, 30) It looks like this

Awesome 3.5
This widget didn't work for me without changes in 3.5 so I decided to share an example config.

rc.lua home = os.getenv("HOME")

-- Mail widget mailicon = wibox.widget.textbox vicious.register(mailicon, vicious.widgets.mdir, function (widget, args)	if args[1] == 0       	then return string.format("")         else return string.format('✉ ' .. args[1] .. ' | ')       end end, 60, { home..'/mail/new' })

-- Mail mouse hover local mailhoover = require("mailhoover") local mail_cmd = "urxvt -e alot search is:inbox and not tag:killed"

mailfolders =  { '/home/myusername/mail/new', }

mailhoover:addToWidget(print,mailicon, "is:inbox and not tag:killed",5) mailbuttons = awful.util.table.join(       awful.button({ }, 1, function  awful.util.spawn(mail_cmd) end) ) mailicon:buttons(mailbuttons) ... (add to layout where you want) mailhoover.lua local string = string local tostring = tostring local io = io local table = table local pairs = pairs local capi = { mouse = mouse, screen = screen } local os = os local json = require("cjson") local awful = require("awful") local naughty = require("naughty") local beautiful = require('beautiful') module("mailhoover")

local popup local query_format = " %s \n " local thread_format = "%s %s (%s) "

local mailhoover = {}

function mailhoover:addToWidget(print,mywidget, querystring, maxcount) mywidget:connect_signal('mouse::enter', function 	local info = mailhoover:read_index(print,querystring,maxcount)       popup = naughty.notify({ title = "", text = string.format(query_format,querystring) .. " " .. info, timeout = 0, hover_timeout = 0.5, screen = capi.mouse.screen }) end) mywidget:connect_signal('mouse::leave', function naughty.destroy(popup) end) end

function mailhoover:read_index(print,querystring,maxcount) local info = "" local count = 0

local f = io.popen("notmuch search --format=json "..querystring) local out = f:read("*all") print(out) f:close local threads = json.decode(out)

for num,thread in pairs(threads) do       if count == maxcount then break else count = count +1 end date = os.date("%c",thread["timestamp"]) subject = thread["subject"] subject = string.gsub(subject, "&","&amp;") subject = string.gsub(subject, "<","&lt;") subject = string.gsub(subject, ">","&gt;") authors = thread["authors"] authors = string.gsub(authors, "<(.*)>","") tags = table.concat(thread["tags"],', ')

info = info .. string.format(thread_format,date,authors,subject,tags) .. '\n' -- optionally omit timestamps by removing date end return info end

return mailhoover