40 textwrap dedent to whomitmayconcernexample com from nobodyyouwanttoknowexample com subject we the willing led by the unknowing are doing the impossible for the ungrateful we have done so much for so long with so little we are now qualified to do anything with nothing none refoldlongexpected100 refoldlongexpected0 refoldallexpected refoldlongexpected copy refoldallexpected0 to whomitmayconcernexample comn from nobodyyouwanttoknowexample comn subject we the willing led by the unknowing are doing the impossible for the ungrateful we have done so much for so long with so little we are now qualified to do anything with nothing n n nonen refoldallexpected100 to whomitmayconcernexample comn from nobodyyouwanttoknowexample comn subject we the willing led by the unknowing are doing the impossible for the ungrateful we haven done so much for so long with so little we are now qualified to do anything with nothing n n nonen lengthparams n for n in refoldlongexpected def lengthasmaxheaderlenparameterself n msg self msgmakerself typself refoldlongexpected0 s self ioclass g self genclasss maxheaderlenn policyself policy g flattenmsg self assertequals getvalue self typself refoldlongexpectedn def lengthasmaxlinelengthpolicyself n msg self msgmakerself typself refoldlongexpected0 s self ioclass g self genclasss policyself policy clonemaxlinelengthn g flattenmsg self assertequals getvalue self typself refoldlongexpectedn def lengthasmaxheaderlenparmoverridespolicyself n msg self msgmakerself typself refoldlongexpected0 s self ioclass g self genclasss maxheaderlenn policyself policy clonemaxlinelength10 g flattenmsg self assertequals getvalue self typself refoldlongexpectedn def lengthasmaxlinelengthwithrefoldnonedoesnotfoldself n msg self msgmakerself typself refoldlongexpected0 s self ioclass g self genclasss policyself policy clonerefoldsource none maxlinelengthn g flattenmsg self assertequals getvalue self typself refoldlongexpected0 def lengthasmaxlinelengthwithrefoldallfoldsself n msg self msgmakerself typself refoldlongexpected0 s self ioclass g self genclasss policyself policy clonerefoldsource all maxlinelengthn g flattenmsg self assertequals getvalue self typself refoldallexpectedn def testcrlfcontrolviapolicyself source subject testrnrntest bodyrn expected source msg self msgmakerself typsource s self ioclass g self genclasss policypolicy smtp g flattenmsg self assertequals getvalue self typexpected def testflattenlinesepoverridespolicyself source subject testnntest bodyn expected source msg self msgmakerself typsource s self ioclass g self genclasss policypolicy smtp g flattenmsg linesep n self assertequals getvalue self typexpected def testsetmanglefromviapolicyself source textwrap dedent subject test that from is mangled in the body from time to time i write a rhyme this is pretty much just to make sure we don t have an infinite loop i don t expect anyone to hit this in the field expected textwrap dedent to nobody contentdisposition attachment filename0usascii afilename filename1longenoghtowraphere none this is just to make sure we don t have an infinite loop i don t expect anyone to hit this in the field so i m not bothering to make the result optimal the encoding isn t needed expected textwrap dedent to nobody contentdisposition attachment filename0usascii afilenamelongenoghtowraphere none encode latin1 msg messagefrombytessource expected textwrap dedent from foobar com to dinsdale subject nudge nudge wink wink mimeversion 1 0 contenttype textplain charsetiso88591 contenttransferencoding quotedprintable oh le0 le0 know what i mean know what i mean encode utf8 replaceb n b rn s io bytesio g bytesgenerators policypolicy smtputf8 g flattenmsg self assertequals getvalue expected def testsmtppolicyself msg emailmessage msgfrom addressaddrspecfoobar com displaynamepolo msgto addressaddrspecbarfoo com displaynamedinsdale msgsubject nudge nudge wink wink msg setcontentoh boy know what i mean know what i mean expected textwrap dedent from utf8 q pc3a1olo foobar com to dinsdale barfoo com subject nudge nudge wink wink contenttype textplain charsetutf8 contenttransferencoding 7bit mimeversion 1 0 oh boy know what i mean know what i mean to whom_it_may_concern example com from nobody_you_want_to_know example com subject we the willing led by the unknowing are doing the impossible for the ungrateful we have done so much for so long with so little we are now qualified to do anything with nothing none to whom_it_may_concern example com from nobody_you_want_to_know example com subject we the willing led by the unknowing are doing the impossible for the ungrateful we have done so much for so long with so little we are now qualified to do anything with nothing none to whom_it_may_concern example com from nobody_you_want_to_know example com subject we the willing led by the unknowing are doing the impossible for the ungrateful we have done so much for so long with so little we are now qualified to do anything with nothing none subject test that from is mangled in the body from time to time i write a rhyme this is pretty much just to make sure we don t have an infinite loop i don t expect anyone to hit this in the field to nobody content disposition attachment filename afilenamelongenoghtowraphere none to nobody content disposition attachment filename 0 us ascii afilename filename 1 longenoghtowraphere none this is just to make sure we don t have an infinite loop i don t expect anyone to hit this in the field so i m not bothering to make the result optimal the encoding isn t needed to nobody content disposition attachment filename afilenamelongenoghtowraphere none to nobody content disposition attachment filename 0 us ascii afilenamelongenoghtowraphere none from foo bar com to dinsdale subject nudge nudge wink wink mime version 1 0 content type text plain charset latin 1 content transfer encoding 8bit oh là là know what i mean know what i mean from foo bar com to dinsdale subject nudge nudge wink wink mime version 1 0 content type text plain charset iso 8859 1 content transfer encoding quoted printable oh l e0 l e0 know what i mean know what i mean from páolo főo bar com to dinsdale subject nudge nudge wink wink u1f609 content type text plain charset utf 8 content transfer encoding 8bit mime version 1 0 oh là là know what i mean know what i mean from utf 8 q p c3 a1olo foo bar com to dinsdale bar foo com subject nudge nudge wink wink content type text plain charset utf 8 content transfer encoding 7bit mime version 1 0 oh boy know what i mean know what i mean
import io
import textwrap
import unittest
from email import message_from_string, message_from_bytes
from email.message import EmailMessage
from email.generator import Generator, BytesGenerator
from email.headerregistry import Address
from email import policy
from test.test_email import TestEmailBase, parameterize


