Recipe10.16.Reading Microsoft Outlook Contacts


Recipe 10.16. Reading Microsoft Outlook Contacts

Credit: Kevin Altis

Problem

Your Microsoft Outlook Contacts house a wealth of useful information, and you need to extract some of it in text form.

Solution

Like many other problems of system administration on Windows, this one is best approached by using COM. The most popular way to interface Python to COM is to use the win32com package, which is part of Mark Hammond's pywin32 extension package:

from win32com.client import gencache, constants DEBUG = False class MSOutlook(object):     def _ _init_ _(self):         try:             self.oOutlookApp = gencache.EnsureDispatch("Outlook.Application")             self.outlookFound = True         except:             print "MSOutlook: unable to load Outlook"             self.outlookFound = False         self.records = [  ]     def loadContacts(self, keys=None):         if not self.outlookFound: return         onMAPI = self.oOutlookApp.GetNamespace("MAPI")         ofContacts = onMAPI.GetDefaultFolder(constants.olFolderContacts)         if DEBUG: print "number of contacts:", len(ofContacts.Items)         for oc in range(len(ofContacts.Items)):             contact = ofContacts.Items.Item(oc + 1)             if contact.Class == constants.olContact:                 if keys is None:                     # no keys were specified, so build up a list of all keys                     # that belong to some types we know we can deal with                     good_types = int, str, unicode                     keys = [key for key in contact._prop_map_get_                         if isinstance(getattr(contact, key), good_types) ]                     if DEBUG:                         print "Fields\n== == == == == == == == == == == =="                         keys.sort( )                         for key in keys: print key                 record = {  }                 for key in keys:                     record[key] = getattr(contact, key)                 self.records.append(record)                 if DEBUG:                     print oc, contact.FullName if _ _name_ _ == '_ _main_ _':     if '-d' in sys.argv:         DEBUG = True     if DEBUG:         print "attempting to load Outlook"     oOutlook = MSOutlook( )     if not oOutlook.outlookFound:         print "Outlook not found"         sys.exit(1)     fields = ['FullName', 'CompanyName',               'MailingAddressStreet', 'MailingAddressCity',               'MailingAddressState', 'MailingAddressPostalCode',               'HomeTelephoneNumber', 'BusinessTelephoneNumber',               'MobileTelephoneNumber', 'Email1Address', 'Body',              ]     if DEBUG:         import time         print "loading records..."         startTime = time.time( )     # to get all fields just call oOutlook.loadContacts( )     # but getting a specific set of fields is much faster     oOutlook.loadContacts(fields)     if DEBUG:         print "loading took %f seconds" % (time.time( ) - startTime)     print "Number of contacts: %d" % len(oOutlook.records)     print "Contact: %s" % oOutlook.records[0]['FullName']     print "Body:\n%s" % oOutlook.records[0]['Body']

Discussion

This recipe's code could use more error-checking, and you could get it by using nested TRy/except blocks, but I didn't want to obscure the code's fundamental simplicity in this recipe. This recipe should work with different versions of Outlook, but I've tested it only with Outlook 2000. If you have applied the Outlook security patches then you will be prompted with a dialog requesting access to Outlook for 1-10 minutes from an external program, which in this case is Python.

The code has already been optimized in two important ways. First, by ensuring that the Python COM wrappers for Outlook have been generated, which is guaranteed by calling gencache.EnsureDispatch. Second, in the loop that reads the contacts, the Contact reference is obtained only once and then kept in a local variable contact to avoid repeated references. This simple but crucial optimization is the role of the statement:

contact = ofContacts.Items.Item(oc + 1)

Both of these optimizations have a dramatic impact on total import time, and both are important enough to keep in mind. Specifically, the EnsureDispatch idea is important for most uses of COM in Python; the concept of getting an object reference, once, into a local variable (rather than repeating indexing, calls, and attribute accesses) is even more important and applies to every use of Python.

Simple variations of this script can be applied to other elements of the Outlook object model such as the Calendar and Tasks. You'll want to look at the Python wrappers generated for Outlook in the C:\Python23\Lib\site-packages\win32com\gen_py directory. I also suggest that you look at the Outlook object model documentation on MSDN and/or pick up a book on the subject.

See Also

PyWin32 docs at http://sourceforge.net/projects/pywin32/; Microsoft's MSDN site, http://msdn.microsoft.com.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net