diff --git a/src/wuttjamaican/email.py b/src/wuttjamaican/email.py index a7f138f..8ae62b5 100644 --- a/src/wuttjamaican/email.py +++ b/src/wuttjamaican/email.py @@ -166,6 +166,10 @@ class Message: .. attribute:: html_body String with the ``text/html`` body content. + + .. attribute:: attachments + + List of file attachments for the message. """ def __init__( @@ -179,6 +183,7 @@ class Message: replyto=None, txt_body=None, html_body=None, + attachments=None, ): self.key = key self.sender = sender @@ -189,6 +194,7 @@ class Message: self.replyto = replyto self.txt_body = txt_body self.html_body = html_body + self.attachments = attachments or [] def set_recips(self, name, value): """ """ @@ -224,6 +230,13 @@ class Message: if not msg: raise ValueError("message has no body parts") + if self.attachments: + for attachment in self.attachments: + if isinstance(attachment, str): + raise ValueError("must specify valid MIME attachments; this class cannot " + "auto-create them from file path etc.") + msg = MIMEMultipart(_subtype='mixed', _subparts=[msg] + self.attachments) + msg['Subject'] = self.subject msg['From'] = self.sender diff --git a/tests/test_email.py b/tests/test_email.py index 1776723..7e0c062 100644 --- a/tests/test_email.py +++ b/tests/test_email.py @@ -1,5 +1,6 @@ # -*- coding: utf-8; -*- +from email.mime.text import MIMEText from unittest import TestCase from unittest.mock import patch, MagicMock @@ -8,7 +9,7 @@ import pytest from wuttjamaican import email as mod from wuttjamaican.util import resource_path from wuttjamaican.exc import ConfigurationError -from wuttjamaican.testing import ConfigTestCase +from wuttjamaican.testing import ConfigTestCase, FileTestCase class TestEmailSetting(ConfigTestCase): @@ -24,7 +25,7 @@ class TestEmailSetting(ConfigTestCase): self.assertEqual(setting.sample_data(), {}) -class TestMessage(TestCase): +class TestMessage(FileTestCase): def make_message(self, **kwargs): return mod.Message(**kwargs) @@ -77,6 +78,26 @@ class TestMessage(TestCase): complete = msg.as_string() self.assertIn('From: bob@example.com', complete) + # html + attachment + csv_part = MIMEText("foo,bar\n1,2", 'csv', 'utf_8') + msg = self.make_message(sender='bob@example.com', + html_body="
hello world
", + attachments=[csv_part]) + complete = msg.as_string() + self.assertIn('Content-Type: multipart/mixed; boundary=', complete) + self.assertIn('Content-Type: text/csv; charset="utf_8"', complete) + + # error if improper attachment + csv_path = self.write_file('data.csv', "foo,bar\n1,2") + msg = self.make_message(sender='bob@example.com', + html_body="hello world
", + attachments=[csv_path]) + self.assertRaises(ValueError, msg.as_string) + try: + msg.as_string() + except ValueError as err: + self.assertIn("must specify valid MIME attachments", str(err)) + # everything msg = self.make_message(sender='bob@example.com', subject='meeting follow-up',