Why is this better than just using Growl?
I can't speak for Growl on the Mac, but the Windows Gmail Growl notifier polls the atom feed. Google recommends only doing this every 10 minutes. This means you get notified within 5 minutes of new emails on average.
If you like getting notified faster, this is almost instant. It uses IDLE which means the IMAP server will notify the script instead of it having to poll. It's more like "push"
I hacked it together modifying some guy's python idle script.
It requires prowlpy.py: http://github.com/jacobb/prowlpy/tree/master
and imaplib2: http://www.janeelix.com/piers/python/imaplib2_pp.html
Oh, and prowlpy requires httplib2 which you can "python setup.py install". http://code.google.com/p/httplib2/
Feel free to improve it. I kept it running in a thread so it can be shut down. If you use the synchronous version of idle, it will block until activity on the account, which means you can't shut down the script cleanly. I don't think.
Also, you might want to change line 25 in prowlpy.py to just h = httplib2.Http() instead of using ".cache" because you'll get errors with longer descriptions. I haven't investigated why this is the case. It'll still work OK.
Here it is:
- Code: Select all
import imaplib2
import time
import os
import prowlpy
import email
from threading import *
prowl_apikey = "APIKEYHERE"
IMAP_USERNAME = "USERNAME"
IMAP_PASSWORD = "PASSWORD"
# This is the threading object that does all the waiting on
# the event
class Idler(object):
def __init__(self, conn):
self.thread = Thread(target=self.idle)
self.M = conn
self.event = Event()
self.last_notify = ""
def start(self):
self.thread.start()
def stop(self):
# This is a neat trick to make thread end. Took me a
# while to figure that one out!
self.event.set()
def join(self):
self.thread.join()
def idle(self):
# Starting an unending loop here
while True:
# This is part of the trick to make the loop stop
# when the stop() command is given
if self.event.isSet():
return
self.needsync = False
# A callback method that gets called when a new
# email arrives. Very basic, but that's good.
def callback(args):
if not self.event.isSet():
self.needsync = True
self.event.set()
# Do the actual idle call. This returns immediately,
# since it's asynchronous.
self.M.idle(callback=callback)
# This waits until the event is set. The event is
# set by the callback, when the server 'answers'
# the idle call and the callback function gets
# called.
self.event.wait()
# Because the function sets the needsync variable,
# this helps escape the loop without doing
# anything if the stop() is called. Kinda neat
# solution.
if self.needsync:
self.event.clear()
self.dosync()
# The method that gets called when a new email arrives.
def dosync(self):
print "Got an event!"
retcode, messages = self.M.search(None, 'UNSEEN')
if len(messages) >= 1 and len(messages[0].split()) >= 1:
ret, msginfo = self.M.fetch(messages[0].split()[-1], '(BODY[HEADER.FIELDS (SUBJECT FROM)] BODY[1])')
if ret == 'OK':
header = msginfo[0][1].split('\r\n')
sender = header[0]
subject = header[1][9:]
body = msginfo[1][1][:100]
notify = sender+subject+body
if notify != self.last_notify:
self.last_notify = notify
print "New email %s %s %s" % (sender,subject,body)
p = prowlpy.Prowl(prowl_apikey)
try:
p.post('Gmail Josh',subject,body)
print 'Posted to Prowl'
except Exception,msg:
print msg
else:
print "Already notified"
idler = None
last_notify = ""
try:
# loop forever, timing out faster than IMAP will time you out
while True:
# Set the following two lines to your creds and server
M = imaplib2.IMAP4_SSL("imap.gmail.com")
M.login(IMAP_USERNAME, IMAP_PASSWORD)
# defaults to inbox
M.select()
# Start the Idler thread
idler = Idler(M)
idler.last_notify = last_notify
print "Connected. Waiting on IDLE."
idler.start()
# sleep 20 minutes. Idle can time out in 30 minutes.
time.sleep(20*60)
# a hack to make sure you only get notified once per email
last_notify = idler.last_notify
idler.stop()
idler.join()
M.close()
M.logout()
idler = None
finally:
# Clean up.
if idler is not None:
print "Shutting down"
idler.stop()
idler.join()
M.close()
M.logout()

