Welcome, guest | Sign In | My Account | Store | Cart

This is a simple class and test code to read the Contacts from Outlook using win32com, which is part of Mark Hammond's win32all package.

Python, 91 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import win32com.client

DEBUG = 0

class MSOutlook:
    def __init__(self):
        self.outlookFound = 0
        try:
            self.oOutlookApp = \
                win32com.client.gencache.EnsureDispatch("Outlook.Application")
            self.outlookFound = 1
        except:
            print "MSOutlook: unable to load Outlook"
        
        self.records = []


    def loadContacts(self, keys=None):
        if not self.outlookFound:
            return

        # this should use more try/except blocks or nested blocks
        onMAPI = self.oOutlookApp.GetNamespace("MAPI")
        ofContacts = \
            onMAPI.GetDefaultFolder(win32com.client.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 == win32com.client.constants.olContact:
                if keys is None:
                    # if we were't give a set of keys to use
                    # then build up a list of keys that we will be
                    # able to process
                    # I didn't include fields of type time, though
                    # those could probably be interpreted
                    keys = []
                    for key in contact._prop_map_get_:
                        if isinstance(getattr(contact, key), (int, str, unicode)):
                            keys.append(key)
                    if DEBUG:
                        keys.sort()
                        print "Fields\n======================================"
                        for key in keys:
                            print key
                record = {}
                for key in keys:
                    record[key] = getattr(contact, key)
                if DEBUG:
                    print oc, record['FullName']
                self.records.append(record)


if __name__ == '__main__':
    if DEBUG:
        print "attempting to load Outlook"
    oOutlook = MSOutlook()
    # delayed check for Outlook on win32 box
    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()
    # you can either get all of the data fields
    # or just a specific set of fields which is much faster
    #oOutlook.loadContacts()
    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']

The code could use more error-checking, perhaps by using nested try/accept blocks. It should work with different versions of Outlook, but I've only tested it with Outlook 2000.

Note that if you are using the Outlook security patches then you will be prompted with a dialog to allow access to Outlook for 1 - 10 minutes from an external program, which in this case is Python.

The code has already been optimized to ensure that the Python COM wrappers for Outlook have been generated by calling gencache.EnsureDispatch and in the loop that reads the contacts, the Contact reference is kept in a local variable to avoid repeated references.

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

Both of these optimizations have a dramatic impact on total import time.

A variation 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 Python22\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.

1 comment

Jingzhao Ou 20 years, 11 months ago  # | flag

No problem with Windows XP and Office XP. This script is very useful to me. Great!

Created by Kevin Altis on Fri, 10 Jan 2003 (PSF)
Python recipes (4591)
Kevin Altis's recipes (4)

Required Modules

Other Information and Tasks