December 8, 2007

Gmail notify for dzen

16 June 2008 Update: I have updated the notifier - please read here for details


Notification of new mail in my gmail account is very important to me on my desktop and therefore that was the first thing I tried to solve once I set up xmonad and dzen. Fortunately, it wasn't that difficult. The following script checks the mail and formats the output for the latest development version of dzen2 (see previous post).
To use it, add your username and password and edit the other variables to change the color of the output, number of new mails to show and words to show in the subject for each mail. Note that I have opted to put the password in a hidden file with proper permissions and the script reads the file for the password.

You can read more about this and download the script from the dzen wiki here.




#!/usr/bin/env python

#========================================================================
# Copyright 2007 Raja <rajajs@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#==========================================================================

# ======================================================================
# Modified from code originally written by Baishampayan Ghose
# Copyright (C) 2006 Baishampayan Ghose <b.ghose@ubuntu.com>
# ======================================================================


import urllib
import feedparser

_url = "https://mail.google.com/gmail/feed/atom"

################## Edit here #######################

#pwd = xxxx # pwd stored in script
_pwdfile = '/path_to/hidden/pwd_file' # pwd stored in a file
_username = 'XXXX'
_calmcolor = 'white'
_alertcolor = 'red'
_maxmails = 5 # maximum new mails to show
_maxwords = 3 # maximum words to show in each mail header

###########################################################

class GmailRSSOpener(urllib.FancyURLopener):
'''Logs on with stored password and username
Password is stored in a hidden file in the home folder'''

def prompt_user_passwd(self, host, realm):
#uncomment line below if password directly entered in script.
pwd = open(_pwdfile).read()
return (_username, pwd)

def auth():
'''The method to do HTTPBasicAuthentication'''
opener = GmailRSSOpener()
f = opener.open(_url)
feed = f.read()
return feed

def showmail(feed):
'''Parse the Atom feed and print a summary'''
atom = feedparser.parse(feed)
newmails = len(atom.entries)
if newmails == 0:
title = "^fg(%s) You have no new mails" % (_calmcolor)
elif newmails == 1:
title = "^fg(%s) You have 1 new mail" % (_alertcolor)
else:
title = "^fg(%s) You have %s new mails" % (_alertcolor,newmails)

# print the title with formatting
print "^tw()" +title
#clear the slave window
print "^cs()"

#then print the messages
for i in range(min(_maxmails,newmails)):

emailtitle = atom.entries[i].title
# show only first few words if title is too long
if len(emailtitle.split()) > _maxwords:
emailtitle = ' '.join(emailtitle.split()[:_maxwords])

print "^fg(%s) %s from %s" % (_calmcolor, emailtitle, atom.entries[i].author)

if __name__ == "__main__":
feed = auth()
showmail(feed)




This bash script calls the dzenGmailNotify script at specified intervals.


#!/bin/bash

#checkgmail.sh

while true ; do
python dzenGmailNotify.py
sleep 30
done


Finally, make the above executable and add this to .xsession to display in dzen.


./checkgmail.sh | dzen2 -ta r -l 5 -bg '#808080' -x 700 -w 380 &

6 comments:

Bijoy said...

I tried running this as a python script by doing

python dzenGmailNotify.py

and it kept hanging.

I inserted a print statement before the return statement in the prompt_user_passwd() method and it seems like the method is being called multiple times. But the username and passwd that I entered in the script are correct

Raja said...

Hi Bijoy,
How are you inputting the password? The options are to put it in the script directly (pwd="your_password") or to put it in a file (plain text file only containing the password) and entering the full path to the file as '_pwdfile'.

Bijoy said...

Hey Raja,

Thanks for the prompt reply. I tried both options. My print
statement looks like
print "Before the passwd: " + _username + " " + pwd
and its printing the correct username and passwd in both cases
(reading from file or direct in the script). I'm using python-2.3

Cheers,
Bijoy.

Bijoy said...

Hey Raja,

From the Pyhton-2.3 documentation
When performing basic authentication, a FancyURLopener instance calls its prompt_user_passwd() method. The default implementation asks the users for the required information on the controlling terminal. A subclass may override this method to support more appropriate behavior if needed.

I removed your implementation of prompt_user_passwd() and i did get a prompt for username and password. But it keeps asking me even though I enter the correct username and passwd. Maybe something is wrong with the python module itself.

Cheers,
Bijoy

Raja said...

Hi Bijoy,
Seems odd, doesnt it? I would atleast expect some error message when running the script. Why are you still running 2.3? I am running this now with python 2.5, I will try to test this with 2.3 and 2.4 to see what minimum version is required.

Bijoy said...

Sooooo .. after playing with this last Dec .. I came across this again today and figured to give it another shot :-) .. this time i got is working :-)

Basically I think there is something wrong with the urllib module in python-2.3. So I edited your script to use urllib2. The changes that I made were

import urllib2

authurl = 'mail.google.com'
_url = 'mail.google.com/gmail/feed/atom'
protocol = 'https://'

def auth():
'''The method to do HTTPBasicAuthentication'''
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, authurl, _username, pwd)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
opener.open(protocol + _url)
urllib2.install_opener(opener)
try:
f = urllib2.urlopen(protocol + _url)
except IOError, e:
if hasattr(e, 'code'):
if e.code != 401:
print 'Got Error'
print e.code
else:
print e.headers
print e.headers['www-authenticate']
feed = f.read()
return feed

The above code is courtesy of a code snippet written on a tutorial I found online :-) .. It works now.

You also need to mention that for "^cs()" (clear slave) to work, one must use th latest SVN checkout. Older version will not interpret ^cs() correctly.

Thanks Again