IMAP Email and Notifications: How-To

Introduction
In this article we’ll look at how you can use Mountain Lion’s notification system to notify you of unread emails for any IMAP account. More specifically, we’ll look at how you can leverage Python and cron to check any email account at a specified interval, notifying you of any unread emails.

Target
I’m not one to limit the audience for an article since of the main purposes of this blog is to encourage you to try new things. However, this article might be better suited to those who are comfortable with the command line and have a basic understanding of how OS X works.

Tasks
In this article, we’ll be doing three things:

  1. Getting all the tools needed.
  2. Modifying the Python script that checks the IMAP account.
  3. Setting up cron to run the script at a specified interval.

Getting the Tools
Before we begin, we need to make sure we have all the right tools. In planning any project, it’s always good to figure out what you have and what you need to get. Let’s take a look at what we need:

  • A way to create notifications from the command line.
  • A Python install.
  • Plain text editor.
  • Cron.

The things we have are in green and those features/tools that we don’t have are in red. As you can see, we’re off to a pretty good start and thankfully, the only thing we don’t have can be easily had. To create notifications from the command line, head over to this page and download terminal-notifier. Download that, decompress it and put the app bundle in /Applications. Once that’s done, we’re ready to start the fun part.

The Python Script
This isn’t a Python tutorial so I’m going to provide the script that will do the work for you:

#!/usr/bin/env python

###### References ######
# 1. http://stackoverflow.com/questions/953561/check-unread-count-of-gmail-messages-with-python
# 2. http://stackoverflow.com/questions/348630/how-can-i-download-all-emails-with-attachments-from-gmail
# 3. http://docs.python.org/library/imaplib.html
# 4. http://segfault.in/2010/07/playing-with-python-and-gmail-part-1/
########################

import imaplib
import subprocess

email_server = "CHANGE ME" # Gmail = imap.gmail.com
user = "CHANGE ME"
password = "CHANGE ME"
notification_title = "CHANGE ME"

server = imaplib.IMAP4_SSL(email_server)
server.login(user, password)
server.select("INBOX")

x, items = server.search(None, "UNSEEN")
count = 0
for num in items[0].split():
    server.status(num, '(RFC822)')
    count += 1

if count > 0:
	print("You have %s unread message(s)." % str(count))
	subprocess.Popen("/Applications/terminal-notifier.app/Contents/MacOS/terminal-notifier -message 'You have %s unread message(s).' -title '%s' -open 'http://www.gmail.com'" % (str(count), notification_title), stdout=subprocess.PIPE, shell=True)

Paste that into a plain text editor. TextEdit will suffice but you need to make sure that you save the file as plain text since TextEdit defaults to rich text.

Regardless of how you get this, you’ll need to edit a few values. Specifically, you need to change the name of the IMAP server, the username, the password and the title for the notification. These are found on lines 13-17. It should be pretty self-explanatory what each is (hopefully the variables aren’t all that cryptic!). Note that the quotation marks are necessary so make sure those remain.

Once you’ve made the changes to those four variables, test the script to make sure it works. Open up a Terminal window and enter the following:

python

Make sure that there’s a space after the word python and then drag the script you created/downloaded into the Terminal window. Press enter, give it a second and then you should see a notification appear telling you how many unread messages you have for that account. If you have any errors, make sure the values are correct and, as noted above, are properly enclosed in quotation marks. Once that’s working, it’s time to make this script run at regular intervals behind the scenes.

Cron
Cron is one of the little gems that OS X inherits as an operating system that is part of the Unix family. In short, it’s a scheduler that let’s you tell the OS to do certain things at an interval that you specify. Thankfully, it’s pre-installed and ready to go out of the box.

Open up a Terminal window (if you closed it earlier) and enter the following:

crontab -e

This will open up the Vim text editor which itself has opened what is called the crontab. The crontab is simply the file that contains the list of instructions and corresponding interval rules for cron.

To setup a cron job, the instruction needs to have the following structure1:

*    *    *    *    *  command to be executed
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
|    |    |    |    ------ day of week (0 - 6) (0 is Sunday, or use names)
|    |    |    ----------- month (1 - 12)
|    |    ---------------- day of month (1 - 31)
|    --------------------- hour (0 - 23)
-------------------------- min (0 - 59)

Let’s look at some examples which will make this much more clear.

Say you want to execute a command (signified by the <command> part) at 15 minutes past every hour. If this were the case, your cron instruction would look something like this:

15 * * * * <command>

The 15 signifies the minute and the asterisks signify “every” so this command is essentially saying execute <command> at 15 minutes past every hour of every day of month, every month of the year and do this every day of the week. Now, you might be thinking, “I’d like to check more than once an hour.” This isn’t a problem but it involves some new syntax.

Say you want to execute a command every 10 minutes. Doing this requires the forward slash to signify that you want to divide an hour into parts:

*/10 * * * * <command>

In essence, this is telling cron that you want to divide an hour into ten minute intervals and at each interval, you want to execute the command.

For the sake of this project, pretend that you want to check your email every 20 minutes with no other limitations (in other words, you want to execute this every hour of every day of the year). As such, we’ll need the following cron instruction:

*/20 * * * *

We’re not done yet though since we still need to tell cron what to execute. In its current state, cron knows it needs to do something every 20 minutes but doesn’t know what. So, let’s add the path to the crontab. As you did above,  simply drag the script into the Terminal window after the last asterisk (make sure there’s a space between the last asterisk and the script path & name). Once you’ve done this, your crontab will look something like the following (the script path will vary but the structure of the cron instruction should look similar to this):

*/20 * * * * /Users/vansmith/.scripts/checkGmail.py

To save it, press esc and the enter the following:

:wq

For more info about setting up cron jobs, take a look at this.

We have one final step before we’re done. For this to work, the script needs to be executable. In short, the script is a plain text file and right now, it just looks like text to the operating system. We want OS X to see this script as something that can be executed like any other application. To do this, in a Terminal window, enter the following:

chmod +x

As you did above, drag the script into the Terminal window and again, make sure there’s a space between the +x and the script path & name.

That’s it. Enjoy your email notifications!

Caveats

  1. If you use GMail and two-step authorization, you’ll need to generate an application-specific password here and use that as your password.
  2. The email notifications will appear under the “terminal-notifier” heading in the notification sidebar. This isn’t the most elegant solution and is something I’m working to solve right now. See below for an example of what I mean.

1 http://en.wikipedia.org/wiki/Cron#Predefined_scheduling_definitions