Monday, October 3, 2011

MAPI Email Backend available for testing

I noticed that Django does not include a MAPI Backend for sending
Email, for some environments having this type of backend is essential
for testing and debugging. I do not recommend it as a production
backend unless you are a full exchange shop, as some are and do not
offer SMTP for internal applications.

I do not recommend using this as a production backend as it has not
yet been tested, it is recommended that you have experience coding
MAPI with Python before using this backend. This backend is only
compatible on Windows machines using the Python extensions as it talks
to Outlook directly, there are no sockets involved, so it makes it
very useful in environments with a tight firewall. Without further
delay here is the backend, as I said I haven't gotten around to
testing it and I do need some help adding support for the subject line
as this is my first Email backend attempt:

import win32com.client.dynamic, sys, re
import threading

from django.conf import settings
from django.core.mail.backends.base import BaseEmailBackend

class EmailBackend(BaseEmailBackend):
"""
A wrapper that manages the MAPI network connection.
"""
def __init__(self, MAPIProfile=None, fail_silently=False,
**kwargs):
super(EmailBackend,
self).__init__(fail_silently=fail_silently)
self.MAPIProfile = MAPIProfile or settings.MAPIProfile
self.connection = None
self._lock = threading.RLock()

def open(self):
"""
Ensures we have a MAPI Session to the exchange server. Returns
whether or
not a new connection was required (True or False).
"""
if self.connection:
# Nothing to do if the connection is already open.
return False
try:
self.connection = win32com.client.dynamic.Dispatch("MAPI.session")
if self.MAPIProfile <> None:
self.connection.Logon(self.MAPIProfile)
else:
self.connection.Logon("MS Exchange Settings")
return True
except:
if not self.fail_silently:
raise

def close(self):
"""Closes the connection to the exchange server."""
try:
try:
self.connection.Logoff()
except:
if self.fail_silently:
return
raise
finally:
self.connection = None

def send_messages(self, email_messages):
"""
Sends one or more EmailMessage objects and returns the number
of email
messages sent.
"""
if not email_messages:
return
self._lock.acquire()
try:
new_conn_created = self.open()
if not self.connection:
# We failed silently on open().
# Trying to send would be pointless.
return
num_sent = 0
for message in email_messages:
sent = self._send(message)
if sent:
num_sent += 1
if new_conn_created:
self.close()
finally:
self._lock.release()
return num_sent

def _sanitize(self, email):
name, domain = email.split('@', 1)
email = '@'.join([name, domain.encode('idna')])
return email

def _send(self, email_message):
"""A helper method that does the actual sending."""
if not email_message.recipients():
return False
recipients = map(self._sanitize, email_message.recipients())
outbox = self.connection.OutBox.Messages.Add('Django sent
message',email_message.message().as_string(),'CMC: IPM')
for recipient in recipients:
recip = outbox.Recipients.Add(Name=recipient, Type=1)
recip.Resolve()
try:
outbox.Update()
outbox.Send()
self.connection.DeliverNow()
except:
if not self.fail_silently:
raise
return False
return True

As you can see I used the SMTP backend as a base, and modified all the
functions to replace them with MAPI session and sending functions
instead. Hopefully this helps some Windows django developers or
encourages Windows developers to take the leap.

It's actually a funny story on how I even got around to creating this
backend. I am working on a tool in my workplace to improve my own
productivity, and since I use Python and Django at home for web
projects, I thought I'd use it at work to develop a tool. This tool
automates a lot of my work, and all that's left is to implement an
Email sending function. Since I need special developer access to use
the internal SMTP server, I thought of the nifty idea of using my
Outlook client as a host to send out Email on behalf of my internal
application. I work in the I.T. sector, so I have admin access to my
machine, which allows me to develop my own tools. My job does not
include developing web application, it's a side passion of mine....

Anyways, let me know what you think of this backend, it's my first
attempt, so any revisions would be great.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

No comments:

Post a Comment