Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[1.6.x] Fixed #21093 -- Ensured that mails are not base64 encoded on …

…python 3.3.3+.

Thanks to Arfrever for the report and Aymeric for the review.

Backport of f28ea02 from master.
  • Loading branch information...
commit 35a447a263115b22a7040a9f4a16ff4bd2078466 1 parent 2d08390
@apollo13 apollo13 authored
Showing with 30 additions and 32 deletions.
  1. +30 −32 django/core/mail/message.py
View
62 django/core/mail/message.py
@@ -5,8 +5,8 @@
import random
import sys
import time
+from email import generator
from email import charset as Charset, encoders as Encoders
-from email.generator import Generator
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
@@ -119,16 +119,7 @@ def sanitize_address(addr, encoding):
return formataddr((nm, addr))
-class SafeMIMEText(MIMEText):
-
- def __init__(self, text, subtype, charset):
- self.encoding = charset
- MIMEText.__init__(self, text, subtype, charset)
-
- def __setitem__(self, name, val):
- name, val = forbid_multi_line_headers(name, val, self.encoding)
- MIMEText.__setitem__(self, name, val)
-
+class MIMEMixin():
def as_string(self, unixfrom=False):
"""Return the entire formatted message as a string.
Optional `unixfrom' when True, means include the Unix From_ envelope
@@ -137,16 +128,36 @@ def as_string(self, unixfrom=False):
This overrides the default as_string() implementation to not mangle
lines that begin with 'From '. See bug #13433 for details.
"""
- fp = six.StringIO()
- g = Generator(fp, mangle_from_ = False)
- if sys.version_info < (2, 6, 6) and isinstance(self._payload, six.text_type):
- # Workaround for http://bugs.python.org/issue1368247
- self._payload = self._payload.encode(self._charset.output_charset)
- g.flatten(self, unixfrom=unixfrom)
- return fp.getvalue()
+ # Using a normal Generator on python 3 will yield a string, which will
+ # get base64 encoded in some cases to ensure that it's always convertable
+ # to ascii. We don't want base64 encoded emails, so we use a BytesGenertor
+ # which will do the right thing and then decode according to our known
+ # encoding. See #21093 and #3472 for details.
+ if six.PY3 and sys.version_info >= (3, 3, 3):
+ fp = six.BytesIO()
+ g = generator.BytesGenerator(fp, mangle_from_=False)
+ g.flatten(self, unixfrom=unixfrom)
+ encoding = self.get_charset().get_output_charset() if self.get_charset() else 'utf-8'
+ return fp.getvalue().decode(encoding)
+ else:
+ fp = six.StringIO()
+ g = generator.Generator(fp, mangle_from_=False)
+ g.flatten(self, unixfrom=unixfrom)
+ return fp.getvalue()
-class SafeMIMEMultipart(MIMEMultipart):
+class SafeMIMEText(MIMEMixin, MIMEText):
+
+ def __init__(self, text, subtype, charset):
+ self.encoding = charset
+ MIMEText.__init__(self, text, subtype, charset)
+
+ def __setitem__(self, name, val):
+ name, val = forbid_multi_line_headers(name, val, self.encoding)
+ MIMEText.__setitem__(self, name, val)
+
+
+class SafeMIMEMultipart(MIMEMixin, MIMEMultipart):
def __init__(self, _subtype='mixed', boundary=None, _subparts=None, encoding=None, **_params):
self.encoding = encoding
@@ -156,19 +167,6 @@ def __setitem__(self, name, val):
name, val = forbid_multi_line_headers(name, val, self.encoding)
MIMEMultipart.__setitem__(self, name, val)
- def as_string(self, unixfrom=False):
- """Return the entire formatted message as a string.
- Optional `unixfrom' when True, means include the Unix From_ envelope
- header.
-
- This overrides the default as_string() implementation to not mangle
- lines that begin with 'From '. See bug #13433 for details.
- """
- fp = six.StringIO()
- g = Generator(fp, mangle_from_ = False)
- g.flatten(self, unixfrom=unixfrom)
- return fp.getvalue()
-
class EmailMessage(object):
"""
Please sign in to comment.
Something went wrong with that request. Please try again.