asserts that the message has all headers message can be an instance of an email message subclass or a string with the contents of an email message headers should be a set of headername headervalue tuples nonbackend specific tests encode the specified django core mail message emailmessage then decode it using python s email parser module and for each attachment of the message return a list of tuples with filename content mimetype empty strings in various recipient arguments are always stripped off the final recipient list regression test for 7722 email emailmessage subject content fromexample com toexample com ccccexample com message email message self assertequalmessagecc ccexample com self assertequalemail recipients toexample com ccexample com test multiple cc with multiple to email emailmessage subject content fromexample com toexample com otherexample com ccccexample com cc otherexample com message email message self assertequalmessagecc ccexample com cc otherexample com self assertequal email recipients toexample com otherexample com ccexample com cc otherexample com testing with bcc email emailmessage subject content fromexample com toexample com otherexample com ccccexample com cc otherexample com bccbccexample com message email message self assertequalmessagecc ccexample com cc otherexample com self assertequal email recipients toexample com otherexample com ccexample com cc otherexample com bccexample com def testccheadersself message emailmessage subject content bounceexample com toexample com ccfooexample com headerscc overrideexample com message self assertequalmessagecc overrideexample com def testccinheadersonlyself message emailmessage subject content bounceexample com toexample com headerscc fooexample com message self assertequalmessagecc fooexample com def testreplytoself email emailmessage subject content fromexample com toexample com replytoreplytoexample com message email message self assertequalmessagereplyto replytoexample com email emailmessage subject content fromexample com toexample com replytoreplyto1example com replyto2example com message email message self assertequal messagereplyto replyto1example com replyto2example com def testrecipientsastupleself email emailmessage subject content fromexample com toexample com otherexample com ccccexample com cc otherexample com bccbccexample com message email message self assertequalmessagecc ccexample com cc otherexample com self assertequal email recipients toexample com otherexample com ccexample com cc otherexample com bccexample com def testrecipientsasstringself with self assertraisesmessage typeerror to argument must be a list or tuple emailmessagetofooexample com with self assertraisesmessage typeerror cc argument must be a list or tuple emailmessageccfooexample com with self assertraisesmessage typeerror bcc argument must be a list or tuple emailmessagebccfooexample com with self assertraisesmessage typeerror replyto argument must be a list or tuple emailmessagereplytoreplytoexample com def testheaderinjectionself msg header values can t contain newlines email emailmessage subjectninjection test content fromexample com toexample com with self assertraisesmessagebadheadererror msg email message email emailmessage gettextlazysubjectninjection test content fromexample com toexample com with self assertraisesmessagebadheadererror msg email message with self assertraisesmessagebadheadererror msg emailmessage subject content fromexample com nameninjection test toexample com message def testspacecontinuationself email emailmessage long subject lines that get wrapped should contain a space continuation character to get expected behavior in outlook and thunderbird content fromexample com toexample com message email message self assertequal messagesubject encode blong subject lines that get wrapped should contain a space continuationn b character to get expected behavior in outlook and thunderbird def testmessageheaderoverridesself headers date fri 09 nov 2001 01 08 47 0000 messageid foo email emailmessage subject content fromexample com toexample com headersheaders self assertmessagehasheaders email message contenttransferencoding 7bit contenttype textplain charsetutf8 from fromexample com mimeversion 1 0 messageid foo subject subject to toexample com date fri 09 nov 2001 01 08 47 0000 def testfromheaderself email emailmessage subject content bounceexample com toexample com headersfrom fromexample com message email message self assertequalmessagefrom fromexample com def testtoheaderself email emailmessage subject content bounceexample com listsubscriberexample com listsubscriber2example com headersto mailinglistexample com message email message self assertequalmessageto mailinglistexample com self assertequal email to listsubscriberexample com listsubscriber2example com if we don t set the to header manually it should default to the to argument to the constructor email emailmessage subject content bounceexample com listsubscriberexample com listsubscriber2example com message email message self assertequal messageto listsubscriberexample com listsubscriber2example com self assertequal email to listsubscriberexample com listsubscriber2example com def testtoinheadersonlyself message emailmessage subject content bounceexample com headersto toexample com message self assertequalmessageto toexample com def testreplytoheaderself email emailmessage subject content bounceexample com toexample com replytofooexample com headersreplyto overrideexample com message email message self assertequalmessagereplyto overrideexample com def testreplytoinheadersonlyself message emailmessage subject content fromexample com toexample com headersreplyto replytoexample com message self assertequalmessagereplyto replytoexample com def testmultiplemessagecallself email emailmessage subject content bounceexample com toexample com headersfrom fromexample com message email message self assertequalmessagefrom fromexample com message email message self assertequalmessagefrom fromexample com def testunicodeaddressheaderself email emailmessage subject content fromexample com firstname srname toexample com otherexample com self assertequal email messageto utf8 q firstnamesc3bcrname toexample com otherexample com email emailmessage subject content fromexample com srname firstname toexample com otherexample com self assertequal email messageto utf8 q sc3bcrname2cfirstname toexample com otherexample com def testunicodeheadersself email emailmessage gegka content fromexample com toexample com headers sender firstname srname senderexample com comments my srname is nonascii message email message self assertequalmessagesubject utf8 b r8w8zwffvmozxyjryq self assertequal messagesender utf8 q firstnamesc3bcrname senderexample com self assertequal messagecomments utf8 q mysc3bcrnameisnonascii def testsafemimemultipartself headers date fri 09 nov 2001 01 08 47 0000 messageid foo fromemail to fromexample com srname firstname toexample com textcontent this is an important message htmlcontent pthis is an strongimportantstrong message p msg emailmultialternatives message from firstname srname textcontent fromemail to headersheaders msg attachalternativehtmlcontent texthtml msg encoding iso88591 self assertequal msg messageto iso88591 q sfcrname2cfirstname toexample com self assertequal msg messagesubject iso88591 q messagefromfirstnamesfcrname def testsafemimemultipartwithattachmentsself msg emailmultialternativesbody htmlcontent pthis is stronghtmlstrongp msg attachalternativehtmlcontent texthtml msg attachexample txt text file content textplain self assertinhtmlcontent msg message asstring def testnonebodyself msg emailmessagesubject none fromexample com toexample com self assertequalmsg body self assertequalmsg message getpayload mock patchsocket getfqdn returnvalue def testnonasciidnsnonunicodeemailself mockedgetfqdn delattrdnsname fqdn email emailmessage subject content fromexample com toexample com email encoding iso88591 self assertinxnp8s937b email messagemessageid def testencodingself email emailmessage subject firstname srname is a great guy fromexample com otherexample com email encoding iso88591 message email message self assertmessagehasheaders message mimeversion 1 0 contenttype textplain charsetiso88591 contenttransferencoding quotedprintable subject subject from fromexample com to otherexample com self assertequalmessage getpayload firstname sfcrname is a great guy mime attachments works correctly with other encodings than utf8 textcontent firstname srname is a great guy htmlcontent pfirstname srname is a stronggreatstrong guy p msg emailmultialternatives subject textcontent fromexample com toexample com msg encoding iso88591 msg attachalternativehtmlcontent texthtml payload0 msg message getpayload0 self assertmessagehasheaders payload0 mimeversion 1 0 contenttype textplain charsetiso88591 contenttransferencoding quotedprintable self asserttrue payload0 asbytes endswithbnnfirstname sfcrname is a great guy payload1 msg message getpayload1 self assertmessagehasheaders payload1 mimeversion 1 0 contenttype texthtml charsetiso88591 contenttransferencoding quotedprintable self asserttrue payload1 asbytes endswith bnnpfirstname sfcrname is a stronggreatstrong guy p def testattachmentsself regression test for 14964 headers date fri 09 nov 2001 01 08 47 0000 messageid foo subject fromemail to hello fromexample com toexample com content this is the message msg emailmessagesubject content fromemail to headersheaders unicode in file name msg attachune pice jointe pdf bpdf1 4 mimetypeapplicationpdf msgbytes msg message asbytes message messagefrombytesmsgbytes payload message getpayload self assertequalpayload1 getfilename une pice jointe pdf def testattachfileself files filename actual mimetype file txt textplain file png imagepng filetxt none filepng none filetxt png imagepng filepng txt textplain file eml messagerfc822 testmimetypes textplain imagepng none for basename realmimetype in files for mimetype in testmimetypes email emailmessage subject body fromexample com toexample com self assertequalmimetypes guesstypebasename0 realmimetype self assertequalemail attachments filepath os path join os path dirnamefile attachments basename email attachfilefilepath mimetypemimetype self assertequallenemail attachments 1 self assertinbasename email attachments0 msgssentnum email send self assertequalmsgssentnum 1 def testattachtextasbytesself msg emailmessagesubject body fromexample com toexample com msg attachfile txt bfile content sentnum msg send self assertequalsentnum 1 filename content mimetype self getdecodedattachmentsmsg0 self assertequalfilename file txt self assertequalcontent bfile content self assertequalmimetype textplain def testattachutf8textasbytesself msg emailmessagesubject body fromexample com toexample com msg attachfile txt bxc3xa4 utf8 encoded a umlaut filename content mimetype self getdecodedattachmentsmsg0 self assertequalfilename file txt self assertequalcontent bxc3xa4 self assertequalmimetype textplain def testattachnonutf8textasbytesself msg emailmessagesubject body fromexample com toexample com msg attachfile txt bxff invalid utf8 filename content mimetype self getdecodedattachmentsmsg0 self assertequalfilename file txt content should be passed through unmodified self assertequalcontent bxff self assertequalmimetype applicationoctetstream def testattachmimetextcontentmimetypeself emailmsg emailmessage txt mimetextcontent msg content and mimetype must not be given when a mimebase instance is provided with self assertraisesmessagevalueerror msg emailmsg attachtxt contentcontent with self assertraisesmessagevalueerror msg emailmsg attachtxt mimetypetextplain def testattachcontentnoneself emailmsg emailmessage msg content must be provided with self assertraisesmessagevalueerror msg emailmsg attachfile txt mimetypeapplicationpdf def testdummybackendself connection dummy emailbackend email emailmessage subject content bounceexample com toexample com headersfrom fromexample com self assertequalconnection sendmessagesemail email email 3 def testarbitrarykeywordself c mail getconnectionfailsilentlytrue foobar self asserttruec failsilently def testcustombackendself test backend argument of mail getconnection self assertisinstance mail getconnectiondjango core mail backends smtp emailbackend smtp emailbackend self assertisinstance mail getconnectiondjango core mail backends locmem emailbackend locmem emailbackend self assertisinstance mail getconnectiondjango core mail backends dummy emailbackend dummy emailbackend self assertisinstance mail getconnectiondjango core mail backends console emailbackend console emailbackend with tempfile temporarydirectory as tmpdir self assertisinstance mail getconnection django core mail backends filebased emailbackend filepathtmpdir filebased emailbackend if sys platform win32 and not py311 msg getfullpathname path should be string bytes or os pathlike not object else msg expected str bytes or os pathlike object not object with self assertraisesmessagetypeerror msg mail getconnection django core mail backends filebased emailbackend filepathobject self assertisinstancemail getconnection locmem emailbackend overridesettings emailbackenddjango core mail backends locmem emailbackend adminsnobody nobodyexample com managersnobody nobodyexample com def testconnectionargself send using nondefault connection regression for 13433 make sure that emailmessage doesn t mangle from in message body ticket 3472 shouldn t use base64 encoding at all ticket 11212 shouldn t use quoted printable should detect it can represent content with 7 bit data shouldn t use quoted printable should detect it can represent content with 8 bit data ticket 18967 shouldn t use base64 encoding for a child emailmessage attachment create a child message first now create a parent attach to parent as a string the child message header is not base64 encoded feature test try attaching email message object directly to the mail the child message header is not base64 encoded feature test try attaching django s emailmessage object directly to the mail the child message header is not base64 encoded a utf8 charset with a custom body encoding is respected body body with latin characters msg emailmessagesubject body bounceexample com toexample com encoding charset charsetutf8 encoding bodyencoding charset qp msg encoding encoding message msg message self assertmessagehasheaders message mimeversion 1 0 contenttype textplain charsetutf8 contenttransferencoding quotedprintable self assertequalmessage getpayload encoding bodyencodebody def testsanitizeaddressself ascii addresses ascii addresses with display names unicode addresses supported per rfc6532 unicode addresses with display names addresses with two signs addresses with long unicode display names address with long display name and unicode domain invalid address with two signs invalid address without the quotes other invalid addresses emailuselocaltimefalse creates a datetime in utc emailuselocaltimetrue creates a datetime in the local time zone tests for 12422 django smarts 247211212 with charset of utf8 text parts shouldn t pollute global email python package charset registry when django mail message is imported email line length is limited to 998 chars by the rfc 5322 section 2 1 1 message body containing longer lines are converted to quotedprintable to avoid having to insert newlines which could be hairy to do properly unencoded body length is 998 840 but 998 when utf8 encoded sendmessages may take a list or an iterator test sendmail without the htmlmessage regression test for adding htmlmessage parameter to sendmail test htmlmessage argument to sendmail sendmail subject content senderexample com nobodyexample com htmlmessagehtml content message self getthemessage self assertequalmessage getsubject subject self assertequalmessage getallto nobodyexample com self asserttruemessage ismultipart self assertequallenmessage getpayload 2 self assertequalmessage getpayload0 getpayload content self assertequalmessage getpayload0 getcontenttype textplain self assertequalmessage getpayload1 getpayload html content self assertequalmessage getpayload1 getcontenttype texthtml overridesettingsmanagersnobody nobodyexample com def testhtmlmailmanagersself test htmlmessage argument to mailadmins mailadminssubject content htmlmessagehtml content message self getthemessage self assertequalmessage getsubject django subject self assertequalmessage getallto nobodyexample com self asserttruemessage ismultipart self assertequallenmessage getpayload 2 self assertequalmessage getpayload0 getpayload content self assertequalmessage getpayload0 getcontenttype textplain self assertequalmessage getpayload1 getpayload html content self assertequalmessage getpayload1 getcontenttype texthtml overridesettings adminsnobody nobodyadminexample com managersnobody nobodymanagerexample com def testmanagerandadminmailprefixself mailmanagersgettextlazysubject content message self getthemessage self assertequalmessage getsubject django subject self flushmailbox mailadminsgettextlazysubject content message self getthemessage self assertequalmessage getsubject django subject overridesettingsadmins managers def testemptyadminsself mailadminshi there self assertequalself getmailboxcontent mailmanagershi there self assertequalself getmailboxcontent def testwrongadminsmanagersself tests testexample com testexample com testexample com otherexample com testexample com otherexample com for setting mailfunc in admins mailadmins managers mailmanagers msg the s setting must be a list of 2tuples setting for value in tests with self subtestsettingsetting valuevalue self settings setting value with self assertraisesmessagevalueerror msg mailfuncsubject content def testmessageccheaderself email emailmessage subject content fromexample com toexample com ccccexample com mail getconnection sendmessagesemail message self getthemessage self assertmessagehasheaders message mimeversion 1 0 contenttype textplain charsetutf8 contenttransferencoding 7bit subject subject from fromexample com to toexample com cc ccexample com self assertinndate message asstring def testidnsendself self asserttruesendmailsubject content from com to com message self getthemessage self assertequalmessage getsubject subject self assertequalmessage getfrom fromxn4ca9at com self assertequalmessage getto toxn4ca9at com self flushmailbox m emailmessage subject content from com to com cccc com m send message self getthemessage self assertequalmessage getsubject subject self assertequalmessage getfrom fromxn4ca9at com self assertequalmessage getto toxn4ca9at com self assertequalmessage getcc ccxn4ca9at com def testrecipientwithoutdomainself self asserttruesendmailsubject content tester django message self getthemessage self assertequalmessage getsubject subject self assertequalmessage getfrom tester self assertequalmessage getto django def testlazyaddressesself gettextlazy self asserttruesendmailsubject content tester django message self getthemessage self assertequalmessage getfrom tester self assertequalmessage getto django self flushmailbox m emailmessage subject content tester to1 to2 cccc1 cc2 bccbcc replytoreply self assertequalm recipients to1 to2 cc1 cc2 bcc m send message self getthemessage self assertequalmessage getfrom tester self assertequalmessage getto to1 to2 self assertequalmessage getcc cc1 cc2 self assertequalmessage getreplyto reply def testcloseconnectionself conn mail getconnectionusername password conn close def testuseascontextmanagerself opened false closed false conn mail getconnectionusername password def open opened0 true conn open open def close closed0 true conn close close with conn as sameconn self asserttrueopened0 self assertissameconn conn self assertfalseclosed0 self asserttrueclosed0 class locmembackendtestsbaseemailbackendtests simpletestcase emailbackend django core mail backends locmem emailbackend def getmailboxcontentself return m message for m in mail outbox def flushmailboxself mail outbox def teardownself super teardown mail outbox def testlocmemsharedmessagesself connection locmem emailbackend connection2 locmem emailbackend email emailmessage subject content bounceexample com toexample com headersfrom fromexample com connection sendmessagesemail connection2 sendmessagesemail self assertequallenmail outbox 2 def testvalidatemultilineheadersself ticket 18861 validate emails when using the locmem backend with self assertraisesbadheadererror sendmail subjectnmultiline content fromexample com toexample com def testoutboxnotmutatedaftersendself email emailmessage subjectcorrect subject bodytest body fromemailfromexample com totoexample com email send email subject other subject email to appendotherexample com self assertequalmail outbox0 subject correct subject self assertequalmail outbox0 to toexample com class filebackendtestsbaseemailbackendtests simpletestcase emailbackend django core mail backends filebased emailbackend def setupself super setup self tmpdir self mkdtemp self addcleanupshutil rmtree self tmpdir self settingsoverride overridesettingsemailfilepathself tmpdir self settingsoverride enable def teardownself self settingsoverride disable super teardown def mkdtempself return tempfile mkdtemp def flushmailboxself for filename in os listdirself tmpdir os unlinkos path joinself tmpdir filename def getmailboxcontentself messages for filename in os listdirself tmpdir with openos path joinself tmpdir filename rb as fp session fp read splitbn b 79 bn messages extendmessagefrombytesm for m in session if m return messages def testfilesessionsself the console backend can be pointed at an arbitrary stream according to the spec mailfrom does not necessarily match the from header this is the case where the local part isn t encoded so try to correct that find a free port opening the backend with non empty usernamepassword tries to authenticate against the smtp server open returns whether it opened a connection simulate an already open connection the connection s timeout value is none by default connection mail getconnectiondjango core mail backends smtp emailbackend self assertisnoneconnection timeout def testconnectiontimeoutcustomself 23063 rfccompliant messages are sent over smtp send smtp send try smtpmessages def mocksendself s smtpmessages appends return sendself s smtp send mocksend email emailmessage subject content fromexample com toexample com mail getconnection sendmessagesemail find the actual message msg none for i m in enumeratesmtpmessages if m 4 data msg smtpmessagesi 1 break self asserttruemsg msg msg decode the message only contains crlf and not combinations of crlf lf and cr msg msg replacern self assertnotinr msg self assertnotinn msg finally smtp send send def testsendmessagesafteropenfailedself backend smtp emailbackend simulate connection initialization success and a subsequent connection exception backend connection mock mockspecobject backend open lambda none email emailmessage subject content fromexample com toexample com self assertequalbackend sendmessagesemail 0 def testsendmessagesemptylistself backend smtp emailbackend backend connection mock mockspecobject self assertequalbackend sendmessages 0 def testsendmessageszerosentself smtp controller is stopped in setupclass closing the backend while the smtp server is stopped doesn t raise an exception a socket connection error is silenced with failsilentlytrue asserts that the message has all headers message can be an instance of an email message subclass or a string with the contents of an email message headers should be a set of header name header value tuples non backend specific tests encode the specified django core mail message emailmessage then decode it using python s email parser module and for each attachment of the message return a list of tuples with filename content mimetype empty strings in various recipient arguments are always stripped off the final recipient list regression test for 7722 test multiple cc with multiple to testing with bcc test for space continuation character in long ascii subject headers 7747 specifying dates or message ids in the extra headers overrides the default values 9233 make sure we can manually set the from header 9214 make sure we can manually set the to header 17444 if we don t set the to header manually it should default to the to argument to the constructor specifying reply to in headers should override reply_to regression for 13259 make sure that headers are not changed when calling emailmessage message regression for 11144 when a to from cc header contains unicode make sure the email addresses are parsed correctly especially with regards to commas make sure headers can be set with a different encoding than utf 8 in safemimemultipart as well emailmultialternatives includes alternatives if the body is empty and it has attachments regression for 12791 encode body correctly with other encodings than utf 8 mime attachments works correctly with other encodings than utf 8 regression test for 9367 regression test for 14964 unicode in file name test attaching a file against different mimetypes and make sure that a file will be attached and sent properly even if an invalid mimetype is specified filename actual mimetype non ascii characters encoded as valid utf 8 are correctly transported and decoded utf 8 encoded a umlaut binary data that can t be decoded as utf 8 overrides the mime type instead of decoding the data invalid utf 8 content should be passed through unmodified make sure that dummy backends returns correct number of sent messages make sure that get_connection accepts arbitrary keyword that might be used with custom backends test custom backend defined in this suite test backend argument of mail get_connection test connection argument to send_mail et al send using non default connection regression for 13433 make sure that emailmessage doesn t mangle from in message body ticket 3472 shouldn t use base64 encoding at all ticket 11212 shouldn t use quoted printable should detect it can represent content with 7 bit data shouldn t use quoted printable should detect it can represent content with 8 bit data ticket 18967 shouldn t use base64 encoding for a child emailmessage attachment create a child message first now create a parent attach to parent as a string the child message header is not base64 encoded feature test try attaching email message object directly to the mail the child message header is not base64 encoded feature test try attaching django s emailmessage object directly to the mail the child message header is not base64 encoded a utf 8 charset with a custom body encoding is respected email addresses are properly sanitized ascii addresses ascii addresses with display names unicode addresses supported per rfc 6532 unicode addresses with display names addresses with two signs addresses with long unicode display names address with long display name and unicode domain invalid address with two signs invalid address without the quotes other invalid addresses email_use_localtime false creates a datetime in utc email_use_localtime true creates a datetime in the local time zone africa algiers is utc 1 tests for 12422 django smarts 2472 11212 with charset of utf 8 text parts shouldn t pollute global email python package charset registry when django mail message is imported email line length is limited to 998 chars by the rfc 5322 section 2 1 1 message body containing longer lines are converted to quoted printable to avoid having to insert newlines which could be hairy to do properly unencoded body length is 998 840 but 998 when utf 8 encoded send_messages may take a list or an iterator test send_mail without the html_message regression test for adding html_message parameter to send_mail test html_message argument to send_mail test html_message argument to mail_managers test html_message argument to mail_admins string prefix lazy translated subject bad output regression for 13494 mail_admins mail_managers doesn t connect to the mail server if there are no recipients 9383 regression test for 7722 regression test for 14301 regression test for 15042 email sending should support lazy email addresses 24416 connection can be closed even when not explicitly opened the connection can be used as a contextmanager make sure that the locmen backend populates the outbox ticket 18861 validate emails when using the locmem backend make sure opening a connection creates a new file the console backend can be pointed at an arbitrary stream according to the spec mail_from does not necessarily match the from header this is the case where the local part isn t encoded so try to correct that find a free port opening the backend with non empty username password tries to authenticate against the smtp server open returns whether it opened a connection simulate an already open connection the connection s timeout value is none by default the timeout parameter can be customized 23063 rfc compliant messages are sent over smtp find the actual message the message only contains crlf and not combinations of crlf lf and cr send_messages shouldn t try to send messages if open raises an exception after initializing the connection simulate connection initialization success and a subsequent connection exception a message isn t sent if it doesn t have any recipients smtp controller is stopped in setupclass closing the backend while the smtp server is stopped doesn t raise an exception a socket connection error is silenced with fail_silently true
import mimetypes
import os
import shutil
import socket
import sys
import tempfile
from email import charset, message_from_binary_file, message_from_bytes
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr
from io import StringIO
from pathlib import Path
from smtplib import SMTP, SMTPException
from ssl import SSLError
from unittest import mock, skipUnless

