diff --git a/djrill/mail/backends/djrill.py b/djrill/mail/backends/djrill.py index c14807d..9114ca9 100644 --- a/djrill/mail/backends/djrill.py +++ b/djrill/mail/backends/djrill.py @@ -206,14 +206,15 @@ class DjrillBackend(BaseEmailBackend): def _add_attachments(self, message, msg_dict): """Extend msg_dict to include any attachments in message""" if message.attachments: + str_encoding = message.encoding or settings.DEFAULT_CHARSET attachments = [ - self._make_mandrill_attachment(attachment) - for attachment in message.attachments + self._make_mandrill_attachment(attachment, str_encoding) + for attachment in message.attachments ] if len(attachments) > 0: msg_dict['attachments'] = attachments - def _make_mandrill_attachment(self, attachment): + def _make_mandrill_attachment(self, attachment, str_encoding=None): """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 @@ -244,9 +245,19 @@ class DjrillBackend(BaseEmailBackend): "text/*, image/*, and application/pdf attachments." % mimetype) + try: + content_b64 = b64encode(content) + except TypeError: + # Python 3 b64encode requires bytes. Convert str attachment: + if isinstance(content, str): + content_bytes = content.encode(str_encoding) + content_b64 = b64encode(content_bytes) + else: + raise + return { 'type': mimetype, 'name': filename or "", - 'content': b64encode(content), + 'content': content_b64.decode('ascii'), } diff --git a/djrill/tests/test_mandrill_send.py b/djrill/tests/test_mandrill_send.py index 165dd53..2b2710d 100644 --- a/djrill/tests/test_mandrill_send.py +++ b/djrill/tests/test_mandrill_send.py @@ -1,4 +1,4 @@ -from base64 import b64encode +from base64 import b64decode from email.mime.base import MIMEBase from django.conf import settings @@ -100,18 +100,18 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase): 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, + text_content = "* Item one\n* Item two\n* Item three" + email.attach(filename="test.txt", content=text_content, 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) + png_content = b"PNG\xb4 pretend this is the contents of a png file" + email.attach(filename="test.png", content=png_content) # Should work with a MIMEBase object (also tests no filename)... - content3 = "PDF* pretend this is valid pdf data" + pdf_content = b"PDF\xb4 pretend this is valid pdf data" mimeattachment = MIMEBase('application', 'pdf') - mimeattachment.set_payload(content3) + mimeattachment.set_payload(pdf_content) email.attach(mimeattachment) email.send() @@ -120,13 +120,14 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase): 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(b64decode(attachments[0]["content"]).decode('ascii'), + text_content) self.assertEqual(attachments[1]["type"], "image/png") # inferred self.assertEqual(attachments[1]["name"], "test.png") - self.assertEqual(attachments[1]["content"], b64encode(content2)) + self.assertEqual(b64decode(attachments[1]["content"]), png_content) self.assertEqual(attachments[2]["type"], "application/pdf") self.assertEqual(attachments[2]["name"], "") # none - self.assertEqual(attachments[2]["content"], b64encode(content3)) + self.assertEqual(b64decode(attachments[2]["content"]), pdf_content) def test_extra_header_errors(self): email = mail.EmailMessage('Subject', 'Body', 'from@example.com',