Ataraxia Consulting

Peace of mind for consulting

Making imaplib simple

Not long ago I wrote an imap polling script for work that used Python's [imaplib](http://docs.python.org/library/imaplib.html). Shortly after that [HoopyCat](http://blog.hoopycat.com/) wrote an excellent [imap backup script](http://blog.hoopycat.com/index.php/2009/07/04/imap2maildir-a-tool-for-mirroring-imap-t) that also used imaplib. We exchanged some stories and opined on wanting a simpler mechanism to get imaplib to return an [email.Message](http://docs.python.org/library/email.message.html) object (a feature that should be available from the core). I happened to have to look at my code again this week and decided to work up a quick example of the interface I expected to actually find in the core imaplib
import imaplib
import email
 
class __simplebase:
  def get_messages_by_folder(self, folder, charset=None):
    ids = self.get_ids_by_folder(folder, charset=charset)
 
    for m in self.get_messages_by_ids(ids):
      yield m
 
  def get_ids_by_folder(self, folder, charset=None):
    self.select(folder)
    status, data = self.search(charset, 'ALL')
    if status != 'OK':
      raise Exception(data)
 
    return data[0].split()
 
  def get_messages_by_ids(self, ids):
    for i in ids:
      yield self.get_message_by_id(i)
 
  def get_message_by_id(self, id):
    status, data = self.fetch(id, '(RFC822)')
 
    if status != 'OK':
      raise Exception(data)
 
    return email.message_from_string(data[0][1])
 
class SimpleImap(imaplib.IMAP4, __simplebase):
  pass
 
class SimpleImapSSL(imaplib.IMAP4_SSL, __simplebase):
  pass
The SimpleImap and SimpleImapSSL classes should be drop in replacements for your existing usage of IMAP4 and IMAP4_SSL. You'll notice the use of generator objects (the yield keyword), this means that each iteration the message you're working on is pulled from the server right then. That's useful when you have a lot of messages that you don't necessarily want to cache into memory or when they'll potentially have large attachments. On the other hand, it will result in considerably more imap commands and traffic than if you were to just pull all the messages at once. Here's a sample usage that prints out the subject of every message in your inbox:
c = SimpleImap('mail.example.com', 143)
c.login('someluser', 'stupersekrit')
for m in c.get_messages_by_folder('INBOX'):
  print m['subject']
c.logout()

Posted in 

blog comments powered by Disqus