from django.core import mail
from django.core.mail import (
    DNS_NAME,
    EmailMessage,
    EmailMultiAlternatives,
    mail_admins,
    mail_managers,
    send_mail,
    send_mass_mail,
)
from django.core.mail.backends import console, dummy, filebased, locmem, smtp
from django.core.mail.message import BadHeaderError, sanitize_address
from django.test import SimpleTestCase, override_settings
from django.test.utils import requires_tz_support
from django.utils.translation import gettext_lazy
from django.utils.version import PY311

try:
    from aiosmtpd.controller import Controller

    HAS_AIOSMTPD = True
except ImportError:
    HAS_AIOSMTPD = False


class HeadersCheckMixin:
    def assertMessageHasHeaders(self, message, headers):
        
        if isinstance(message, bytes):
            message = message_from_bytes(message)
        msg_headers = set(message.items())
        self.assertTrue(
            headers.issubset(msg_headers),
            msg="Message is missing "
            "the following headers: %s" % (headers - msg_headers),
        )


class MailTests(HeadersCheckMixin, SimpleTestCase):
    

    def get_decoded_attachments(self, django_message):
        
        msg_bytes = django_message.message().as_bytes()
        email_message = message_from_bytes(msg_bytes)

        def iter_attachments():
            for i in email_message.walk():
                if i.get_content_disposition() == "attachment":
                    filename = i.get_filename()
                    content = i.get_payload(decode=True)
                    mimetype = i.get_content_type()
                    yield filename, content, mimetype

        return list(iter_attachments())

    def test_ascii(self):
        email = EmailMessage(
            "Subject", "Content", "from@example.com", ["to@example.com"]
        )
        message = email.message()
        self.assertEqual(message["Subject"], "Subject")
        self.assertEqual(message.get_payload(), "Content")
        self.assertEqual(message["From"], "from@example.com")
        self.assertEqual(message["To"], "to@example.com")

    def test_multiple_recipients(self):
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com", "other@example.com"],
        )
        message = email.message()
        self.assertEqual(message["Subject"], "Subject")
        self.assertEqual(message.get_payload(), "Content")
        self.assertEqual(message["From"], "from@example.com")
        self.assertEqual(message["To"], "to@example.com, other@example.com")

    def test_header_omitted_for_no_to_recipients(self):
        message = EmailMessage(
            "Subject", "Content", "from@example.com", cc=["cc@example.com"]
        ).message()
        self.assertNotIn("To", message)

    def test_recipients_with_empty_strings(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com", ""],
            cc=["cc@example.com", ""],
            bcc=["", "bcc@example.com"],
            reply_to=["", None],
        )
        self.assertEqual(
            email.recipients(), ["to@example.com", "cc@example.com", "bcc@example.com"]
        )

    def test_cc(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            cc=["cc@example.com"],
        )
        message = email.message()
        self.assertEqual(message["Cc"], "cc@example.com")
        self.assertEqual(email.recipients(), ["to@example.com", "cc@example.com"])

        
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com", "other@example.com"],
            cc=["cc@example.com", "cc.other@example.com"],
        )
        message = email.message()
        self.assertEqual(message["Cc"], "cc@example.com, cc.other@example.com")
        self.assertEqual(
            email.recipients(),
            [
                "to@example.com",
                "other@example.com",
                "cc@example.com",
                "cc.other@example.com",
            ],
        )

        
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com", "other@example.com"],
            cc=["cc@example.com", "cc.other@example.com"],
            bcc=["bcc@example.com"],
        )
        message = email.message()
        self.assertEqual(message["Cc"], "cc@example.com, cc.other@example.com")
        self.assertEqual(
            email.recipients(),
            [
                "to@example.com",
                "other@example.com",
                "cc@example.com",
                "cc.other@example.com",
                "bcc@example.com",
            ],
        )

    def test_cc_headers(self):
        message = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            cc=["foo@example.com"],
            headers={"Cc": "override@example.com"},
        ).message()
        self.assertEqual(message["Cc"], "override@example.com")

    def test_cc_in_headers_only(self):
        message = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"Cc": "foo@example.com"},
        ).message()
        self.assertEqual(message["Cc"], "foo@example.com")

    def test_reply_to(self):
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            reply_to=["reply_to@example.com"],
        )
        message = email.message()
        self.assertEqual(message["Reply-To"], "reply_to@example.com")

        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            reply_to=["reply_to1@example.com", "reply_to2@example.com"],
        )
        message = email.message()
        self.assertEqual(
            message["Reply-To"], "reply_to1@example.com, reply_to2@example.com"
        )

    def test_recipients_as_tuple(self):
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ("to@example.com", "other@example.com"),
            cc=("cc@example.com", "cc.other@example.com"),
            bcc=("bcc@example.com",),
        )
        message = email.message()
        self.assertEqual(message["Cc"], "cc@example.com, cc.other@example.com")
        self.assertEqual(
            email.recipients(),
            [
                "to@example.com",
                "other@example.com",
                "cc@example.com",
                "cc.other@example.com",
                "bcc@example.com",
            ],
        )

    def test_recipients_as_string(self):
        with self.assertRaisesMessage(
            TypeError, '"to" argument must be a list or tuple'
        ):
            EmailMessage(to="foo@example.com")
        with self.assertRaisesMessage(
            TypeError, '"cc" argument must be a list or tuple'
        ):
            EmailMessage(cc="foo@example.com")
        with self.assertRaisesMessage(
            TypeError, '"bcc" argument must be a list or tuple'
        ):
            EmailMessage(bcc="foo@example.com")
        with self.assertRaisesMessage(
            TypeError, '"reply_to" argument must be a list or tuple'
        ):
            EmailMessage(reply_to="reply_to@example.com")

    def test_header_injection(self):
        msg = "Header values can't contain newlines "
        email = EmailMessage(
            "Subject\nInjection Test", "Content", "from@example.com", ["to@example.com"]
        )
        with self.assertRaisesMessage(BadHeaderError, msg):
            email.message()
        email = EmailMessage(
            gettext_lazy("Subject\nInjection Test"),
            "Content",
            "from@example.com",
            ["to@example.com"],
        )
        with self.assertRaisesMessage(BadHeaderError, msg):
            email.message()
        with self.assertRaisesMessage(BadHeaderError, msg):
            EmailMessage(
                "Subject",
                "Content",
                "from@example.com",
                ["Name\nInjection test <to@example.com>"],
            ).message()

    def test_space_continuation(self):
        
        email = EmailMessage(
            "Long subject lines that get wrapped should contain a space continuation "
            "character to get expected behavior in Outlook and Thunderbird",
            "Content",
            "from@example.com",
            ["to@example.com"],
        )
        message = email.message()
        self.assertEqual(
            message["Subject"].encode(),
            b"Long subject lines that get wrapped should contain a space continuation\n"
            b" character to get expected behavior in Outlook and Thunderbird",
        )

    def test_message_header_overrides(self):
        
        headers = {"date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
        email = EmailMessage(
            "subject",
            "content",
            "from@example.com",
            ["to@example.com"],
            headers=headers,
        )

        self.assertMessageHasHeaders(
            email.message(),
            {
                ("Content-Transfer-Encoding", "7bit"),
                ("Content-Type", 'text/plain; charset="utf-8"'),
                ("From", "from@example.com"),
                ("MIME-Version", "1.0"),
                ("Message-ID", "foo"),
                ("Subject", "subject"),
                ("To", "to@example.com"),
                ("date", "Fri, 09 Nov 2001 01:08:47 -0000"),
            },
        )

    def test_from_header(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        message = email.message()
        self.assertEqual(message["From"], "from@example.com")

    def test_to_header(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["list-subscriber@example.com", "list-subscriber2@example.com"],
            headers={"To": "mailing-list@example.com"},
        )
        message = email.message()
        self.assertEqual(message["To"], "mailing-list@example.com")
        self.assertEqual(
            email.to, ["list-subscriber@example.com", "list-subscriber2@example.com"]
        )

        
        
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["list-subscriber@example.com", "list-subscriber2@example.com"],
        )
        message = email.message()
        self.assertEqual(
            message["To"], "list-subscriber@example.com, list-subscriber2@example.com"
        )
        self.assertEqual(
            email.to, ["list-subscriber@example.com", "list-subscriber2@example.com"]
        )

    def test_to_in_headers_only(self):
        message = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            headers={"To": "to@example.com"},
        ).message()
        self.assertEqual(message["To"], "to@example.com")

    def test_reply_to_header(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            reply_to=["foo@example.com"],
            headers={"Reply-To": "override@example.com"},
        )
        message = email.message()
        self.assertEqual(message["Reply-To"], "override@example.com")

    def test_reply_to_in_headers_only(self):
        message = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            headers={"Reply-To": "reply_to@example.com"},
        ).message()
        self.assertEqual(message["Reply-To"], "reply_to@example.com")

    def test_multiple_message_call(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        message = email.message()
        self.assertEqual(message["From"], "from@example.com")
        message = email.message()
        self.assertEqual(message["From"], "from@example.com")

    def test_unicode_address_header(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ['"Firstname Sürname" <to@example.com>', "other@example.com"],
        )
        self.assertEqual(
            email.message()["To"],
            "=?utf-8?q?Firstname_S=C3=BCrname?= <to@example.com>, other@example.com",
        )
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ['"Sürname, Firstname" <to@example.com>', "other@example.com"],
        )
        self.assertEqual(
            email.message()["To"],
            "=?utf-8?q?S=C3=BCrname=2C_Firstname?= <to@example.com>, other@example.com",
        )

    def test_unicode_headers(self):
        email = EmailMessage(
            "Gżegżółka",
            "Content",
            "from@example.com",
            ["to@example.com"],
            headers={
                "Sender": '"Firstname Sürname" <sender@example.com>',
                "Comments": "My Sürname is non-ASCII",
            },
        )
        message = email.message()
        self.assertEqual(message["Subject"], "=?utf-8?b?R8W8ZWfFvMOzxYJrYQ==?=")
        self.assertEqual(
            message["Sender"], "=?utf-8?q?Firstname_S=C3=BCrname?= <sender@example.com>"
        )
        self.assertEqual(
            message["Comments"], "=?utf-8?q?My_S=C3=BCrname_is_non-ASCII?="
        )

    def test_safe_mime_multipart(self):
        
        headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
        from_email, to = "from@example.com", '"Sürname, Firstname" <to@example.com>'
        text_content = "This is an important message."
        html_content = "<p>This is an <strong>important</strong> message.</p>"
        msg = EmailMultiAlternatives(
            "Message from Firstname Sürname",
            text_content,
            from_email,
            [to],
            headers=headers,
        )
        msg.attach_alternative(html_content, "text/html")
        msg.encoding = "iso-8859-1"
        self.assertEqual(
            msg.message()["To"],
            "=?iso-8859-1?q?S=FCrname=2C_Firstname?= <to@example.com>",
        )
        self.assertEqual(
            msg.message()["Subject"],
            "=?iso-8859-1?q?Message_from_Firstname_S=FCrname?=",
        )

    def test_safe_mime_multipart_with_attachments(self):
        
        msg = EmailMultiAlternatives(body="")
        html_content = "<p>This is <strong>html</strong></p>"
        msg.attach_alternative(html_content, "text/html")
        msg.attach("example.txt", "Text file content", "text/plain")
        self.assertIn(html_content, msg.message().as_string())

    def test_none_body(self):
        msg = EmailMessage("subject", None, "from@example.com", ["to@example.com"])
        self.assertEqual(msg.body, "")
        self.assertEqual(msg.message().get_payload(), "")

    @mock.patch("socket.getfqdn", return_value="漢字")
    def test_non_ascii_dns_non_unicode_email(self, mocked_getfqdn):
        delattr(DNS_NAME, "_fqdn")
        email = EmailMessage(
            "subject", "content", "from@example.com", ["to@example.com"]
        )
        email.encoding = "iso-8859-1"
        self.assertIn("@xn--p8s937b>", email.message()["Message-ID"])

    def test_encoding(self):
        
        email = EmailMessage(
            "Subject",
            "Firstname Sürname is a great guy.",
            "from@example.com",
            ["other@example.com"],
        )
        email.encoding = "iso-8859-1"
        message = email.message()
        self.assertMessageHasHeaders(
            message,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/plain; charset="iso-8859-1"'),
                ("Content-Transfer-Encoding", "quoted-printable"),
                ("Subject", "Subject"),
                ("From", "from@example.com"),
                ("To", "other@example.com"),
            },
        )
        self.assertEqual(message.get_payload(), "Firstname S=FCrname is a great guy.")

        
        text_content = "Firstname Sürname is a great guy."
        html_content = "<p>Firstname Sürname is a <strong>great</strong> guy.</p>"
        msg = EmailMultiAlternatives(
            "Subject", text_content, "from@example.com", ["to@example.com"]
        )
        msg.encoding = "iso-8859-1"
        msg.attach_alternative(html_content, "text/html")
        payload0 = msg.message().get_payload(0)
        self.assertMessageHasHeaders(
            payload0,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/plain; charset="iso-8859-1"'),
                ("Content-Transfer-Encoding", "quoted-printable"),
            },
        )
        self.assertTrue(
            payload0.as_bytes().endswith(b"\n\nFirstname S=FCrname is a great guy.")
        )
        payload1 = msg.message().get_payload(1)
        self.assertMessageHasHeaders(
            payload1,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/html; charset="iso-8859-1"'),
                ("Content-Transfer-Encoding", "quoted-printable"),
            },
        )
        self.assertTrue(
            payload1.as_bytes().endswith(
                b"\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>"
            )
        )

    def test_attachments(self):
        
        headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
        subject, from_email, to = "hello", "from@example.com", "to@example.com"
        text_content = "This is an important message."
        html_content = "<p>This is an <strong>important</strong> message.</p>"
        msg = EmailMultiAlternatives(
            subject, text_content, from_email, [to], headers=headers
        )
        msg.attach_alternative(html_content, "text/html")
        msg.attach("an attachment.pdf", b"%PDF-1.4.%...", mimetype="application/pdf")
        msg_bytes = msg.message().as_bytes()
        message = message_from_bytes(msg_bytes)
        self.assertTrue(message.is_multipart())
        self.assertEqual(message.get_content_type(), "multipart/mixed")
        self.assertEqual(message.get_default_type(), "text/plain")
        payload = message.get_payload()
        self.assertEqual(payload[0].get_content_type(), "multipart/alternative")
        self.assertEqual(payload[1].get_content_type(), "application/pdf")

    def test_attachments_two_tuple(self):
        msg = EmailMessage(attachments=[("filename1", "content1")])
        filename, content, mimetype = self.get_decoded_attachments(msg)[0]
        self.assertEqual(filename, "filename1")
        self.assertEqual(content, b"content1")
        self.assertEqual(mimetype, "application/octet-stream")

    def test_attachments_MIMEText(self):
        txt = MIMEText("content1")
        msg = EmailMessage(attachments=[txt])
        payload = msg.message().get_payload()
        self.assertEqual(payload[0], txt)

    def test_non_ascii_attachment_filename(self):
        
        headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
        subject, from_email, to = "hello", "from@example.com", "to@example.com"
        content = "This is the message."
        msg = EmailMessage(subject, content, from_email, [to], headers=headers)
        
        msg.attach("une pièce jointe.pdf", b"%PDF-1.4.%...", mimetype="application/pdf")
        msg_bytes = msg.message().as_bytes()
        message = message_from_bytes(msg_bytes)
        payload = message.get_payload()
        self.assertEqual(payload[1].get_filename(), "une pièce jointe.pdf")

    def test_attach_file(self):
        
        files = (
            
            ("file.txt", "text/plain"),
            ("file.png", "image/png"),
            ("file_txt", None),
            ("file_png", None),
            ("file_txt.png", "image/png"),
            ("file_png.txt", "text/plain"),
            ("file.eml", "message/rfc822"),
        )
        test_mimetypes = ["text/plain", "image/png", None]

        for basename, real_mimetype in files:
            for mimetype in test_mimetypes:
                email = EmailMessage(
                    "subject", "body", "from@example.com", ["to@example.com"]
                )
                self.assertEqual(mimetypes.guess_type(basename)[0], real_mimetype)
                self.assertEqual(email.attachments, [])
                file_path = os.path.join(
                    os.path.dirname(__file__), "attachments", basename
                )
                email.attach_file(file_path, mimetype=mimetype)
                self.assertEqual(len(email.attachments), 1)
                self.assertIn(basename, email.attachments[0])
                msgs_sent_num = email.send()
                self.assertEqual(msgs_sent_num, 1)

    def test_attach_text_as_bytes(self):
        msg = EmailMessage("subject", "body", "from@example.com", ["to@example.com"])
        msg.attach("file.txt", b"file content")
        sent_num = msg.send()
        self.assertEqual(sent_num, 1)
        filename, content, mimetype = self.get_decoded_attachments(msg)[0]
        self.assertEqual(filename, "file.txt")
        self.assertEqual(content, b"file content")
        self.assertEqual(mimetype, "text/plain")

    def test_attach_utf8_text_as_bytes(self):
        
        msg = EmailMessage("subject", "body", "from@example.com", ["to@example.com"])
        msg.attach("file.txt", b"\xc3\xa4")  
        filename, content, mimetype = self.get_decoded_attachments(msg)[0]
        self.assertEqual(filename, "file.txt")
        self.assertEqual(content, b"\xc3\xa4")
        self.assertEqual(mimetype, "text/plain")

    def test_attach_non_utf8_text_as_bytes(self):
        
        msg = EmailMessage("subject", "body", "from@example.com", ["to@example.com"])
        msg.attach("file.txt", b"\xff")  
        filename, content, mimetype = self.get_decoded_attachments(msg)[0]
        self.assertEqual(filename, "file.txt")
        
        self.assertEqual(content, b"\xff")
        self.assertEqual(mimetype, "application/octet-stream")

    def test_attach_mimetext_content_mimetype(self):
        email_msg = EmailMessage()
        txt = MIMEText("content")
        msg = (
            "content and mimetype must not be given when a MIMEBase instance "
            "is provided."
        )
        with self.assertRaisesMessage(ValueError, msg):
            email_msg.attach(txt, content="content")
        with self.assertRaisesMessage(ValueError, msg):
            email_msg.attach(txt, mimetype="text/plain")

    def test_attach_content_none(self):
        email_msg = EmailMessage()
        msg = "content must be provided."
        with self.assertRaisesMessage(ValueError, msg):
            email_msg.attach("file.txt", mimetype="application/pdf")

    def test_dummy_backend(self):
        
        connection = dummy.EmailBackend()
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        self.assertEqual(connection.send_messages([email, email, email]), 3)

    def test_arbitrary_keyword(self):
        
        c = mail.get_connection(fail_silently=True, foo="bar")
        self.assertTrue(c.fail_silently)

    def test_custom_backend(self):
        
        conn = mail.get_connection("mail.custombackend.EmailBackend")
        self.assertTrue(hasattr(conn, "test_outbox"))
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        conn.send_messages([email])
        self.assertEqual(len(conn.test_outbox), 1)

    def test_backend_arg(self):
        
        self.assertIsInstance(
            mail.get_connection("django.core.mail.backends.smtp.EmailBackend"),
            smtp.EmailBackend,
        )
        self.assertIsInstance(
            mail.get_connection("django.core.mail.backends.locmem.EmailBackend"),
            locmem.EmailBackend,
        )
        self.assertIsInstance(
            mail.get_connection("django.core.mail.backends.dummy.EmailBackend"),
            dummy.EmailBackend,
        )
        self.assertIsInstance(
            mail.get_connection("django.core.mail.backends.console.EmailBackend"),
            console.EmailBackend,
        )
        with tempfile.TemporaryDirectory() as tmp_dir:
            self.assertIsInstance(
                mail.get_connection(
                    "django.core.mail.backends.filebased.EmailBackend",
                    file_path=tmp_dir,
                ),
                filebased.EmailBackend,
            )

        if sys.platform == "win32" and not PY311:
            msg = (
                "_getfullpathname: path should be string, bytes or os.PathLike, not "
                "object"
            )
        else:
            msg = "expected str, bytes or os.PathLike object, not object"
        with self.assertRaisesMessage(TypeError, msg):
            mail.get_connection(
                "django.core.mail.backends.filebased.EmailBackend", file_path=object()
            )
        self.assertIsInstance(mail.get_connection(), locmem.EmailBackend)

    @override_settings(
        EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend",
        ADMINS=[("nobody", "nobody@example.com")],
        MANAGERS=[("nobody", "nobody@example.com")],
    )
    def test_connection_arg(self):
        
        mail.outbox = []

        
        connection = mail.get_connection("mail.custombackend.EmailBackend")
        send_mail(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            connection=connection,
        )
        self.assertEqual(mail.outbox, [])
        self.assertEqual(len(connection.test_outbox), 1)
        self.assertEqual(connection.test_outbox[0].subject, "Subject")

        connection = mail.get_connection("mail.custombackend.EmailBackend")
        send_mass_mail(
            [
                ("Subject1", "Content1", "from1@example.com", ["to1@example.com"]),
                ("Subject2", "Content2", "from2@example.com", ["to2@example.com"]),
            ],
            connection=connection,
        )
        self.assertEqual(mail.outbox, [])
        self.assertEqual(len(connection.test_outbox), 2)
        self.assertEqual(connection.test_outbox[0].subject, "Subject1")
        self.assertEqual(connection.test_outbox[1].subject, "Subject2")

        connection = mail.get_connection("mail.custombackend.EmailBackend")
        mail_admins("Admin message", "Content", connection=connection)
        self.assertEqual(mail.outbox, [])
        self.assertEqual(len(connection.test_outbox), 1)
        self.assertEqual(connection.test_outbox[0].subject, "[Django] Admin message")

        connection = mail.get_connection("mail.custombackend.EmailBackend")
        mail_managers("Manager message", "Content", connection=connection)
        self.assertEqual(mail.outbox, [])
        self.assertEqual(len(connection.test_outbox), 1)
        self.assertEqual(connection.test_outbox[0].subject, "[Django] Manager message")

    def test_dont_mangle_from_in_body(self):
        
        
        email = EmailMessage(
            "Subject",
            "From the future",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        self.assertNotIn(b">From the future", email.message().as_bytes())

    def test_dont_base64_encode(self):
        
        
        msg = EmailMessage(
            "Subject",
            "UTF-8 encoded body",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        self.assertIn(b"Content-Transfer-Encoding: 7bit", msg.message().as_bytes())

        
        
        
        msg = EmailMessage(
            "Subject",
            "Body with only ASCII characters.",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        s = msg.message().as_bytes()
        self.assertIn(b"Content-Transfer-Encoding: 7bit", s)

        
        
        msg = EmailMessage(
            "Subject",
            "Body with latin characters: àáä.",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        s = msg.message().as_bytes()
        self.assertIn(b"Content-Transfer-Encoding: 8bit", s)
        s = msg.message().as_string()
        self.assertIn("Content-Transfer-Encoding: 8bit", s)

        msg = EmailMessage(
            "Subject",
            "Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        s = msg.message().as_bytes()
        self.assertIn(b"Content-Transfer-Encoding: 8bit", s)
        s = msg.message().as_string()
        self.assertIn("Content-Transfer-Encoding: 8bit", s)

    def test_dont_base64_encode_message_rfc822(self):
        
        
        
        child_msg = EmailMessage(
            "Child Subject",
            "Some body of child message",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        child_s = child_msg.message().as_string()

        
        parent_msg = EmailMessage(
            "Parent Subject",
            "Some parent body",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )

        
        parent_msg.attach(content=child_s, mimetype="message/rfc822")
        parent_s = parent_msg.message().as_string()

        
        self.assertIn("Child Subject", parent_s)

        
        parent_msg = EmailMessage(
            "Parent Subject",
            "Some parent body",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        parent_msg.attach(content=child_msg.message(), mimetype="message/rfc822")
        parent_s = parent_msg.message().as_string()

        
        self.assertIn("Child Subject", parent_s)

        
        parent_msg = EmailMessage(
            "Parent Subject",
            "Some parent body",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        parent_msg.attach(content=child_msg, mimetype="message/rfc822")
        parent_s = parent_msg.message().as_string()

        
        self.assertIn("Child Subject", parent_s)

    def test_custom_utf8_encoding(self):
        
        body = "Body with latin characters: àáä."
        msg = EmailMessage("Subject", body, "bounce@example.com", ["to@example.com"])
        encoding = charset.Charset("utf-8")
        encoding.body_encoding = charset.QP
        msg.encoding = encoding
        message = msg.message()
        self.assertMessageHasHeaders(
            message,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/plain; charset="utf-8"'),
                ("Content-Transfer-Encoding", "quoted-printable"),
            },
        )
        self.assertEqual(message.get_payload(), encoding.body_encode(body))

    def test_sanitize_address(self):
        
        for email_address, encoding, expected_result in (
            
            ("to@example.com", "ascii", "to@example.com"),
            ("to@example.com", "utf-8", "to@example.com"),
            (("A name", "to@example.com"), "ascii", "A name <to@example.com>"),
            (
                ("A name", "to@example.com"),
                "utf-8",
                "A name <to@example.com>",
            ),
            ("localpartonly", "ascii", "localpartonly"),
            
            ("A name <to@example.com>", "ascii", "A name <to@example.com>"),
            ("A name <to@example.com>", "utf-8", "A name <to@example.com>"),
            ('"A name" <to@example.com>', "ascii", "A name <to@example.com>"),
            ('"A name" <to@example.com>', "utf-8", "A name <to@example.com>"),
            
            ("tó@example.com", "utf-8", "=?utf-8?b?dMOz?=@example.com"),
            ("to@éxample.com", "utf-8", "to@xn--xample-9ua.com"),
            (
                ("Tó Example", "tó@example.com"),
                "utf-8",
                "=?utf-8?q?T=C3=B3_Example?= <=?utf-8?b?dMOz?=@example.com>",
            ),
            
            (
                "Tó Example <tó@example.com>",
                "utf-8",
                "=?utf-8?q?T=C3=B3_Example?= <=?utf-8?b?dMOz?=@example.com>",
            ),
            (
                "To Example <to@éxample.com>",
                "ascii",
                "To Example <to@xn--xample-9ua.com>",
            ),
            (
                "To Example <to@éxample.com>",
                "utf-8",
                "To Example <to@xn--xample-9ua.com>",
            ),
            
            ('"to@other.com"@example.com', "utf-8", r'"to@other.com"@example.com'),
            (
                '"to@other.com" <to@example.com>',
                "utf-8",
                '"to@other.com" <to@example.com>',
            ),
            (
                ("To Example", "to@other.com@example.com"),
                "utf-8",
                'To Example <"to@other.com"@example.com>',
            ),
            
            (
                "Tó Example very long" * 4 + " <to@example.com>",
                "utf-8",
                "=?utf-8?q?T=C3=B3_Example_very_longT=C3=B3_Example_very_longT"
                "=C3=B3_Example_?=\n"
                " =?utf-8?q?very_longT=C3=B3_Example_very_long?= "
                "<to@example.com>",
            ),
            (
                ("Tó Example very long" * 4, "to@example.com"),
                "utf-8",
                "=?utf-8?q?T=C3=B3_Example_very_longT=C3=B3_Example_very_longT"
                "=C3=B3_Example_?=\n"
                " =?utf-8?q?very_longT=C3=B3_Example_very_long?= "
                "<to@example.com>",
            ),
            
            (
                ("To Example very long" * 4, "to@exampl€.com"),
                "utf-8",
                "To Example very longTo Example very longTo Example very longT"
                "o Example very\n"
                " long <to@xn--exampl-nc1c.com>",
            ),
        ):
            with self.subTest(email_address=email_address, encoding=encoding):
                self.assertEqual(
                    sanitize_address(email_address, encoding), expected_result
                )

    def test_sanitize_address_invalid(self):
        for email_address in (
            
            "to@other.com@example.com",
            
            "to@other.com <to@example.com>",
            
            "@",
            "to@",
            "@example.com",
            ("", ""),
        ):
            with self.subTest(email_address=email_address):
                with self.assertRaisesMessage(ValueError, "Invalid address"):
                    sanitize_address(email_address, encoding="utf-8")

    def test_sanitize_address_header_injection(self):
        msg = "Invalid address; address parts cannot contain newlines."
        tests = [
            "Name\nInjection <to@example.com>",
            ("Name\nInjection", "to@xample.com"),
            "Name <to\ninjection@example.com>",
            ("Name", "to\ninjection@example.com"),
        ]
        for email_address in tests:
            with self.subTest(email_address=email_address):
                with self.assertRaisesMessage(ValueError, msg):
                    sanitize_address(email_address, encoding="utf-8")

    def test_email_multi_alternatives_content_mimetype_none(self):
        email_msg = EmailMultiAlternatives()
        msg = "Both content and mimetype must be provided."
        with self.assertRaisesMessage(ValueError, msg):
            email_msg.attach_alternative(None, "text/html")
        with self.assertRaisesMessage(ValueError, msg):
            email_msg.attach_alternative("<p>content</p>", None)


@requires_tz_support
class MailTimeZoneTests(SimpleTestCase):
    @override_settings(
        EMAIL_USE_LOCALTIME=False, USE_TZ=True, TIME_ZONE="Africa/Algiers"
    )
    def test_date_header_utc(self):
        
        email = EmailMessage(
            "Subject", "Body", "bounce@example.com", ["to@example.com"]
        )
        self.assertTrue(email.message()["Date"].endswith("-0000"))

    @override_settings(
        EMAIL_USE_LOCALTIME=True, USE_TZ=True, TIME_ZONE="Africa/Algiers"
    )
    def test_date_header_localtime(self):
        
        email = EmailMessage(
            "Subject", "Body", "bounce@example.com", ["to@example.com"]
        )
        self.assertTrue(
            email.message()["Date"].endswith("+0100")
        )  


class PythonGlobalState(SimpleTestCase):
    

    def test_utf8(self):
        txt = MIMEText("UTF-8 encoded body", "plain", "utf-8")
        self.assertIn("Content-Transfer-Encoding: base64", txt.as_string())

    def test_7bit(self):
        txt = MIMEText("Body with only ASCII characters.", "plain", "utf-8")
        self.assertIn("Content-Transfer-Encoding: base64", txt.as_string())

    def test_8bit_latin(self):
        txt = MIMEText("Body with latin characters: àáä.", "plain", "utf-8")
        self.assertIn("Content-Transfer-Encoding: base64", txt.as_string())

    def test_8bit_non_latin(self):
        txt = MIMEText(
            "Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.",
            "plain",
            "utf-8",
        )
        self.assertIn("Content-Transfer-Encoding: base64", txt.as_string())


class BaseEmailBackendTests(HeadersCheckMixin):
    email_backend = None

    def setUp(self):
        self.settings_override = override_settings(EMAIL_BACKEND=self.email_backend)
        self.settings_override.enable()

    def tearDown(self):
        self.settings_override.disable()

    def assertStartsWith(self, first, second):
        if not first.startswith(second):
            self.longMessage = True
            self.assertEqual(
                first[: len(second)],
                second,
                "First string doesn't start with the second.",
            )

    def get_mailbox_content(self):
        raise NotImplementedError(
            "subclasses of BaseEmailBackendTests must provide a get_mailbox_content() "
            "method"
        )

    def flush_mailbox(self):
        raise NotImplementedError(
            "subclasses of BaseEmailBackendTests may require a flush_mailbox() method"
        )

    def get_the_message(self):
        mailbox = self.get_mailbox_content()
        self.assertEqual(
            len(mailbox),
            1,
            "Expected exactly one message, got %d.\n%r"
            % (len(mailbox), [m.as_string() for m in mailbox]),
        )
        return mailbox[0]

    def test_send(self):
        email = EmailMessage(
            "Subject", "Content", "from@example.com", ["to@example.com"]
        )
        num_sent = mail.get_connection().send_messages([email])
        self.assertEqual(num_sent, 1)
        message = self.get_the_message()
        self.assertEqual(message["subject"], "Subject")
        self.assertEqual(message.get_payload(), "Content")
        self.assertEqual(message["from"], "from@example.com")
        self.assertEqual(message.get_all("to"), ["to@example.com"])

    def test_send_unicode(self):
        email = EmailMessage(
            "Chère maman", "Je t'aime très fort", "from@example.com", ["to@example.com"]
        )
        num_sent = mail.get_connection().send_messages([email])
        self.assertEqual(num_sent, 1)
        message = self.get_the_message()
        self.assertEqual(message["subject"], "=?utf-8?q?Ch=C3=A8re_maman?=")
        self.assertEqual(
            message.get_payload(decode=True).decode(), "Je t'aime très fort"
        )

    def test_send_long_lines(self):
        
        
        email = EmailMessage(
            "Subject", "В южных морях " * 60, "from@example.com", ["to@example.com"]
        )
        email.send()
        message = self.get_the_message()
        self.assertMessageHasHeaders(
            message,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/plain; charset="utf-8"'),
                ("Content-Transfer-Encoding", "quoted-printable"),
            },
        )

    def test_send_many(self):
        email1 = EmailMessage(
            "Subject", "Content1", "from@example.com", ["to@example.com"]
        )
        email2 = EmailMessage(
            "Subject", "Content2", "from@example.com", ["to@example.com"]
        )
        
        emails_lists = ([email1, email2], iter((email1, email2)))
        for emails_list in emails_lists:
            num_sent = mail.get_connection().send_messages(emails_list)
            self.assertEqual(num_sent, 2)
            messages = self.get_mailbox_content()
            self.assertEqual(len(messages), 2)
            self.assertEqual(messages[0].get_payload(), "Content1")
            self.assertEqual(messages[1].get_payload(), "Content2")
            self.flush_mailbox()

    def test_send_verbose_name(self):
        email = EmailMessage(
            "Subject",
            "Content",
            '"Firstname Sürname" <from@example.com>',
            ["to@example.com"],
        )
        email.send()
        message = self.get_the_message()
        self.assertEqual(message["subject"], "Subject")
        self.assertEqual(message.get_payload(), "Content")
        self.assertEqual(
            message["from"], "=?utf-8?q?Firstname_S=C3=BCrname?= <from@example.com>"
        )

    def test_plaintext_send_mail(self):
        
        send_mail("Subject", "Content", "sender@example.com", ["nobody@example.com"])
        message = self.get_the_message()

        self.assertEqual(message.get("subject"), "Subject")
        self.assertEqual(message.get_all("to"), ["nobody@example.com"])
        self.assertFalse(message.is_multipart())
        self.assertEqual(message.get_payload(), "Content")
        self.assertEqual(message.get_content_type(), "text/plain")

    def test_html_send_mail(self):
        
        send_mail(
            "Subject",
            "Content",
            "sender@example.com",
            ["nobody@example.com"],
            html_message="HTML Content",
        )
        message = self.get_the_message()

        self.assertEqual(message.get("subject"), "Subject")
        self.assertEqual(message.get_all("to"), ["nobody@example.com"])
        self.assertTrue(message.is_multipart())
        self.assertEqual(len(message.get_payload()), 2)
        self.assertEqual(message.get_payload(0).get_payload(), "Content")
        self.assertEqual(message.get_payload(0).get_content_type(), "text/plain")
        self.assertEqual(message.get_payload(1).get_payload(), "HTML Content")
        self.assertEqual(message.get_payload(1).get_content_type(), "text/html")

    @override_settings(MANAGERS=[("nobody", "nobody@example.com")])
    def test_html_mail_managers(self):
        
        mail_managers("Subject", "Content", html_message="HTML Content")
        message = self.get_the_message()

        self.assertEqual(message.get("subject"), "[Django] Subject")
        self.assertEqual(message.get_all("to"), ["nobody@example.com"])
        self.assertTrue(message.is_multipart())
        self.assertEqual(len(message.get_payload()), 2)
        self.assertEqual(message.get_payload(0).get_payload(), "Content")
        self.assertEqual(message.get_payload(0).get_content_type(), "text/plain")
        self.assertEqual(message.get_payload(1).get_payload(), "HTML Content")
        self.assertEqual(message.get_payload(1).get_content_type(), "text/html")

    @override_settings(ADMINS=[("nobody", "nobody@example.com")])
    def test_html_mail_admins(self):
        
        mail_admins("Subject", "Content", html_message="HTML Content")
        message = self.get_the_message()

        self.assertEqual(message.get("subject"), "[Django] Subject")
        self.assertEqual(message.get_all("to"), ["nobody@example.com"])
        self.assertTrue(message.is_multipart())
        self.assertEqual(len(message.get_payload()), 2)
        self.assertEqual(message.get_payload(0).get_payload(), "Content")
        self.assertEqual(message.get_payload(0).get_content_type(), "text/plain")
        self.assertEqual(message.get_payload(1).get_payload(), "HTML Content")
        self.assertEqual(message.get_payload(1).get_content_type(), "text/html")

    @override_settings(
        ADMINS=[("nobody", "nobody+admin@example.com")],
        MANAGERS=[("nobody", "nobody+manager@example.com")],
    )
    def test_manager_and_admin_mail_prefix(self):
        
        mail_managers(gettext_lazy("Subject"), "Content")
        message = self.get_the_message()
        self.assertEqual(message.get("subject"), "[Django] Subject")

        self.flush_mailbox()
        mail_admins(gettext_lazy("Subject"), "Content")
        message = self.get_the_message()
        self.assertEqual(message.get("subject"), "[Django] Subject")

    @override_settings(ADMINS=[], MANAGERS=[])
    def test_empty_admins(self):
        
        mail_admins("hi", "there")
        self.assertEqual(self.get_mailbox_content(), [])
        mail_managers("hi", "there")
        self.assertEqual(self.get_mailbox_content(), [])

    def test_wrong_admins_managers(self):
        tests = (
            "test@example.com",
            ("test@example.com",),
            ["test@example.com", "other@example.com"],
            ("test@example.com", "other@example.com"),
        )
        for setting, mail_func in (
            ("ADMINS", mail_admins),
            ("MANAGERS", mail_managers),
        ):
            msg = "The %s setting must be a list of 2-tuples." % setting
            for value in tests:
                with self.subTest(setting=setting, value=value), self.settings(
                    **{setting: value}
                ):
                    with self.assertRaisesMessage(ValueError, msg):
                        mail_func("subject", "content")

    def test_message_cc_header(self):
        
        email = EmailMessage(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            cc=["cc@example.com"],
        )
        mail.get_connection().send_messages([email])
        message = self.get_the_message()
        self.assertMessageHasHeaders(
            message,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/plain; charset="utf-8"'),
                ("Content-Transfer-Encoding", "7bit"),
                ("Subject", "Subject"),
                ("From", "from@example.com"),
                ("To", "to@example.com"),
                ("Cc", "cc@example.com"),
            },
        )
        self.assertIn("\nDate: ", message.as_string())

    def test_idn_send(self):
        
        self.assertTrue(send_mail("Subject", "Content", "from@öäü.com", ["to@öäü.com"]))
        message = self.get_the_message()
        self.assertEqual(message.get("subject"), "Subject")
        self.assertEqual(message.get("from"), "from@xn--4ca9at.com")
        self.assertEqual(message.get("to"), "to@xn--4ca9at.com")

        self.flush_mailbox()
        m = EmailMessage(
            "Subject", "Content", "from@öäü.com", ["to@öäü.com"], cc=["cc@öäü.com"]
        )
        m.send()
        message = self.get_the_message()
        self.assertEqual(message.get("subject"), "Subject")
        self.assertEqual(message.get("from"), "from@xn--4ca9at.com")
        self.assertEqual(message.get("to"), "to@xn--4ca9at.com")
        self.assertEqual(message.get("cc"), "cc@xn--4ca9at.com")

    def test_recipient_without_domain(self):
        
        self.assertTrue(send_mail("Subject", "Content", "tester", ["django"]))
        message = self.get_the_message()
        self.assertEqual(message.get("subject"), "Subject")
        self.assertEqual(message.get("from"), "tester")
        self.assertEqual(message.get("to"), "django")

    def test_lazy_addresses(self):
        
        _ = gettext_lazy
        self.assertTrue(send_mail("Subject", "Content", _("tester"), [_("django")]))
        message = self.get_the_message()
        self.assertEqual(message.get("from"), "tester")
        self.assertEqual(message.get("to"), "django")

        self.flush_mailbox()
        m = EmailMessage(
            "Subject",
            "Content",
            _("tester"),
            [_("to1"), _("to2")],
            cc=[_("cc1"), _("cc2")],
            bcc=[_("bcc")],
            reply_to=[_("reply")],
        )
        self.assertEqual(m.recipients(), ["to1", "to2", "cc1", "cc2", "bcc"])
        m.send()
        message = self.get_the_message()
        self.assertEqual(message.get("from"), "tester")
        self.assertEqual(message.get("to"), "to1, to2")
        self.assertEqual(message.get("cc"), "cc1, cc2")
        self.assertEqual(message.get("Reply-To"), "reply")

    def test_close_connection(self):
        
        conn = mail.get_connection(username="", password="")
        conn.close()

    def test_use_as_contextmanager(self):
        
        opened = [False]
        closed = [False]
        conn = mail.get_connection(username="", password="")

        def open():
            opened[0] = True

        conn.open = open

        def close():
            closed[0] = True

        conn.close = close
        with conn as same_conn:
            self.assertTrue(opened[0])
            self.assertIs(same_conn, conn)
            self.assertFalse(closed[0])
        self.assertTrue(closed[0])


class LocmemBackendTests(BaseEmailBackendTests, SimpleTestCase):
    email_backend = "django.core.mail.backends.locmem.EmailBackend"

    def get_mailbox_content(self):
        return [m.message() for m in mail.outbox]

    def flush_mailbox(self):
        mail.outbox = []

    def tearDown(self):
        super().tearDown()
        mail.outbox = []

    def test_locmem_shared_messages(self):
        
        connection = locmem.EmailBackend()
        connection2 = locmem.EmailBackend()
        email = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        connection.send_messages([email])
        connection2.send_messages([email])
        self.assertEqual(len(mail.outbox), 2)

    def test_validate_multiline_headers(self):
        
        with self.assertRaises(BadHeaderError):
            send_mail(
                "Subject\nMultiline", "Content", "from@example.com", ["to@example.com"]
            )

    def test_outbox_not_mutated_after_send(self):
        email = EmailMessage(
            subject="correct subject",
            body="test body",
            from_email="from@example.com",
            to=["to@example.com"],
        )
        email.send()
        email.subject = "other subject"
        email.to.append("other@example.com")
        self.assertEqual(mail.outbox[0].subject, "correct subject")
        self.assertEqual(mail.outbox[0].to, ["to@example.com"])


class FileBackendTests(BaseEmailBackendTests, SimpleTestCase):
    email_backend = "django.core.mail.backends.filebased.EmailBackend"

    def setUp(self):
        super().setUp()
        self.tmp_dir = self.mkdtemp()
        self.addCleanup(shutil.rmtree, self.tmp_dir)
        self._settings_override = override_settings(EMAIL_FILE_PATH=self.tmp_dir)
        self._settings_override.enable()

    def tearDown(self):
        self._settings_override.disable()
        super().tearDown()

    def mkdtemp(self):
        return tempfile.mkdtemp()

    def flush_mailbox(self):
        for filename in os.listdir(self.tmp_dir):
            os.unlink(os.path.join(self.tmp_dir, filename))

    def get_mailbox_content(self):
        messages = []
        for filename in os.listdir(self.tmp_dir):
            with open(os.path.join(self.tmp_dir, filename), "rb") as fp:
                session = fp.read().split(b"\n" + (b"-" * 79) + b"\n")
            messages.extend(message_from_bytes(m) for m in session if m)
        return messages

    def test_file_sessions(self):
        
        msg = EmailMessage(
            "Subject",
            "Content",
            "bounce@example.com",
            ["to@example.com"],
            headers={"From": "from@example.com"},
        )
        connection = mail.get_connection()
        connection.send_messages([msg])

        self.assertEqual(len(os.listdir(self.tmp_dir)), 1)
        with open(os.path.join(self.tmp_dir, os.listdir(self.tmp_dir)[0]), "rb") as fp:
            message = message_from_binary_file(fp)
        self.assertEqual(message.get_content_type(), "text/plain")
        self.assertEqual(message.get("subject"), "Subject")
        self.assertEqual(message.get("from"), "from@example.com")
        self.assertEqual(message.get("to"), "to@example.com")

        connection2 = mail.get_connection()
        connection2.send_messages([msg])
        self.assertEqual(len(os.listdir(self.tmp_dir)), 2)

        connection.send_messages([msg])
        self.assertEqual(len(os.listdir(self.tmp_dir)), 2)

        msg.connection = mail.get_connection()
        self.assertTrue(connection.open())
        msg.send()
        self.assertEqual(len(os.listdir(self.tmp_dir)), 3)
        msg.send()
        self.assertEqual(len(os.listdir(self.tmp_dir)), 3)

        connection.close()


class FileBackendPathLibTests(FileBackendTests):
    def mkdtemp(self):
        tmp_dir = super().mkdtemp()
        return Path(tmp_dir)


class ConsoleBackendTests(BaseEmailBackendTests, SimpleTestCase):
    email_backend = "django.core.mail.backends.console.EmailBackend"

    def setUp(self):
        super().setUp()
        self.__stdout = sys.stdout
        self.stream = sys.stdout = StringIO()

    def tearDown(self):
        del self.stream
        sys.stdout = self.__stdout
        del self.__stdout
        super().tearDown()

    def flush_mailbox(self):
        self.stream = sys.stdout = StringIO()

    def get_mailbox_content(self):
        messages = self.stream.getvalue().split("\n" + ("-" * 79) + "\n")
        return [message_from_bytes(m.encode()) for m in messages if m]

    def test_console_stream_kwarg(self):
        
        s = StringIO()
        connection = mail.get_connection(
            "django.core.mail.backends.console.EmailBackend", stream=s
        )
        send_mail(
            "Subject",
            "Content",
            "from@example.com",
            ["to@example.com"],
            connection=connection,
        )
        message = s.getvalue().split("\n" + ("-" * 79) + "\n")[0].encode()
        self.assertMessageHasHeaders(
            message,
            {
                ("MIME-Version", "1.0"),
                ("Content-Type", 'text/plain; charset="utf-8"'),
                ("Content-Transfer-Encoding", "7bit"),
                ("Subject", "Subject"),
                ("From", "from@example.com"),
                ("To", "to@example.com"),
            },
        )
        self.assertIn(b"\nDate: ", message)


class SMTPHandler:
    def __init__(self, *args, **kwargs):
        self.mailbox = []

    async def handle_DATA(self, server, session, envelope):
        data = envelope.content
        mail_from = envelope.mail_from

        message = message_from_bytes(data.rstrip())
        message_addr = parseaddr(message.get("from"))[1]
        if mail_from != message_addr:
            
            
            
            lp, domain = mail_from.split("@", 1)
            lp = Header(lp, "utf-8").encode()
            mail_from = "@".join([lp, domain])

        if mail_from != message_addr:
            return f"553 '{mail_from}' != '{message_addr}'"
        self.mailbox.append(message)
        return "250 OK"

    def flush_mailbox(self):
        self.mailbox[:] = []


@skipUnless(HAS_AIOSMTPD, "No aiosmtpd library detected.")
class SMTPBackendTestsBase(SimpleTestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        
        with socket.socket() as s:
            s.bind(("127.0.0.1", 0))
            port = s.getsockname()[1]
        cls.smtp_handler = SMTPHandler()
        cls.smtp_controller = Controller(
            cls.smtp_handler,
            hostname="127.0.0.1",
            port=port,
        )
        cls._settings_override = override_settings(
            EMAIL_HOST=cls.smtp_controller.hostname,
            EMAIL_PORT=cls.smtp_controller.port,
        )
        cls._settings_override.enable()
        cls.addClassCleanup(cls._settings_override.disable)
        cls.smtp_controller.start()
        cls.addClassCleanup(cls.stop_smtp)

    @classmethod
    def stop_smtp(cls):
        cls.smtp_controller.stop()


@skipUnless(HAS_AIOSMTPD, "No aiosmtpd library detected.")
class SMTPBackendTests(BaseEmailBackendTests, SMTPBackendTestsBase):
    email_backend = "django.core.mail.backends.smtp.EmailBackend"

    def setUp(self):
        super().setUp()
        self.smtp_handler.flush_mailbox()

    def tearDown(self):
        self.smtp_handler.flush_mailbox()
        super().tearDown()

    def flush_mailbox(self):
        self.smtp_handler.flush_mailbox()

    def get_mailbox_content(self):
        return self.smtp_handler.mailbox

    @override_settings(
        EMAIL_HOST_USER="not empty username",
        EMAIL_HOST_PASSWORD="not empty password",
    )
    def test_email_authentication_use_settings(self):
        backend = smtp.EmailBackend()
        self.assertEqual(backend.username, "not empty username")
        self.assertEqual(backend.password, "not empty password")

    @override_settings(
        EMAIL_HOST_USER="not empty username",
        EMAIL_HOST_PASSWORD="not empty password",
    )
    def test_email_authentication_override_settings(self):
        backend = smtp.EmailBackend(username="username", password="password")
        self.assertEqual(backend.username, "username")
        self.assertEqual(backend.password, "password")

    @override_settings(
        EMAIL_HOST_USER="not empty username",
        EMAIL_HOST_PASSWORD="not empty password",
    )
    def test_email_disabled_authentication(self):
        backend = smtp.EmailBackend(username="", password="")
        self.assertEqual(backend.username, "")
        self.assertEqual(backend.password, "")

    def test_auth_attempted(self):
        
        backend = smtp.EmailBackend(
            username="not empty username", password="not empty password"
        )
        with self.assertRaisesMessage(
            SMTPException, "SMTP AUTH extension not supported by server."
        ):
            with backend:
                pass

    def test_server_open(self):
        
        backend = smtp.EmailBackend(username="", password="")
        self.assertIsNone(backend.connection)
        opened = backend.open()
        backend.close()
        self.assertIs(opened, True)

    def test_reopen_connection(self):
        backend = smtp.EmailBackend()
        
        backend.connection = mock.Mock(spec=object())
        self.assertIs(backend.open(), False)

    @override_settings(EMAIL_USE_TLS=True)
    def test_email_tls_use_settings(self):
        backend = smtp.EmailBackend()
        self.assertTrue(backend.use_tls)

    @override_settings(EMAIL_USE_TLS=True)
    def test_email_tls_override_settings(self):
        backend = smtp.EmailBackend(use_tls=False)
        self.assertFalse(backend.use_tls)

    def test_email_tls_default_disabled(self):
        backend = smtp.EmailBackend()
        self.assertFalse(backend.use_tls)

    def test_ssl_tls_mutually_exclusive(self):
        msg = (
            "EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set "
            "one of those settings to True."
        )
        with self.assertRaisesMessage(ValueError, msg):
            smtp.EmailBackend(use_ssl=True, use_tls=True)

    @override_settings(EMAIL_USE_SSL=True)
    def test_email_ssl_use_settings(self):
        backend = smtp.EmailBackend()
        self.assertTrue(backend.use_ssl)

    @override_settings(EMAIL_USE_SSL=True)
    def test_email_ssl_override_settings(self):
        backend = smtp.EmailBackend(use_ssl=False)
        self.assertFalse(backend.use_ssl)

    def test_email_ssl_default_disabled(self):
        backend = smtp.EmailBackend()
        self.assertFalse(backend.use_ssl)

    @override_settings(EMAIL_SSL_CERTFILE="foo")
    def test_email_ssl_certfile_use_settings(self):
        backend = smtp.EmailBackend()
        self.assertEqual(backend.ssl_certfile, "foo")

    @override_settings(EMAIL_SSL_CERTFILE="foo")
    def test_email_ssl_certfile_override_settings(self):
        backend = smtp.EmailBackend(ssl_certfile="bar")
        self.assertEqual(backend.ssl_certfile, "bar")

    def test_email_ssl_certfile_default_disabled(self):
        backend = smtp.EmailBackend()
        self.assertIsNone(backend.ssl_certfile)

    @override_settings(EMAIL_SSL_KEYFILE="foo")
    def test_email_ssl_keyfile_use_settings(self):
        backend = smtp.EmailBackend()
        self.assertEqual(backend.ssl_keyfile, "foo")

    @override_settings(EMAIL_SSL_KEYFILE="foo")
    def test_email_ssl_keyfile_override_settings(self):
        backend = smtp.EmailBackend(ssl_keyfile="bar")
        self.assertEqual(backend.ssl_keyfile, "bar")

    def test_email_ssl_keyfile_default_disabled(self):
        backend = smtp.EmailBackend()
        self.assertIsNone(backend.ssl_keyfile)

    @override_settings(EMAIL_USE_TLS=True)
    def test_email_tls_attempts_starttls(self):
        backend = smtp.EmailBackend()
        self.assertTrue(backend.use_tls)
        with self.assertRaisesMessage(
            SMTPException, "STARTTLS extension not supported by server."
        ):
            with backend:
                pass

    @override_settings(EMAIL_USE_SSL=True)
    def test_email_ssl_attempts_ssl_connection(self):
        backend = smtp.EmailBackend()
        self.assertTrue(backend.use_ssl)
        with self.assertRaises(SSLError):
            with backend:
                pass

    def test_connection_timeout_default(self):
        
        connection = mail.get_connection("django.core.mail.backends.smtp.EmailBackend")
        self.assertIsNone(connection.timeout)

    def test_connection_timeout_custom(self):
        

        class MyEmailBackend(smtp.EmailBackend):
            def __init__(self, *args, **kwargs):
                kwargs.setdefault("timeout", 42)
                super().__init__(*args, **kwargs)

        myemailbackend = MyEmailBackend()
        myemailbackend.open()
        self.assertEqual(myemailbackend.timeout, 42)
        self.assertEqual(myemailbackend.connection.timeout, 42)
        myemailbackend.close()

    @override_settings(EMAIL_TIMEOUT=10)
    def test_email_timeout_override_settings(self):
        backend = smtp.EmailBackend()
        self.assertEqual(backend.timeout, 10)

    def test_email_msg_uses_crlf(self):
        
        send = SMTP.send
        try:
            smtp_messages = []

            def mock_send(self, s):
                smtp_messages.append(s)
                return send(self, s)

            SMTP.send = mock_send

            email = EmailMessage(
                "Subject", "Content", "from@example.com", ["to@example.com"]
            )
            mail.get_connection().send_messages([email])

            
            msg = None
            for i, m in enumerate(smtp_messages):
                if m[:4] == "data":
                    msg = smtp_messages[i + 1]
                    break

            self.assertTrue(msg)

            msg = msg.decode()
            
            msg = msg.replace("\r\n", "")
            self.assertNotIn("\r", msg)
            self.assertNotIn("\n", msg)

        finally:
            SMTP.send = send

    def test_send_messages_after_open_failed(self):
        
        backend = smtp.EmailBackend()
        
        
        backend.connection = mock.Mock(spec=object())
        backend.open = lambda: None
        email = EmailMessage(
            "Subject", "Content", "from@example.com", ["to@example.com"]
        )
        self.assertEqual(backend.send_messages([email]), 0)

    def test_send_messages_empty_list(self):
        backend = smtp.EmailBackend()
        backend.connection = mock.Mock(spec=object())
        self.assertEqual(backend.send_messages([]), 0)

    def test_send_messages_zero_sent(self):
        
        backend = smtp.EmailBackend()
        backend.connection = mock.Mock(spec=object())
        email = EmailMessage("Subject", "Content", "from@example.com", to=[])
        sent = backend.send_messages([email])
        self.assertEqual(sent, 0)


@skipUnless(HAS_AIOSMTPD, "No aiosmtpd library detected.")
class SMTPBackendStoppedServerTests(SMTPBackendTestsBase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.backend = smtp.EmailBackend(username="", password="")
        cls.smtp_controller.stop()

    @classmethod
    def stop_smtp(cls):
        
        pass

    def test_server_stopped(self):
        
        self.backend.close()

    def test_fail_silently_on_connection_error(self):
        
        with self.assertRaises(ConnectionError):
            self.backend.open()
        self.backend.fail_silently = True
        self.backend.open()