Tuesday, 1 September 2009

IMAP PUSH GMail Python Script (for Mac, but easily changable)


So, you need a python script to do something when you get an email (from GMail, for example, but other services that support IMAP4 will work as well). I came across this post when finding out how to do this. It pointed me in the right direction; I didn't have to do much initial thinking/goggling.

A quick explanation as to how the script works:
  1. Connect using IMAP to imap.gmail.com
  2. Send login credentials (encrypted with SSL, don't worry)
  3. Select 'INBOX'
  4. Send IDLE command and wait for mail...
  5. When a message gets to Google's servers, they terminate the IDLE connection. This then signals to our script that a message has been received (or we've timed out)
  6. The script then checks to see if there is new, unseen mail, and, if so, uses growlnotify to let us know the sender and the subject. (This is the bit that can be replaced to do whatever you want it to do. You can get the message body if you want, times, dates, etc... and do whatever with it)
  7. IDLE command is sent again (i.e. back to 4.)
Instead of a growl notification, you could use pySerial to send something to an Arduino and light something, spin something, etc... Feel free to change the code and do whatever to it.

There are two bits of code you'll need: imaplib2.py and my IMAPPush.py

I hosted my IMAPPush.py on Google Sites because I couldn't host it here. All you need to do is put the files in the same directory, cd to said directory and execute:

python IMAPPush.py USERNAME [PASSWORD]

The PASSWORD is not required -- you'll be prompted for it if it is omitted.

To find out more about IMAP IDLE, see it's RFC (RFC 2177) here.

There's no point me explaining how the code works here; if you want to understand how the code works, I've put a lot of comments in the code. That's the best place for explaining the code, after all.

Here are the links to the code again:
  1. http://sites.google.com/site/hmmtheresanidea/files/IMAPPush.py?attredirects=0
  2. http://www.cs.usyd.edu.au/%7Epiers/python/imaplib.html
Any comments, suggestions, etc... please let me know below. Thanks for reading!

UPDATE: links fixed, and code is now licensed.

7 comments:

wtip said...

Thanks for publishing this code!
One of the problems I'm having with it is that there is no response timeout checking.
So if the remote imap server reboots the script does not try to re login. Any ideas on how to fix this?

Peter said...

Hi Chris,

What license is this released under? Would really appreciate it if you could add some sort of contact email address so I can get in touch :-)

Cheers,

Pete

chris said...

Hi Peter,

It wasn't before, but I've updated the code so it's now under a MIT/X11 license -- basically, do what you want with it!

I don't really know if this is a good choice for a license, but it seemed to be the most flexible one I came across. It seems pretty compatible with others as well.

What are you doing, or planning to do, with it? I'm curious. It's good to see that it may be of use to someone!


Thanks for commenting,

All the best,


Chris

P.S. I have just added an email address to my profile.

Anonymous said...

I'm using this to get emails from a GMail account and deliver it to trac using email2trac. Thanks a lot!

chris said...

Great! Glad it was of some use!

Johannes said...

This is a beautiful example of IMAP IDLE using Python. This is going to be a lot of help to me while trying to work things out, all those wonderful comments! *drools*

erocm123 said...

Holy crap, this is awesome. I have implemented this into a script I have been using for years and it is working great. My problem is I can't seem to get the thread to die when not running interactively. In your code, the script is run interactively and pressing q followed by enter kills the thread and then exits the script.

My script does not run interactively and when I send sigterm to it with kill {pid} the thread is never notified of the sigterm and it never exits! How can I handle this situation to get everything to exit when I request it to?