Support sending attachments

This commit is contained in:
medmunds
2013-01-03 13:52:41 -08:00
parent e529fe682d
commit 5b4f4c12cb
3 changed files with 80 additions and 2 deletions

View File

@@ -122,7 +122,8 @@ Djrill supports most of the functionality of Django's `EmailMessage`_ and
raise a ``ValueError`` exception when you attempt to send the message. raise a ``ValueError`` exception when you attempt to send the message.
(Mandrill doesn't support sending multiple html alternative parts, or any (Mandrill doesn't support sending multiple html alternative parts, or any
non-html alternatives.) non-html alternatives.)
* Djrill (currently) silently ignores all attachments on a message. * Djrill attempts to include a message's attachments, though Mandrill may place
some restrictions on allowable attachment types. (See the Mandrill docs.)
* Djrill treats all cc and bcc recipients as if they were additional "to" * Djrill treats all cc and bcc recipients as if they were additional "to"
addresses. (Mandrill does not distinguish cc, and only allows a single bcc -- addresses. (Mandrill does not distinguish cc, and only allows a single bcc --
which Djrill doesn't use. *Caution:* depending on the ``preserve_recipients`` which Djrill doesn't use. *Caution:* depending on the ``preserve_recipients``

View File

@@ -1,10 +1,13 @@
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.mail.backends.base import BaseEmailBackend from django.core.mail.backends.base import BaseEmailBackend
from django.core.mail.message import sanitize_address from django.core.mail.message import sanitize_address, DEFAULT_ATTACHMENT_MIME_TYPE
from django.utils import simplejson as json from django.utils import simplejson as json
from base64 import b64encode
from email.mime.base import MIMEBase
from email.utils import parseaddr from email.utils import parseaddr
import mimetypes
import requests import requests
# This backend was developed against this API endpoint. # This backend was developed against this API endpoint.
@@ -68,6 +71,7 @@ class DjrillBackend(BaseEmailBackend):
self._add_mandrill_options(message, msg_dict) self._add_mandrill_options(message, msg_dict)
if getattr(message, 'alternatives', None): if getattr(message, 'alternatives', None):
self._add_alternatives(message, msg_dict) self._add_alternatives(message, msg_dict)
self._add_attachments(message, msg_dict)
except ValueError: except ValueError:
if not self.fail_silently: if not self.fail_silently:
raise raise
@@ -186,3 +190,39 @@ class DjrillBackend(BaseEmailBackend):
% mimetype) % mimetype)
msg_dict['html'] = content msg_dict['html'] = content
def _add_attachments(self, message, msg_dict):
"""Extend msg_dict to include any attachments in message"""
if message.attachments:
attachments = [
self._make_mandrill_attachment(attachment)
for attachment in message.attachments
]
if len(attachments) > 0:
msg_dict['attachments'] = attachments
def _make_mandrill_attachment(self, attachment):
"""Return a Mandrill dict for an EmailMessage.attachments item"""
# Note that an attachment can be either a tuple of (filename, content,
# mimetype) or a MIMEBase object. (Also, both filename and mimetype may
# be missing.)
if isinstance(attachment, MIMEBase):
filename = attachment.get_filename()
content = attachment.get_payload(decode=True)
mimetype = attachment.get_content_type()
else:
(filename, content, mimetype) = attachment
# Guess missing mimetype, borrowed from
# django.core.mail.EmailMessage._create_attachment()
if mimetype is None and filename is not None:
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
return {
'type': mimetype,
'name': filename or "",
'content': b64encode(content),
}

View File

@@ -1,3 +1,6 @@
from base64 import b64encode
from email.mime.base import MIMEBase
from django.conf import settings from django.conf import settings
from django.core import mail from django.core import mail
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@@ -78,6 +81,40 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
data = self.get_api_call_data() data = self.get_api_call_data()
self.assertEqual(data['message']['text'], text_content) self.assertEqual(data['message']['text'], text_content)
self.assertEqual(data['message']['html'], html_content) self.assertEqual(data['message']['html'], html_content)
# Don't accidentally send the html part as an attachment:
self.assertFalse('attachments' in data['message'])
def test_attachments(self):
email = mail.EmailMessage('Subject', 'Body goes here',
'from@example.com', ['to1@example.com'])
content1 = "* Item one\n* Item two\n* Item three"
email.attach(filename="test.txt", content=content1,
mimetype="text/plain")
# Should guess mimetype if not provided...
content2 = "PNG* pretend this is the contents of a png file"
email.attach(filename="test.png", content=content2)
# Should work with a MIMEBase object (also tests no filename)...
content3 = "PDF* pretend this is valid pdf data"
mimeattachment = MIMEBase('application', 'pdf')
mimeattachment.set_payload(content3)
email.attach(mimeattachment)
email.send()
data = self.get_api_call_data()
attachments = data['message']['attachments']
self.assertEqual(len(attachments), 3)
self.assertEqual(attachments[0]["type"], "text/plain")
self.assertEqual(attachments[0]["name"], "test.txt")
self.assertEqual(attachments[0]["content"], b64encode(content1))
self.assertEqual(attachments[1]["type"], "image/png") # inferred
self.assertEqual(attachments[1]["name"], "test.png")
self.assertEqual(attachments[1]["content"], b64encode(content2))
self.assertEqual(attachments[2]["type"], "application/pdf")
self.assertEqual(attachments[2]["name"], "") # none
self.assertEqual(attachments[2]["content"], b64encode(content3))
def test_extra_header_errors(self): def test_extra_header_errors(self):
email = mail.EmailMessage('Subject', 'Body', 'from@example.com', email = mail.EmailMessage('Subject', 'Body', 'from@example.com',