Reading e-mails from Outlook with Python through MAPI

PythonOutlookExchange ServerMapicdo.message

Python Problem Overview


I'm trying to write a short program that will read in the contents of e-mails within a folder on my exchange/Outlook profile so I can manipulate the data. However I'm having a problem finding much information about python and exchange/Outlook integration. A lot of stuff is either very old/has no docs/not explained. I've tried several snippets but seem to be getting the same errors. I've tried Tim Golden's code:

import win32com.client

session = win32com.client.gencache.EnsureDispatch ("MAPI.Session")

#
# Leave blank to be prompted for a session, or use
# your own profile name if not "Outlook". It is also
# possible to pull the default profile from the registry.
#
session.Logon ("Outlook")
messages = session.Inbox.Messages

#
# Although the inbox_messages collection can be accessed
# via getitem-style calls (inbox_messages[1] etc.) this
# is the recommended approach from Microsoft since the
# Inbox can mutate while you're iterating.
#
message = messages.GetFirst ()
while message:
    print message.Subject
    message = messages.GetNext ()

However I get an error:

pywintypes.com_error: (-2147221005, 'Invalid class string', None, None)

Not sure what my profile name is so I tried with:

session.Logon()

to be prompted but that didn't work either (same error). Also tried both with Outlook open and closed and neither changed anything.

Python Solutions


Solution 1 - Python

I had the same problem you did - didn't find much that worked. The following code, however, works like a charm.

import win32com.client

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

inbox = outlook.GetDefaultFolder(6) # "6" refers to the index of a folder - in this case,
                                    # the inbox. You can change that number to reference
                                    # any other folder
messages = inbox.Items
message = messages.GetLast()
body_content = message.body
print body_content

Solution 2 - Python

I have created my own iterator to iterate over Outlook objects via python. The issue is that python tries to iterates starting with Index[0], but outlook expects for first item Index[1]... To make it more Ruby simple, there is below a helper class Oli with following methods:

.items() - yields a tuple(index, Item)...

.prop() - helping to introspect outlook object exposing available properties (methods and attributes)

from win32com.client import constants
from win32com.client.gencache import EnsureDispatch as Dispatch

outlook = Dispatch("Outlook.Application")
mapi = outlook.GetNamespace("MAPI")

class Oli():
	def __init__(self, outlook_object):
		self._obj = outlook_object

	def items(self):
		array_size = self._obj.Count
		for item_index in xrange(1,array_size+1):
			yield (item_index, self._obj[item_index])

	def prop(self):
		return sorted( self._obj._prop_map_get_.keys() )

for inx, folder in Oli(mapi.Folders).items():
	# iterate all Outlook folders (top level)
	print "-"*70
	print folder.Name

	for inx,subfolder in Oli(folder.Folders).items():
		print "(%i)" % inx, subfolder.Name,"=> ", subfolder

Solution 3 - Python

Sorry for my bad English. Checking Mails using Python with MAPI is easier,

outlook =win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
folder = outlook.Folders[5]
Subfldr = folder.Folders[5]
messages_REACH = Subfldr.Items
message = messages_REACH.GetFirst()

Here we can get the most first mail into the Mail box, or into any sub folder. Actually, we need to check the Mailbox number & orientation. With the help of this analysis we can check each mailbox & its sub mailbox folders.

Similarly please find the below code, where we can see, the last/ earlier mails. How we need to check.

`outlook =win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
folder = outlook.Folders[5]
Subfldr = folder.Folders[5]
messages_REACH = Subfldr.Items
message = messages_REACH.GetLast()`

With this we can get most recent email into the mailbox. According to the above mentioned code, we can check our all mail boxes, & its sub folders.

Solution 4 - Python

I had the same issue. Combining various approaches from the internet (and above) come up with the following approach (checkEmails.py)

class CheckMailer:

        def __init__(self, filename="LOG1.txt", mailbox="Mailbox - Another User Mailbox", folderindex=3):
            self.f = FileWriter(filename)
            self.outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI").Folders(mailbox)
            self.inbox = self.outlook.Folders(folderindex)

			
        def check(self):                
        #===============================================================================
        # for i in xrange(1,100):							#Uncomment this section if index 3 does not work for you
        #     try:
        #         self.inbox = self.outlook.Folders(i)     # "6" refers to the index of inbox for Default User Mailbox
        #         print "%i %s" % (i,self.inbox)			# "3" refers to the index of inbox for Another user's mailbox
        #     except:
        #         print "%i does not work"%i
        #===============================================================================
        
                self.f.pl(time.strftime("%H:%M:%S"))
                tot = 0                
                messages = self.inbox.Items
                message = messages.GetFirst()
                while message:
                    self.f.pl (message.Subject)
                    message = messages.GetNext()
                    tot += 1
                self.f.pl("Total Messages found: %i" % tot)
                self.f.pl("-" * 80)
                self.f.flush()

if __name__ == "__main__":
    mail = CheckMailer()
    for i in xrange(320):  # this is 10.6 hours approximately
            mail.check()
            time.sleep(120.00)


	

For concistency I include also the code for the FileWriter class (found in FileWrapper.py). I needed this because trying to pipe UTF8 to a file in windows did not work.

class FileWriter(object):
    '''
    convenient file wrapper for writing to files
    '''


    def __init__(self, filename):
        '''
        Constructor
        '''
        self.file = open(filename, "w")
        
    def pl(self, a_string):
        str_uni = a_string.encode('utf-8')
        self.file.write(str_uni)
        self.file.write("\n")
    
    def flush(self):
        self.file.flush()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjohnharris85View Question on Stackoverflow
Solution 1 - PythonBobbyView Answer on Stackoverflow
Solution 2 - PythonMartin StancikView Answer on Stackoverflow
Solution 3 - PythonOzziusView Answer on Stackoverflow
Solution 4 - PythonraptisthView Answer on Stackoverflow