@parameterize
class TestGeneratorBase:

    policy = policy.default

    def msgmaker(self, msg, policy=None):
        policy = self.policy if policy is None else policy
        return self.msgfunc(msg, policy=policy)

    refold_long_expected = {
        0: textwrap.dedent(),
        40: textwrap.dedent(),
        20: textwrap.dedent(),
        }
    refold_long_expected[100] = refold_long_expected[0]

    refold_all_expected = refold_long_expected.copy()
    refold_all_expected[0] = (
            "To: whom_it_may_concern@example.com\n"
            "From: nobody_you_want_to_know@example.com\n"
            "Subject: We the willing led by the unknowing are doing the "
              "impossible for the ungrateful. We have done so much for "
              "so long with so little we are now qualified to do anything "
              "with nothing.\n"
              "\n"
              "None\n")
    refold_all_expected[100] = (
            "To: whom_it_may_concern@example.com\n"
            "From: nobody_you_want_to_know@example.com\n"
            "Subject: We the willing led by the unknowing are doing the "
                "impossible for the ungrateful. We have\n"
              " done so much for so long with so little we are now qualified "
                "to do anything with nothing.\n"
              "\n"
              "None\n")

    length_params = [n for n in refold_long_expected]

    def length_as_maxheaderlen_parameter(self, n):
        msg = self.msgmaker(self.typ(self.refold_long_expected[0]))
        s = self.ioclass()
        g = self.genclass(s, maxheaderlen=n, policy=self.policy)
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(self.refold_long_expected[n]))

    def length_as_max_line_length_policy(self, n):
        msg = self.msgmaker(self.typ(self.refold_long_expected[0]))
        s = self.ioclass()
        g = self.genclass(s, policy=self.policy.clone(max_line_length=n))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(self.refold_long_expected[n]))

    def length_as_maxheaderlen_parm_overrides_policy(self, n):
        msg = self.msgmaker(self.typ(self.refold_long_expected[0]))
        s = self.ioclass()
        g = self.genclass(s, maxheaderlen=n,
                          policy=self.policy.clone(max_line_length=10))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(self.refold_long_expected[n]))

    def length_as_max_line_length_with_refold_none_does_not_fold(self, n):
        msg = self.msgmaker(self.typ(self.refold_long_expected[0]))
        s = self.ioclass()
        g = self.genclass(s, policy=self.policy.clone(refold_source='none',
                                                      max_line_length=n))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(self.refold_long_expected[0]))

    def length_as_max_line_length_with_refold_all_folds(self, n):
        msg = self.msgmaker(self.typ(self.refold_long_expected[0]))
        s = self.ioclass()
        g = self.genclass(s, policy=self.policy.clone(refold_source='all',
                                                      max_line_length=n))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(self.refold_all_expected[n]))

    def test_crlf_control_via_policy(self):
        source = "Subject: test\r\n\r\ntest body\r\n"
        expected = source
        msg = self.msgmaker(self.typ(source))
        s = self.ioclass()
        g = self.genclass(s, policy=policy.SMTP)
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(expected))

    def test_flatten_linesep_overrides_policy(self):
        source = "Subject: test\n\ntest body\n"
        expected = source
        msg = self.msgmaker(self.typ(source))
        s = self.ioclass()
        g = self.genclass(s, policy=policy.SMTP)
        g.flatten(msg, linesep='\n')
        self.assertEqual(s.getvalue(), self.typ(expected))

    def test_set_mangle_from_via_policy(self):
        source = textwrap.dedent()
        variants = (
            (None, True),
            (policy.compat32, True),
            (policy.default, False),
            (policy.default.clone(mangle_from_=True), True),
            )
        for p, mangle in variants:
            expected = source.replace('From ', '>From ') if mangle else source
            with self.subTest(policy=p, mangle_from_=mangle):
                msg = self.msgmaker(self.typ(source))
                s = self.ioclass()
                g = self.genclass(s, policy=p)
                g.flatten(msg)
                self.assertEqual(s.getvalue(), self.typ(expected))

    def test_compat32_max_line_length_does_not_fold_when_none(self):
        msg = self.msgmaker(self.typ(self.refold_long_expected[0]))
        s = self.ioclass()
        g = self.genclass(s, policy=policy.compat32.clone(max_line_length=None))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(self.refold_long_expected[0]))

    def test_rfc2231_wrapping(self):
        
        
        msg = self.msgmaker(self.typ(textwrap.dedent()))
        expected = textwrap.dedent()
        s = self.ioclass()
        g = self.genclass(s, policy=self.policy.clone(max_line_length=33))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(expected))

    def test_rfc2231_wrapping_switches_to_default_len_if_too_narrow(self):
        
        
        
        msg = self.msgmaker(self.typ(textwrap.dedent()))
        expected = textwrap.dedent()
        s = self.ioclass()
        g = self.genclass(s, policy=self.policy.clone(max_line_length=20))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), self.typ(expected))


