above Backend will not work, unless perhaps you use an older version
of windows or exchange. That code seems outdated. Here is code that
is verified to work with Windows 7 and Outlook 2010, it should work
with others as this code is taken from the MAPI example in the Win32
extensions and adapted for an Email backend. I will be verifying if
it works. Enjoy!
from win32com.mapi import mapi
from win32com.mapi import mapitags
import threading
from django.conf import settings
from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend):
"""
A wrapper that manages the MAPI interface.
"""
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:
mapi.MAPIInitialize(None)
if self.MAPIProfile <> None:
MAPIProfile = self.MAPIProfile
else:
MAPIProfile = ""
session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED
| mapi.MAPI_USE_DEFAULT)
messagestorestable = session.GetMsgStoresTable(0)
messagestorestable.SetColumns((mapitags.PR_ENTRYID,
mapitags.PR_DISPLAY_NAME_A, mapitags.PR_DEFAULT_STORE),0)
while True:
rows = messagestorestable.QueryRows(1, 0)
#if this is the last row then stop
if len(rows) != 1:
break
row = rows[0]
#if this is the default store then stop
if ((mapitags.PR_DEFAULT_STORE,True) in row):
break
# unpack the row and open the message store
(eid_tag, eid), (name_tag, name), (def_store_tag, def_store) = row
msgstore = session.OpenMsgStore(0,eid,None,mapi.MDB_NO_DIALOG |
mapi.MAPI_BEST_ACCESS)
# get the outbox
hr, props = msgstore.GetProps((mapitags.PR_IPM_OUTBOX_ENTRYID), 0)
(tag, eid) = props[0]
#check for errors
if mapitags.PROP_TYPE(tag) == mapitags.PT_ERROR:
raise TypeError('got PT_ERROR instead of PT_BINARY: %s'%eid)
self.connection =
msgstore.OpenEntry(eid,None,mapi.MAPI_BEST_ACCESS)
return True
except:
if not self.fail_silently:
raise
def close(self):
"""Closes the connection to the exchange server."""
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 _makeentry(recipient, recipienttype):
"""A helper method that creates the MAPI Object for the
recipient."""
return ((mapitags.PR_RECIPIENT_TYPE, recipienttype),
(mapitags.PR_SEND_RICH_INFO, False),
(mapitags.PR_DISPLAY_TYPE, 0),
(mapitags.PR_OBJECT_TYPE, 6),
(mapitags.PR_EMAIL_ADDRESS_A, recipient),
(mapitags.PR_ADDRTYPE_A, 'SMTP'),
(mapitags.PR_DISPLAY_NAME_A, recipient))
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())
message = self.connection.CreateMessage(None,0)
pal = []
for recipient in recipients:
pal.extend([self._makeentry(recipient, mapi.MAPI_TO)])
# add the resolved recipients to the message
message.ModifyRecipients(mapi.MODRECIP_ADD,pal)
message.SetProps([(mapitags.PR_BODY_A,email_message.message().as_string()),
(mapitags.PR_SUBJECT_A,'Django sent message')])
self.connection.SaveChanges(0)
message.SubmitMessage(0)
return True
On Oct 3, 4:01 am, Kevin <kveron...@gmail.com> wrote:
> 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