Let Your Mutt Growl

2009-10-18 00:30:45 by jdixon

Like any self-respecting UNIX user, I consume most of my email through the console. Mutt has been my client of choice for a few years now. I used to be a die-hard Mail.app fan on my Apple systems, but the performance was abysmal. As time went on, I evolved from running Mutt on my laptop to running it in screen on a home server. Combined with imapfilter's client-side "push filtering", this allowed me to keep my existing mailserver architecture intact (outside the scope of this post) while gaining all the functionality I missed from a traditional fat mail client.

Recently my Facebook and Twitter Attention Span Syndrome (FaTASS) has peaked, motivating me to find creative solutions for managing the extra load. Growl is a very popular notification system that Mac OS X users have enjoyed for years. I've haven't found myself wanting for it before, mainly because I don't use an abundance of GUI apps for my daily tasks. And yet, Growl's unobtrusive nature and support for network events seemed the perfect fit.

At the risk of reusing an obvious and unimaginative moniker, I hereby announce growler. It's a short Perl script that relies on IO::Socket::SSL, Mail::IMAPClient and Net::GrowlClient. Growler will connect to your IMAP server, search your INBOX for any UNSEEN messages, and send Growl notifications to your workstation.

#!/usr/bin/perl

use strict;
use IO::Socket::SSL;
use Mail::IMAPClient;
use Net::GrowlClient;

my $imap_host = 'mail.foobar.com';
my $imap_port = '993';
my $imap_user = '[email protected]';
my $imap_pass = 'password';
my $growl_host = '10.10.0.222';
my $growl_pass = 'foobar';

my $imap = Mail::IMAPClient->new(
        User => $imap_user,
        Password => $imap_pass,
        Socket => IO::Socket::SSL->new(
                Proto => 'tcp',
                PeerAddr => $imap_host,
                PeerPort => $imap_port,
        ),
 ) || die "Unable to login: $!\n";

$imap->select("INBOX") || die $!;

my $msgs = $imap->search("UNSEEN");
if (defined $msgs) {

        my $growl = Net::GrowlClient->init(
                CLIENT_TYPE_REGISTRATION => 0,
                CLIENT_TYPE_NOTIFICATION => 1,
                CLIENT_PEER_HOST => $growl_host,
                CLIENT_PASSWORD => $growl_pass,
                CLIENT_APPLICATION_NAME => 'Mutt'
        ) || die "Unable to init: $!\n";

        for my $h ( values %{ $imap->parse_headers(
                $msgs , "From", "Subject", "Date") } ) {

                $growl->notify(
                        title => sprintf("New Email from %s",
                                $h->{'From'}->[0]),
                        message => sprintf("Date: %s\nSubject: %s", 
                                $h->{'Date'}->[0],
                                $h->{'Subject'}->[0]),
                        application => 'Mutt'
                );
        }
}

I run the script from cron on my OpenBSD home server, making sure to test for my laptop's availability first.

*/2 * * * *     ping -c1 -i10 10.10.0.222 2>&1 >/dev/null && ~/bin/growler 2>&1

Comments

at 2009-12-14 18:55:54, john_m wrote in to say...

This is exactly what I was looking for! Now if only I could make it work. Is there any way to set the imap folder, in case of INBOX being somewhere other than /

This seems to be my problem. The script is throwing the error:

2 BAD Unrecognised command, mate ...propagated at /Users/jhn/bin/growler line 25

line 25 is:

$imap->select("INBOX") || die $!;

Also what is $growl_pass?

at 2009-12-14 22:06:07, Jason Dixon wrote in to say...

You should be able to do that with the $imap->select(). The $growl_pass is used to authenticate to Growl, if you have that enabled.

Add a comment:

  name

  email

  url

max length 4000 chars