diff --git a/flask_mail.py b/flask_mail.py index d0756e5..384a452 100644 --- a/flask_mail.py +++ b/flask_mail.py @@ -254,6 +254,7 @@ class Message(object): :param extra_headers: A dictionary of additional headers for the message :param mail_options: A list of ESMTP options to be used in MAIL FROM command :param rcpt_options: A list of ESMTP options to be used in RCPT commands + :param subtype: Media subtype name for a message """ def __init__(self, subject='', @@ -270,7 +271,8 @@ def __init__(self, subject='', charset=None, extra_headers=None, mail_options=None, - rcpt_options=None): + rcpt_options=None, + subtype=None): sender = sender or current_app.extensions['mail'].default_sender @@ -290,6 +292,7 @@ def __init__(self, subject='', self.msgId = make_msgid() self.charset = charset self.extra_headers = extra_headers + self.subtype = subtype self.mail_options = mail_options or [] self.rcpt_options = rcpt_options or [] self.attachments = attachments or [] @@ -309,10 +312,11 @@ def html(self, value): else: self.alts['html'] = value - def _mimetext(self, text, subtype='plain'): + def _mimetext(self, text, subtype=None): """Creates a MIMEText object with the given subtype (default: 'plain') If the text is unicode, the utf-8 charset is used. """ + subtype = subtype or 'plain' charset = self.charset or 'utf-8' return MIMEText(text, _subtype=subtype, _charset=charset) @@ -325,16 +329,18 @@ def _message(self): if len(attachments) == 0 and not self.alts: # No html content and zero attachments means plain text - msg = self._mimetext(self.body) + msg = self._mimetext(self.body, self.subtype) elif len(attachments) > 0 and not self.alts: # No html and at least one attachment means multipart - msg = MIMEMultipart() + subtype = self.subtype or 'mixed' + msg = MIMEMultipart(_subtype=subtype) msg.attach(self._mimetext(self.body)) else: # Anything else - msg = MIMEMultipart() - alternative = MIMEMultipart('alternative') - alternative.attach(self._mimetext(self.body, 'plain')) + subtype = self.subtype or 'mixed' + msg = MIMEMultipart(_subtype=subtype) + alternative = MIMEMultipart(_subtype='alternative') + alternative.attach(self._mimetext(self.body)) for mimetype, content in self.alts.items(): alternative.attach(self._mimetext(content, mimetype)) msg.attach(alternative) diff --git a/tests.py b/tests.py index 182cac6..41c1edc 100644 --- a/tests.py +++ b/tests.py @@ -337,6 +337,7 @@ def test_html_message(self): self.assertEqual(html_text, msg.html) self.assertIn('Content-Type: multipart/alternative', msg.as_string()) + self.assertIn('Content-Type: text/html', msg.as_string()) def test_json_message(self): json_text = '{"msg": "Hello World!}' @@ -361,6 +362,8 @@ def test_html_message_with_attachments(self): self.assertEqual(html_text, msg.html) self.assertIn('Content-Type: multipart/alternative', msg.as_string()) + self.assertIn('Content-Type: text/html', msg.as_string()) + self.assertIn('Content-Type: text/plain', msg.as_string()) parsed = email.message_from_string(msg.as_string()) self.assertEqual(len(parsed.get_payload()), 2) @@ -547,6 +550,22 @@ def test_empty_subject_header(self): self.mail.send(msg) self.assertNotIn('Subject:', msg.as_string()) + def test_custom_subtype_without_attachment(self): + msg = Message(sender="from@example.com", + subject="testing", + recipients=["to@example.com"], + subtype="html") + self.assertIn('Content-Type: text/html', msg.as_string()) + + def test_custom_subtype_with_attachment(self): + msg = Message(sender="from@example.com", + subject="testing", + recipients=["to@example.com"], + subtype="related") + msg.attach(data=b"this is a test", + content_type="text/plain") + self.assertIn('Content-Type: multipart/related', msg.as_string()) + class TestMail(TestCase): def test_send(self):