Merge pull request #22 from brack3t/attachments

Support attachments
This commit is contained in:
Mike Edmunds
2013-01-09 12:34:50 -08:00
3 changed files with 82 additions and 2 deletions

View File

@@ -122,7 +122,10 @@ 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, but Mandrill will
(silently) ignore any attachment types it doesn't allow. According to
Mandrill's docs, attachments are only allowed with the mimetypes "text/\*",
"image/\*", or "application/pdf".
* 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',