Trac from Mutt

Dedicated to those who do not want to surrender to proprietary services for code and tickets management: integrating Cartman with Mutt.


The scenario is Trac instances that send email notifications on ticket activity, as is the case with the OSGeo ones (there’s been some recent discussion about the role of its infrastructure).

The Cartman command to comment on a ticket (say #33) of a project (say postgis) would be:

cm -s postgis 33

As you usually comment on some input received by mail (either a new ticket or another comment), building that command line requires eye-parsing for project name and ticket number, and then typing it on the shell.

Mutt allows you to define a macro to do all of that with a single keystroke. Here’s the macro I’ve written for me, to map -t to trac-reply.

macro pager \Ct \
 "<pipe-message>~/bin/muttcm --save\n<shell-escape>~/bin/muttcm\n"

The ~/bin/muttcm script saves the headers of the piped message when invoked with --save; finds the most recently saved headers, parse them for Trac coordinates and invokes Cartman with appropriate arguments.

The script in its current incarnation follows, but it is very likely that it will grow in the future to adapt more to my personal needs and preferences.

That’s what makes Free Software better than any shining proprietary service after all, isn’t it ?

UPDATE: I’ve given the code a dedicated page

# Script integrating cartman (
# with mutt (
# Written (2015) by Sandro Santilli <>
# Released under Creative Commons Public Domain Dedication 1.0
# (
# Example macro to have <CTRL>-t trigger commenting on a ticket
# we're reading a mail notification of:
# macro pager \Ct "<pipe-message>~/bin/muttcm --save\n<shell-escape>~/bin/muttcm\n"
# The script expects to find a `cartman` configuration section
# matching the lowercased value of the X-Trac-Project header
# in the trac notification area.


if test "$1" = "--save"; then
 TS=`date +'%Y%m%d%H%M%S'`
 umask 0077
 sed '/^$/q' > ${FILE}
 echo "Headers saved in ${FILE}"

# find most recent file in ${TMPDIR}/*
LASTFILE=`'ls' ${TMPDIR}/* | tail -1`

PROJ=`grep '^X-Trac-Project:' "${LASTFILE}" | awk '{print $2}' | tr '[A-Z]' '[a-z]'`
TICK=`grep '^X-Trac-Ticket-ID:' "${LASTFILE}" | awk '{print $2}'`

if test -z "${PROJ}"; then
 echo "Cannot find an X-Trac-Project header"
 exit 1
if test -z "${TICK}"; then
 echo "Cannot find an X-Trac-Ticket-ID header"
 exit 1

echo 'PROJ: ' $PROJ
echo 'TICK: ' $TICK

cm -s "${PROJ}" comment "${TICK}"