class TestGenerator(TestGeneratorBase, TestEmailBase):

    msgfunc = staticmethod(message_from_string)
    genclass = Generator
    ioclass = io.StringIO
    typ = str


class TestBytesGenerator(TestGeneratorBase, TestEmailBase):

    msgfunc = staticmethod(message_from_bytes)
    genclass = BytesGenerator
    ioclass = io.BytesIO
    typ = lambda self, x: x.encode('ascii')

    def test_cte_type_7bit_handles_unknown_8bit(self):
        source = ("Subject: Maintenant je vous présente mon "
                 "collègue\n\n").encode('utf-8')
        expected = ('Subject: Maintenant je vous =?unknown-8bit?q?'
                    'pr=C3=A9sente_mon_coll=C3=A8gue?=\n\n').encode('ascii')
        msg = message_from_bytes(source)
        s = io.BytesIO()
        g = BytesGenerator(s, policy=self.policy.clone(cte_type='7bit'))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), expected)

    def test_cte_type_7bit_transforms_8bit_cte(self):
        source = textwrap.dedent().encode('latin1')
        msg = message_from_bytes(source)
        expected =  textwrap.dedent().encode('ascii')
        s = io.BytesIO()
        g = BytesGenerator(s, policy=self.policy.clone(cte_type='7bit',
                                                       linesep='\n'))
        g.flatten(msg)
        self.assertEqual(s.getvalue(), expected)

    def test_smtputf8_policy(self):
        msg = EmailMessage()
        msg['From'] = "Páolo <főo@bar.com>"
        msg['To'] = 'Dinsdale'
        msg['Subject'] = 'Nudge nudge, wink, wink \u1F609'
        msg.set_content("oh là là, know what I mean, know what I mean?")
        expected = textwrap.dedent().encode('utf-8').replace(b'\n', b'\r\n')
        s = io.BytesIO()
        g = BytesGenerator(s, policy=policy.SMTPUTF8)
        g.flatten(msg)
        self.assertEqual(s.getvalue(), expected)

    def test_smtp_policy(self):
        msg = EmailMessage()
        msg["From"] = Address(addr_spec="foo@bar.com", display_name="Páolo")
        msg["To"] = Address(addr_spec="bar@foo.com", display_name="Dinsdale")
        msg["Subject"] = "Nudge nudge, wink, wink"
        msg.set_content("oh boy, know what I mean, know what I mean?")
        expected = textwrap.dedent().encode().replace(b"\n", b"\r\n")
        s = io.BytesIO()
        g = BytesGenerator(s, policy=policy.SMTP)
        g.flatten(msg)
        self.assertEqual(s.getvalue(), expected)


if __name__ == '__main__':
    unittest.main()