From 458e2fbfcc0a06d7d55ff5a1dcd79c91c64e8138 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Tue, 11 Oct 2016 20:53:26 +0200 Subject: [PATCH] Fixed #27333 -- Prevented BASE64 encoding in message.as_string() on Python 3 Thanks Tim Graham for the review. --- django/core/mail/message.py | 29 +++++++++-------------------- tests/mail/tests.py | 4 ++++ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/django/core/mail/message.py b/django/core/mail/message.py index 44178d2447..98f3cfd632 100644 --- a/django/core/mail/message.py +++ b/django/core/mail/message.py @@ -211,31 +211,20 @@ class SafeMIMEText(MIMEMixin, MIMEText): def __init__(self, _text, _subtype='plain', _charset=None): self.encoding = _charset - if _charset == 'utf-8': - # Unfortunately, Python doesn't yet pass a Charset instance as - # MIMEText init parameter to set_payload(). - # http://bugs.python.org/issue27445 - # We do it manually and trigger re-encoding of the payload. - if six.PY3 and isinstance(_text, bytes): - # Sniffing encoding would fail with bytes content in MIMEText.__init__. - _text = _text.decode('utf-8') - MIMEText.__init__(self, _text, _subtype, None) - del self['Content-Transfer-Encoding'] - has_long_lines = any(len(l) > RFC5322_EMAIL_LINE_LENGTH_LIMIT for l in _text.splitlines()) - # Quoted-Printable encoding has the side effect of shortening long - # lines, if any (#22561). - self.set_payload(_text, utf8_charset_qp if has_long_lines else utf8_charset) - self.replace_header('Content-Type', 'text/%s; charset="%s"' % (_subtype, _charset)) - elif _charset is None: - # the default value of '_charset' is 'us-ascii' on Python 2 - MIMEText.__init__(self, _text, _subtype) - else: - MIMEText.__init__(self, _text, _subtype, _charset) + MIMEText.__init__(self, _text, _subtype=_subtype, _charset=_charset) def __setitem__(self, name, val): name, val = forbid_multi_line_headers(name, val, self.encoding) MIMEText.__setitem__(self, name, val) + def set_payload(self, payload, charset=None): + if charset == 'utf-8': + has_long_lines = any(len(l) > RFC5322_EMAIL_LINE_LENGTH_LIMIT for l in payload.splitlines()) + # Quoted-Printable encoding has the side effect of shortening long + # lines, if any (#22561). + charset = utf8_charset_qp if has_long_lines else utf8_charset + MIMEText.set_payload(self, payload, charset=charset) + class SafeMIMEMultipart(MIMEMixin, MIMEMultipart): diff --git a/tests/mail/tests.py b/tests/mail/tests.py index bc0d8eabc9..662cd7c6d6 100644 --- a/tests/mail/tests.py +++ b/tests/mail/tests.py @@ -572,6 +572,8 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): ) s = msg.message().as_bytes() self.assertIn(b'Content-Transfer-Encoding: 8bit', s) + s = msg.message().as_string() + self.assertIn(str('Content-Transfer-Encoding: 8bit'), s) msg = EmailMessage( 'Subject', 'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', 'bounce@example.com', @@ -579,6 +581,8 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): ) s = msg.message().as_bytes() self.assertIn(b'Content-Transfer-Encoding: 8bit', s) + s = msg.message().as_string() + self.assertIn(str('Content-Transfer-Encoding: 8bit'), s) def test_dont_base64_encode_message_rfc822(self): # Ticket #18967