[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 f28ea02308 from master.
This commit is contained in:
Florian Apolloner 2013-12-28 12:40:10 +01:00
parent 2d08390d70
commit 35a447a263
1 changed files with 30 additions and 32 deletions

View File

@ -5,8 +5,8 @@ import os
import random import random
import sys import sys
import time import time
from email import generator
from email import charset as Charset, encoders as Encoders from email import charset as Charset, encoders as Encoders
from email.generator import Generator
from email.mime.text import MIMEText from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase from email.mime.base import MIMEBase
@ -119,7 +119,34 @@ def sanitize_address(addr, encoding):
return formataddr((nm, addr)) return formataddr((nm, addr))
class SafeMIMEText(MIMEText): 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
header.
This overrides the default as_string() implementation to not mangle
lines that begin with 'From '. See bug #13433 for details.
"""
# 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 SafeMIMEText(MIMEMixin, MIMEText):
def __init__(self, text, subtype, charset): def __init__(self, text, subtype, charset):
self.encoding = charset self.encoding = charset
@ -129,24 +156,8 @@ class SafeMIMEText(MIMEText):
name, val = forbid_multi_line_headers(name, val, self.encoding) name, val = forbid_multi_line_headers(name, val, self.encoding)
MIMEText.__setitem__(self, name, val) MIMEText.__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 class SafeMIMEMultipart(MIMEMixin, MIMEMultipart):
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()
class SafeMIMEMultipart(MIMEMultipart):
def __init__(self, _subtype='mixed', boundary=None, _subparts=None, encoding=None, **_params): def __init__(self, _subtype='mixed', boundary=None, _subparts=None, encoding=None, **_params):
self.encoding = encoding self.encoding = encoding
@ -156,19 +167,6 @@ class SafeMIMEMultipart(MIMEMultipart):
name, val = forbid_multi_line_headers(name, val, self.encoding) name, val = forbid_multi_line_headers(name, val, self.encoding)
MIMEMultipart.__setitem__(self, name, val) 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): class EmailMessage(object):
""" """