from __future__ import generators # Utilities for our sandbox import os import pythoncom from win32com.mapi import mapi, mapiutil from win32com.mapi.mapitags import * from win32com.client import Dispatch class MAPIDriver: def __init__(self, read_only = False): old_cwd = os.getcwd() mapi.MAPIInitialize(None) logonFlags = (mapi.MAPI_NO_MAIL | mapi.MAPI_EXTENDED | mapi.MAPI_USE_DEFAULT) self.session = mapi.MAPILogonEx(0, None, None, logonFlags) if read_only: self.mapi_flags = mapi.MAPI_DEFERRED_ERRORS else: self.mapi_flags = mapi.MAPI_DEFERRED_ERRORS | mapi.MAPI_BEST_ACCESS self.outlook = None os.chdir(old_cwd) def _GetMAPIFlags(self, mapi_flags = None): if mapi_flags is None: mapi_flags = self.mapi_flags return mapi_flags def GetOutlookFolder(self, item): if self.outlook is None: self.outlook = Dispatch("Outlook.Application") hr, props = item.GetProps((PR_ENTRYID,PR_STORE_ENTRYID), 0) (tag, eid), (tag, store_eid) = props eid = mapi.HexFromBin(eid) store_eid = mapi.HexFromBin(store_eid) return self.outlook.Session.GetFolderFromID(eid, store_eid) def GetMessageStores(self): tab = self.session.GetMsgStoresTable(0) rows = mapi.HrQueryAllRows(tab, (PR_ENTRYID, PR_DISPLAY_NAME_A, PR_DEFAULT_STORE), # columns to retrieve None, # all rows None, # any sort order is fine 0) # any # of results is fine for row in rows: (eid_tag, eid), (name_tag, name), (def_store_tag, def_store) = row # Open the store. try: store = self.session.OpenMsgStore( 0, # no parent window eid, # msg store to open None, # IID; accept default IMsgStore # need write access to add score fields mapi.MDB_WRITE | # we won't send or receive email mapi.MDB_NO_MAIL | mapi.MAPI_DEFERRED_ERRORS) yield store, name, def_store except pythoncom.com_error, details: hr, msg, exc, arg_err = details if hr== mapi.MAPI_E_FAILONEPROVIDER: # not logged on etc. pass else: print "Error opening message store", details, "- ignoring" def _FindSubfolder(self, store, folder, find_name): find_name = find_name.lower() table = folder.GetHierarchyTable(0) rows = mapi.HrQueryAllRows(table, (PR_ENTRYID, PR_DISPLAY_NAME_A), None, None, 0) for (eid_tag, eid), (name_tag, name), in rows: if name.lower() == find_name: return store.OpenEntry(eid, None, mapi.MAPI_DEFERRED_ERRORS) return None def FindFolder(self, name): assert name names = [n.lower() for n in name.split("\\")] if names[0]: store_name = None for store, name, is_default in self.GetMessageStores(): if is_default: store_name = name.lower() break if store_name is None: raise RuntimeError, "Can't find a default message store" folder_names = names else: store_name = names[1] folder_names = names[2:] # Find the store with the name for store, name, is_default in self.GetMessageStores(): if name.lower() == store_name: folder_store = store break else: raise ValueError, "The store '%s' can not be located" % (store_name,) hr, data = store.GetProps((PR_IPM_SUBTREE_ENTRYID,), 0) subtree_eid = data[0][1] folder = folder_store.OpenEntry(subtree_eid, None, mapi.MAPI_DEFERRED_ERRORS) for name in folder_names: folder = self._FindSubfolder(folder_store, folder, name) if folder is None: raise ValueError, "The subfolder '%s' can not be located" % (name,) return folder def GetAllItems(self, folder, mapi_flags = None): mapi_flags = self._GetMAPIFlags(mapi_flags) table = folder.GetContentsTable(0) table.SetColumns((PR_ENTRYID,PR_STORE_ENTRYID), 0) while 1: # Getting 70 at a time was the random number that gave best # perf for me ;) rows = table.QueryRows(70, 0) if len(rows) == 0: break for row in rows: (tag, eid), (tag, store_eid) = row store = self.session.OpenMsgStore(0, store_eid, None, mapi_flags) item = store.OpenEntry(eid, None, mapi_flags) yield item def GetItemsWithValue(self, folder, prop_tag, prop_val, mapi_flags = None): mapi_flags = self._GetMAPIFlags(mapi_flags) tab = folder.GetContentsTable(0) # Restriction for the table: get rows where our prop values match restriction = (mapi.RES_CONTENT, # a property restriction (mapi.FL_SUBSTRING | mapi.FL_IGNORECASE | mapi.FL_LOOSE, # fuzz level prop_tag, # of the given prop (prop_tag, prop_val))) # with given val rows = mapi.HrQueryAllRows(tab, (PR_ENTRYID, PR_STORE_ENTRYID), # columns to retrieve restriction, # only these rows None, # any sort order is fine 0) # any # of results is fine for row in rows: (tag, eid),(tag, store_eid) = row store = self.session.OpenMsgStore(0, store_eid, None, mapi_flags) item = store.OpenEntry(eid, None, mapi_flags) yield item def DumpTopLevelFolders(self): print "Top-level folder names are:" for store, name, is_default in self.GetMessageStores(): # Find the folder with the content. hr, data = store.GetProps((PR_IPM_SUBTREE_ENTRYID,), 0) subtree_eid = data[0][1] folder = store.OpenEntry(subtree_eid, None, mapi.MAPI_DEFERRED_ERRORS) # Now the top-level folders in the store. table = folder.GetHierarchyTable(0) rows = mapi.HrQueryAllRows(table, (PR_DISPLAY_NAME_A), None, None, 0) for (name_tag, folder_name), in rows: print " \\%s\\%s" % (name, folder_name) def GetFolderNameDoc(self): def_store_name = "" for store, name, is_def in self.GetMessageStores(): if is_def: def_store_name = name return """\ Folder name is a hierarchical 'path' name, using '\\' as the path separator. If the folder name begins with a \\, it must be a fully-qualified name, including the message store name. For example, as your default store is currently named '%s', your Inbox can be specified either as: -f "Inbox" or -f "\\%s\\Inbox" """ % (def_store_name, def_store_name) if __name__=='__main__': print "This is a utility script for the other scripts in this directory"