"""OO interface to IMAP; requires Menno Smits' IMAPClient: http://imapclient.freshfoo.com/ """ import os, sys import email import netrc import imapclient class Unset (object): def __repr__ (self): return "" unset = Unset () class IMAP (object): def __init__ (self, servername, username=None, password=None, root="", use_uid=True, use_ssl=False, port=None): self.name = servername self.server = imapclient.IMAPClient (self.name, port, use_uid, use_ssl) if username is None: username, account, password = netrc.netrc ().authenticators (servername) self.username = username self.password = password self.root = root def __repr__ (self): return "<%s: %s>" % (self.__class__.__name__, self.name) def __enter__ (self): self.login () return self def __exit__ (self, *args): self.logout () def __getattr__ (self, attr): return getattr (self.server, attr) def __getitem__ (self, attr): return self.folder (attr) def _folder_name (self, name): return self.root.rstrip (self.delimiter) + self.delimiter + name.rstrip (self.delimiter) def login (self, username=None, password=None): login = self.server.login ( self.username if username is None else username, self.password if password is None else password ) personal, _, _ = self.server.namespace () for prefix, self.delimiter in personal: break return login def logout (self): return self.server.logout () def folders (self, directory=None, pattern="*"): for flags, delimiter, folder in self.server.list_folders (directory or self.root, pattern): yield self.folder (folder) __iter__ = folders def inbox (self): return IMAPFolder (self, "INBOX", relative_to_root=False) def folder (self, folder_name): return IMAPFolder (self, folder_name, relative_to_root=False) def create_folder (self, folder_name, subscribe=False): self.server.create_folder (self._folder_name (folder_name)) folder = IMAPFolder (self, folder_name) if subscribe: folder.subscribe () return folder def copy (self, messages, folder): return self.server.copy (messages, self._folder_name (messages)) def walk (self, start_from=None): root = self.folder (start_from or self.root) folders = list (root.folders ()) if root == self.root: messages = [] else: with root as f: messages = f.messages () yield root, folders, messages for folder in folders: for result in self.walk (folder.name): yield result class IMAPFolder (object): def __init__ (self, imap_server, folder_name, relative_to_root=True): self.server = imap_server if relative_to_root: self.name = self.server._folder_name (folder_name) else: self.name = folder_name self._status = None def __repr__ (self): return "<%s: %s on %s>" % (self.__class__.__name__, self.name, self.server.name) def __enter__ (self): self.select () return self def __exit__ (self, *args): self.unselect () def __iter__ (self): return iter (self.messages ()) def select (self): self._status = self.server.select_folder (self.name) def unselect (self): self._status = None self.server.close_folder () def delete (self): self.server.delete_folder (self.name) def subscribe (self): self.server.subscribe_folder (self.name) def unsubscribe (self): self.server.unsubscribe_folder (self.name) def folders (self, pattern="*"): for folder_name in self.server.list_folders (self.name, pattern): yield self.__class__ (self.server, folder) def messages (self, criteria="ALL", charset=None): assert self._status, "You must use a context manager to select messages" return IMAPMessages (self.server, self.server.search (criteria, charset)) def append (self, imap_message, flags=(), msg_time=None): return self.server.append (self.name, str (msg), flags, msg_time) def copy (self, imap_messages): return self.server.copy ([m.id for m in imap_messages], self.name) def get_acl (self): return self.server.get_acl (self.name) def set_acl (self, who, what): return self.server.set_acl (self.name, who, what) def status (self, what=None): return self.server.folder_status (self.name, what) def expunge (self): assert self._status, "You must use a context manager to expunge messages" return self.server.expunge () class IMAPMessages (object): def __init__ (self, imap_server, message_ids): self.server = imap_server self.ids = message_ids def __repr__ (self): return "<%s on %s>" % (self.__class__.__name__, self.server.name) def __iter__ (self): for id in self.ids: yield IMAPMessage (self.server, id) def attributes (self, parts): return self.server.fetch (self.ids, parts) def delete (self): return self.server.delete (self.ids) def copy_to (self, folder_name): self.server.copy (self.message_ids, folder_name) def move_to (self, folder_name): self.copy_to (folder_name) self.delete () class IMAPMessage (object): def __init__ (self, imap_server, message_id): self.server = imap_server self.id = message_id self._email = None def __repr__ (self): return "<%s: UID %d>" % (self.__class__.__name__, self.id) def __str__ (self): return self.as_email ().as_string () def fetch (self, parts): return self.server.fetch ([self.id], parts)[self.id] def delete (self, parts): return self.server.delete_messages ([self.id]) def as_email (self): if self._email is None: self._email = email.message_from_string (self.fetch (["RFC822"])['RFC822']) return self._email def copy_to (self, folder_name): self.server.copy ([self.id], folder_name) def move_to (self, folder_name): self.copy_to (folder_name) self.delete () if __name__ == '__main__': with IMAP ("mail.webfaction.com", use_ssl=True, root="mail") as mail: for folder in mail: print folder with folder as open_folder: for message in folder: print " ", message.as_email ()['Subject'] break