Commit 35a447a2 authored by Florian Apolloner's avatar Florian Apolloner
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 f28ea023 from master.
parent 2d08390d
Loading
Loading
Loading
Loading
+30 −32
Original line number Diff line number Diff line
@@ -5,8 +5,8 @@ import os
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 @@ class SafeMIMEText(MIMEText):
        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(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 = 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 @@ class SafeMIMEMultipart(MIMEMultipart):
        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):
    """