Getting Python Working on Microsoft Exchange
26 Jan 2014Creating an Internal Emailing Wikibot in Python
You know how they say that when all you have is a hammer that everything looks like a nail?
For now, Python is my hammer. I understand that C# or VB would be a better choice for this project, particularly since Microsoft Exchange plays much more nicely with them than Python, but as I’m just starting out I think I’m still in the phase of learning how the language works, and haven’t quite progressed to learning what the language is good for.
I suppose there’s something to be said for the fact that Python is platform-agnostic.
Here’s a project I’m working on, though: the first end-goal is to:
1.) Find a random wiki page 2.) Find its owner 3.) Email that owner to notify them that page was chosen
Part 1: Connecting Python to Exchange Web Services
Since this is an internal wiki to my company, there is a lot of benefit to using Exchange to send the emails. Most of all that I am rolling it on my own, and not working with the network admins and therefore don’t have access to the SMTP server.
Microsoft Exchange Server has a SOAP API, called Exchange Web Services. This has been a fun experience learning SOAP for the first time.
What is SOAP?
SOAP stands for Simple Object Access protocol. It’s an XML-based messaging system that servers and clients can use to talk to each other with standardized messages. The client understand what XML tags the server uses by getting a file called the WSDL.
I’ll be using a Python SOAP library called Suds to talk to the Exchange server.
There are a few catches, though. EWS doesn’t play nice with Suds, so we need a few patches and other modules to get it working well.
Installing Suds
On Mac and Linux, this is trivially easy: run
(If you don’t have pip on your Mac, you can run the get-pip installer file.
On Windows, where I did it, this is a little harder, but you can still download an easy_install script and the zip file of Suds.
Then, you boot up a SOAP client with Suds, and I didn’t document this very well, but it returns an HTTP 401 error; Not Authorized.
Getting Suds to Work with EWS
Hmm. Googling for a few hours brought me to a good solution, first suggested on the Suds forums.
EWSClient is Daniel Holth’s solution to marrying Suds to EWS. Installing it will also intall python-ntlm, which will be important later.
The main file in EWSClient is:
This adds a plugin to Suds that adds EWS’s definitions to the end of the SOAP request. I don’t quite understand how it works, given Microsoft’s byzantine EWS definitions. At any rate, it works.
EWSClient has a few other files, too, like monkey.py, which fixes an issue where the client makes a request to the often-overloaded W3C definitions for XML. It instead lets you access a locally-cached copy of the file. I disabled it because my Windows python client was causing me a headache.
Using the example files that ewsclient provides, I try to get the WSDL specs:
And get this error as a response:
The thing to focus on is that we’re authenticating with NTLM, and the auth_header_value s aren’t formatted properly. There are some issues in python-ntlm that need fixing to play nicely with the encoding of domain, user, and pass.
Fixing NTLM to Work with our Suds Client
There’s an issue documented at the python-ntm page. The solution in post #3, in which we add a few lines to the code of /Library/Python/2.7/site-packages/ntlm/HTTPNtlmAuthHandler.py (on my Mac, your filepath will be different), worked for me:
With these changes, made, testing authorization works and I’m ready to start doing things with my client.