Ticket #14440: bug14440.diff

File bug14440.diff, 39.0 KB (added by Andi Albrecht, 14 years ago)
  • tests/regressiontests/mail/tests.py

    diff --git a/tests/regressiontests/mail/tests.py b/tests/regressiontests/mail/tests.py
    index 05973e6..c321ced 100644
    a b  
    11# coding: utf-8
    2 
    3 r"""
    4 # Tests for the django.core.mail.
    5 
    6 >>> import os
    7 >>> import shutil
    8 >>> import tempfile
    9 >>> from StringIO import StringIO
    10 >>> from django.conf import settings
    11 >>> from django.core import mail
    12 >>> from django.core.mail import EmailMessage, mail_admins, mail_managers, EmailMultiAlternatives
    13 >>> from django.core.mail import send_mail, send_mass_mail
    14 >>> from django.core.mail.backends.base import BaseEmailBackend
    15 >>> from django.core.mail.backends import console, dummy, locmem, filebased, smtp
    16 >>> from django.utils.translation import ugettext_lazy
    17 
    18 # Test normal ascii character case:
    19 
    20 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'])
    21 >>> message = email.message()
    22 >>> message['Subject'].encode()
    23 'Subject'
    24 >>> message.get_payload()
    25 'Content'
    26 >>> message['From']
    27 'from@example.com'
    28 >>> message['To']
    29 'to@example.com'
    30 
    31 # Test multiple-recipient case
    32 
    33 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com','other@example.com'])
    34 >>> message = email.message()
    35 >>> message['Subject'].encode()
    36 'Subject'
    37 >>> message.get_payload()
    38 'Content'
    39 >>> message['From']
    40 'from@example.com'
    41 >>> message['To']
    42 'to@example.com, other@example.com'
    43 
    44 # Test for header injection
    45 
    46 >>> email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com'])
    47 >>> message = email.message()
    48 Traceback (most recent call last):
    49     ...
    50 BadHeaderError: Header values can't contain newlines (got u'Subject\nInjection Test' for header 'Subject')
    51 
    52 >>> email = EmailMessage(ugettext_lazy('Subject\nInjection Test'), 'Content', 'from@example.com', ['to@example.com'])
    53 >>> message = email.message()
    54 Traceback (most recent call last):
    55     ...
    56 BadHeaderError: Header values can't contain newlines (got u'Subject\nInjection Test' for header 'Subject')
    57 
    58 # Test for space continuation character in long (ascii) subject headers (#7747)
    59 
    60 >>> email = EmailMessage('Long subject lines that get wrapped should use a space continuation character to get expected behaviour in Outlook and Thunderbird', 'Content', 'from@example.com', ['to@example.com'])
    61 >>> message = email.message()
    62 >>> message.as_string()
    63 'Content-Type: text/plain; charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\nSubject: Long subject lines that get wrapped should use a space continuation\n character to get expected behaviour in Outlook and Thunderbird\nFrom: from@example.com\nTo: to@example.com\nDate: ...\nMessage-ID: <...>\n\nContent'
    64 
    65 # Specifying dates or message-ids in the extra headers overrides the defaul
    66 # values (#9233).
    67 
    68 >>> headers = {"date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
    69 >>> email = EmailMessage('subject', 'content', 'from@example.com', ['to@example.com'], headers=headers)
    70 >>> email.message().as_string()
    71 'Content-Type: text/plain; charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\nSubject: subject\nFrom: from@example.com\nTo: to@example.com\ndate: Fri, 09 Nov 2001 01:08:47 -0000\nMessage-ID: foo\n\ncontent'
    72 
    73 # Test that mail_admins/mail_managers doesn't connect to the mail server if there are no recipients (#9383)
    74 
    75 >>> old_admins = settings.ADMINS
    76 >>> old_managers = settings.MANAGERS
    77 >>> settings.ADMINS = []
    78 >>> settings.MANAGERS = []
    79 >>> mail.outbox = []
    80 >>> mail_admins('hi','there')
    81 >>> len(mail.outbox)
    82 0
    83 >>> mail.outbox = []
    84 >>> mail_managers('hi','there')
    85 >>> len(mail.outbox)
    86 0
    87 >>> settings.ADMINS = settings.MANAGERS = [('nobody','nobody@example.com')]
    88 >>> mail.outbox = []
    89 >>> mail_admins('hi','there')
    90 >>> len(mail.outbox)
    91 1
    92 >>> mail.outbox = []
    93 >>> mail_managers('hi','there')
    94 >>> len(mail.outbox)
    95 1
    96 
    97 # Make sure we can manually set the From header (#9214)
    98 
    99 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    100 >>> message = email.message()
    101 >>> message['From']
    102 'from@example.com'
    103 
    104 # Regression for #13259 - Make sure that headers are not changed
    105 # when calling EmailMessage.message()
    106 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    107 >>> message = email.message()
    108 >>> message['From']
    109 'from@example.com'
    110 >>> message = email.message()
    111 >>> message['From']
    112 'from@example.com'
    113 
    114 # Regression for #11144 - When a to/from/cc header contains unicode,
    115 # make sure the email addresses are parsed correctly (especially
    116 # with regards to commas)
    117 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['"Firstname Sürname" <to@example.com>','other@example.com'])
    118 >>> email.message()['To']
    119 '=?utf-8?q?Firstname_S=C3=BCrname?= <to@example.com>, other@example.com'
    120 
    121 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['"Sürname, Firstname" <to@example.com>','other@example.com'])
    122 >>> email.message()['To']
    123 '=?utf-8?q?S=C3=BCrname=2C_Firstname?= <to@example.com>, other@example.com'
    124 
    125 # Regression for #6918 - When a header contains unicode,
    126 # make sure headers can be set with a different encoding than utf-8
    127 >>> email = EmailMessage('Message from Firstname Sürname', 'Content', 'from@example.com', ['"Sürname, Firstname" <to@example.com>','other@example.com'])
    128 >>> email.encoding = 'iso-8859-1'
    129 >>> email.message()['To']
    130 '=?iso-8859-1?q?S=FCrname=2C_Firstname?= <to@example.com>, other@example.com'
    131 >>> email.message()['Subject'].encode()
    132 u'=?iso-8859-1?q?Message_from_Firstname_S=FCrname?='
    133 
    134 # Make sure headers can be set with a different encoding than utf-8 in SafeMIMEMultipart as well
    135 >>> headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
    136 >>> subject, from_email, to = 'hello', 'from@example.com', '"Sürname, Firstname" <to@example.com>'
    137 >>> text_content = 'This is an important message.'
    138 >>> html_content = '<p>This is an <strong>important</strong> message.</p>'
    139 >>> msg = EmailMultiAlternatives('Message from Firstname Sürname', text_content, from_email, [to], headers=headers)
    140 >>> msg.attach_alternative(html_content, "text/html")
    141 >>> msg.encoding = 'iso-8859-1'
    142 >>> msg.message()['To']
    143 '=?iso-8859-1?q?S=FCrname=2C_Firstname?= <to@example.com>'
    144 >>> msg.message()['Subject'].encode()
    145 u'=?iso-8859-1?q?Message_from_Firstname_S=FCrname?='
    146 
    147 # Regression for #12791  - Encode body correctly with other encodings than utf-8
    148 >>> email = EmailMessage('Subject', 'Firstname Sürname is a great guy.', 'from@example.com', ['other@example.com'])
    149 >>> email.encoding = 'iso-8859-1'
    150 >>> message = email.message()
    151 >>> message.as_string()
    152 'Content-Type: text/plain; charset="iso-8859-1"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\nSubject: Subject\nFrom: from@example.com\nTo: other@example.com\nDate: ...\nMessage-ID: <...>\n\nFirstname S=FCrname is a great guy.'
    153 
    154 # Make sure MIME attachments also works correctly with other encodings than utf-8
    155 >>> text_content = 'Firstname Sürname is a great guy.'
    156 >>> html_content = '<p>Firstname Sürname is a <strong>great</strong> guy.</p>'
    157 >>> msg = EmailMultiAlternatives('Subject', text_content, 'from@example.com', ['to@example.com'])
    158 >>> msg.encoding = 'iso-8859-1'
    159 >>> msg.attach_alternative(html_content, "text/html")
    160 >>> msg.message().get_payload(0).as_string()
    161 'Content-Type: text/plain; charset="iso-8859-1"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\n\nFirstname S=FCrname is a great guy.'
    162 >>> msg.message().get_payload(1).as_string()
    163 'Content-Type: text/html; charset="iso-8859-1"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>'
    164 
    165 # Handle attachments within an multipart/alternative mail correctly (#9367)
    166 # (test is not as precise/clear as it could be w.r.t. email tree structure,
    167 #  but it's good enough.)
    168 >>> headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
    169 >>> subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
    170 >>> text_content = 'This is an important message.'
    171 >>> html_content = '<p>This is an <strong>important</strong> message.</p>'
    172 >>> msg = EmailMultiAlternatives(subject, text_content, from_email, [to], headers=headers)
    173 >>> msg.attach_alternative(html_content, "text/html")
    174 >>> msg.attach("an attachment.pdf", "%PDF-1.4.%...", mimetype="application/pdf")
    175 >>> print msg.message().as_string()
    176 Content-Type: multipart/mixed; boundary="..."
    177 MIME-Version: 1.0
    178 Subject: hello
    179 From: from@example.com
    180 To: to@example.com
    181 Date: Fri, 09 Nov 2001 01:08:47 -0000
    182 Message-ID: foo
    183 ...
    184 Content-Type: multipart/alternative;...
    185 ...
    186 Content-Type: text/plain; charset="utf-8"
    187 MIME-Version: 1.0
    188 Content-Transfer-Encoding: quoted-printable
    189 ...
    190 This is an important message.
    191 ...
    192 Content-Type: text/html; charset="utf-8"
    193 MIME-Version: 1.0
    194 Content-Transfer-Encoding: quoted-printable
    195 ...
    196 <p>This is an <strong>important</strong> message.</p>
    197 ...
    198 ...
    199 Content-Type: application/pdf
    200 MIME-Version: 1.0
    201 Content-Transfer-Encoding: base64
    202 Content-Disposition: attachment; filename="an attachment.pdf"
    203 ...
    204 JVBERi0xLjQuJS4uLg==
    205 ...
    206 
    207 # Make sure that the console backend writes to stdout by default
    208 >>> connection = console.EmailBackend()
    209 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    210 >>> connection.send_messages([email])
    211 Content-Type: text/plain; charset="utf-8"
    212 MIME-Version: 1.0
    213 Content-Transfer-Encoding: quoted-printable
    214 Subject: Subject
    215 From: from@example.com
    216 To: to@example.com
    217 Date: ...
    218 Message-ID: ...
    219 
    220 Content
    221 -------------------------------------------------------------------------------
    222 1
    223 
    224 # Test that the console backend can be pointed at an arbitrary stream
    225 >>> s = StringIO()
    226 >>> connection = mail.get_connection('django.core.mail.backends.console.EmailBackend', stream=s)
    227 >>> send_mail('Subject', 'Content', 'from@example.com', ['to@example.com'], connection=connection)
    228 1
    229 >>> print s.getvalue()
    230 Content-Type: text/plain; charset="utf-8"
    231 MIME-Version: 1.0
    232 Content-Transfer-Encoding: quoted-printable
    233 Subject: Subject
    234 From: from@example.com
    235 To: to@example.com
    236 Date: ...
    237 Message-ID: ...
    238 
    239 Content
    240 -------------------------------------------------------------------------------
    241 
    242 # Make sure that dummy backends returns correct number of sent messages
    243 >>> connection = dummy.EmailBackend()
    244 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    245 >>> connection.send_messages([email, email, email])
    246 3
    247 
    248 # Make sure that locmen backend populates the outbox
    249 >>> mail.outbox = []
    250 >>> connection = locmem.EmailBackend()
    251 >>> email1 = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    252 >>> email2 = EmailMessage('Subject 2', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    253 >>> connection.send_messages([email1, email2])
    254 2
    255 >>> len(mail.outbox)
    256 2
    257 >>> mail.outbox[0].subject
    258 'Subject'
    259 >>> mail.outbox[1].subject
    260 'Subject 2'
    261 
    262 # Make sure that multiple locmem connections share mail.outbox
    263 >>> mail.outbox = []
    264 >>> connection1 = locmem.EmailBackend()
    265 >>> connection2 = locmem.EmailBackend()
    266 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    267 >>> connection1.send_messages([email])
    268 1
    269 >>> connection2.send_messages([email])
    270 1
    271 >>> len(mail.outbox)
    272 2
    273 
    274 # Make sure that the file backend write to the right location
    275 >>> tmp_dir = tempfile.mkdtemp()
    276 >>> connection = filebased.EmailBackend(file_path=tmp_dir)
    277 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    278 >>> connection.send_messages([email])
    279 1
    280 >>> len(os.listdir(tmp_dir))
    281 1
    282 >>> print open(os.path.join(tmp_dir, os.listdir(tmp_dir)[0])).read()
    283 Content-Type: text/plain; charset="utf-8"
    284 MIME-Version: 1.0
    285 Content-Transfer-Encoding: quoted-printable
    286 Subject: Subject
    287 From: from@example.com
    288 To: to@example.com
    289 Date: ...
    290 Message-ID: ...
    291 
    292 Content
    293 -------------------------------------------------------------------------------
    294 
    295 >>> connection2 = filebased.EmailBackend(file_path=tmp_dir)
    296 >>> connection2.send_messages([email])
    297 1
    298 >>> len(os.listdir(tmp_dir))
    299 2
    300 >>> connection.send_messages([email])
    301 1
    302 >>> len(os.listdir(tmp_dir))
    303 2
    304 >>> email.connection = filebased.EmailBackend(file_path=tmp_dir)
    305 >>> connection_created = connection.open()
    306 >>> num_sent = email.send()
    307 >>> len(os.listdir(tmp_dir))
    308 3
    309 >>> num_sent = email.send()
    310 >>> len(os.listdir(tmp_dir))
    311 3
    312 >>> connection.close()
    313 >>> shutil.rmtree(tmp_dir)
    314 
    315 # Make sure that get_connection() accepts arbitrary keyword that might be
    316 # used with custom backends.
    317 >>> c = mail.get_connection(fail_silently=True, foo='bar')
    318 >>> c.fail_silently
    319 True
    320 
    321 # Test custom backend defined in this suite.
    322 >>> conn = mail.get_connection('regressiontests.mail.custombackend.EmailBackend')
    323 >>> hasattr(conn, 'test_outbox')
    324 True
    325 >>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
    326 >>> conn.send_messages([email])
    327 1
    328 >>> len(conn.test_outbox)
    329 1
    330 
    331 # Test backend argument of mail.get_connection()
    332 >>> isinstance(mail.get_connection('django.core.mail.backends.smtp.EmailBackend'), smtp.EmailBackend)
    333 True
    334 >>> isinstance(mail.get_connection('django.core.mail.backends.locmem.EmailBackend'), locmem.EmailBackend)
    335 True
    336 >>> isinstance(mail.get_connection('django.core.mail.backends.dummy.EmailBackend'), dummy.EmailBackend)
    337 True
    338 >>> isinstance(mail.get_connection('django.core.mail.backends.console.EmailBackend'), console.EmailBackend)
    339 True
    340 >>> tmp_dir = tempfile.mkdtemp()
    341 >>> isinstance(mail.get_connection('django.core.mail.backends.filebased.EmailBackend', file_path=tmp_dir), filebased.EmailBackend)
    342 True
    343 >>> shutil.rmtree(tmp_dir)
    344 >>> isinstance(mail.get_connection(), locmem.EmailBackend)
    345 True
    346 
    347 # Test connection argument of send_mail() et al
    348 >>> connection = mail.get_connection('django.core.mail.backends.console.EmailBackend')
    349 >>> send_mail('Subject', 'Content', 'from@example.com', ['to@example.com'], connection=connection)
    350 Content-Type: text/plain; charset="utf-8"
    351 MIME-Version: 1.0
    352 Content-Transfer-Encoding: quoted-printable
    353 Subject: Subject
    354 From: from@example.com
    355 To: to@example.com
    356 Date: ...
    357 Message-ID: ...
    358 
    359 Content
    360 -------------------------------------------------------------------------------
    361 1
    362 
    363 >>> send_mass_mail([
    364 ...         ('Subject1', 'Content1', 'from1@example.com', ['to1@example.com']),
    365 ...         ('Subject2', 'Content2', 'from2@example.com', ['to2@example.com'])
    366 ...     ], connection=connection)
    367 Content-Type: text/plain; charset="utf-8"
    368 MIME-Version: 1.0
    369 Content-Transfer-Encoding: quoted-printable
    370 Subject: Subject1
    371 From: from1@example.com
    372 To: to1@example.com
    373 Date: ...
    374 Message-ID: ...
    375 
    376 Content1
    377 -------------------------------------------------------------------------------
    378 Content-Type: text/plain; charset="utf-8"
    379 MIME-Version: 1.0
    380 Content-Transfer-Encoding: quoted-printable
    381 Subject: Subject2
    382 From: from2@example.com
    383 To: to2@example.com
    384 Date: ...
    385 Message-ID: ...
    386 
    387 Content2
    388 -------------------------------------------------------------------------------
    389 2
    390 
    391 >>> mail_admins('Subject', 'Content', connection=connection)
    392 Content-Type: text/plain; charset="utf-8"
    393 MIME-Version: 1.0
    394 Content-Transfer-Encoding: quoted-printable
    395 Subject: [Django] Subject
    396 From: root@localhost
    397 To: nobody@example.com
    398 Date: ...
    399 Message-ID: ...
    400 
    401 Content
    402 -------------------------------------------------------------------------------
    403 
    404 >>> mail_managers('Subject', 'Content', connection=connection)
    405 Content-Type: text/plain; charset="utf-8"
    406 MIME-Version: 1.0
    407 Content-Transfer-Encoding: quoted-printable
    408 Subject: [Django] Subject
    409 From: root@localhost
    410 To: nobody@example.com
    411 Date: ...
    412 Message-ID: ...
    413 
    414 Content
    415 -------------------------------------------------------------------------------
    416 
    417 >>> settings.ADMINS = old_admins
    418 >>> settings.MANAGERS = old_managers
    419 
    420 # Add Cc to the email argument list (#7722)
    421 
    422 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'], cc=['cc@example.com'])
    423 >>> message = email.message()
    424 >>> message['Cc']
    425 'cc@example.com'
    426 >>> email.recipients()
    427 ['to@example.com', 'cc@example.com']
    428 
    429 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com','other@example.com'], cc=['cc@example.com', 'cc.other@example.com'])
    430 >>> message = email.message()
    431 >>> message['Cc']
    432 'cc@example.com, cc.other@example.com'
    433 >>> email.recipients()
    434 ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com']
    435 
    436 >>> 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'])
    437 >>> message = email.message()
    438 >>> email.recipients()
    439 ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']
    440 
    441 >>> email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'], cc=['cc@example.com'])
    442 >>> message = email.message()
    443 >>> message.as_string()
    444 'Content-Type: text/plain; charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\nSubject: Subject\nFrom: from@example.com\nTo: to@example.com\nCc: cc@example.com\nDate: ...\nMessage-ID: <...>\n\nContent'
    445 
    446 """
     2"""Tests for the django.core.mail."""
     3
     4import os
     5import shutil
     6import tempfile
     7import unittest
     8from email import message_from_file, message_from_string
     9from StringIO import StringIO
     10
     11from django.conf import settings
     12from django.core import mail
     13from django.core.mail import BadHeaderError
     14from django.core.mail import EmailMessage, EmailMultiAlternatives
     15from django.core.mail import mail_admins, mail_managers
     16from django.core.mail import send_mail, send_mass_mail
     17from django.core.mail.backends import console, dummy, filebased, locmem, smtp
     18from django.utils.translation import ugettext_lazy
     19
     20
     21class MailTests(unittest.TestCase):
     22
     23    def test_ascii_characters(self):
     24        email = EmailMessage('Subject', 'Content', 'from@example.com',
     25                             ['to@example.com'])
     26        message = email.message()
     27        self.assertEqual(message['Subject'].encode(), 'Subject')
     28        self.assertEqual(message.get_payload(), 'Content')
     29        self.assertEqual(message['From'], 'from@example.com')
     30        self.assertEqual(message['To'], 'to@example.com')
     31
     32    def test_multiple_recipients(self):
     33         email = EmailMessage('Subject', 'Content', 'from@example.com',
     34                              ['to@example.com','other@example.com'])
     35         message = email.message()
     36         self.assertEqual(message['Subject'].encode(),  'Subject')
     37         self.assertEqual(message.get_payload(), 'Content')
     38         self.assertEqual(message['From'], 'from@example.com')
     39         self.assertEqual(message['To'], 'to@example.com, other@example.com')
     40
     41    def test_header_injection(self):
     42        email = EmailMessage('Subject\nInjection Test', 'Content',
     43                             'from@example.com', ['to@example.com'])
     44        self.assertRaises(BadHeaderError, email.message)
     45        # again with lazy translation
     46        email = EmailMessage(ugettext_lazy('Subject\nInjection Test'),
     47                             'Content', 'from@example.com',
     48                             ['to@example.com'])
     49        self.assertRaises(BadHeaderError, email.message)
     50
     51    def test_continuation_char_in_long_header(self):
     52        # Regression test for #7747
     53        email = EmailMessage(
     54            ('Long subject lines that get wrapped should use a space '
     55             'continuation character to get expected behaviour in Outlook '
     56             'and Thunderbird'), 'Content',
     57            'from@example.com', ['to@example.com'])
     58        message = email.message()
     59        self.assertEqual(str(message['Subject']),
     60            ('Long subject lines that get wrapped should use a space continuation\n'
     61             ' character to get expected behaviour in Outlook and Thunderbird'))
     62
     63    def test_custom_message_id(self):
     64        # Regression test for #9233
     65        date_str = 'Fri, 09 Nov 2001 01:08:47 -0000'
     66        headers = {'date': date_str, 'Message-ID': 'foo'}
     67        email = EmailMessage('subject', 'content', 'from@example.com',
     68                             ['to@example.com'], headers=headers)
     69        message = email.message()
     70        self.assertEqual(str(message['Message-ID']), 'foo')
     71        self.assertEqual(str(message['date']), date_str)
     72
     73    def test_ignore_empty_managers(self):
     74        # Test that mail_admins/mail_managers doesn't connect to the
     75        # mail server if there are no recipients (#9383).
     76        old_admins = settings.ADMINS
     77        old_managers = settings.MANAGERS
     78        settings.ADMINS = []
     79        settings.MANAGERS = []
     80        mail.outbox = []
     81        try:
     82            mail_admins('hi','there')
     83            self.assertEqual(len(mail.outbox), 0)
     84            mail_managers('hi','there')
     85            self.assertEqual(len(mail.outbox), 0)
     86            settings.ADMINS = settings.MANAGERS = [
     87                ('nobody','nobody@example.com')]
     88            mail_admins('hi','there')
     89            self.assertEqual(len(mail.outbox), 1)
     90            mail.outbox = []
     91            mail_managers('hi','there')
     92            self.assertEqual(len(mail.outbox), 1)
     93        finally:
     94            settings.ADMINS = old_admins
     95            settings.MANAGER = old_managers
     96
     97    def test_set_from_header_manually(self):
     98        # Regression test for #9214
     99        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     100                             ['to@example.com'],
     101                             headers={'From': 'from@example.com'})
     102        message = email.message()
     103        self.assertEqual(message['From'], 'from@example.com')
     104
     105    def test_headers_dont_change(self):
     106        # Regression for #13259 - Make sure that headers are not
     107        # changed when calling EmailMessage.message()
     108        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     109                             ['to@example.com'],
     110                             headers={'From': 'from@example.com'})
     111        message = email.message()
     112        self.assertEqual(message['From'], 'from@example.com')
     113        message = email.message()
     114        self.assertEqual(message['From'], 'from@example.com')
     115
     116    def test_parse_unicode_addresses(self):
     117        # Regression for #11144 - When a to/from/cc header contains
     118        # unicode, make sure the email addresses are parsed correctly
     119        # (especially with regards to commas)
     120        email = EmailMessage('Subject', 'Content', 'from@example.com',
     121                             ['"Firstname Sürname" <to@example.com>',
     122                              'other@example.com'])
     123        self.assertEqual(email.message()['To'],
     124                         ('=?utf-8?q?Firstname_S=C3=BCrname?= '
     125                          '<to@example.com>, other@example.com'))
     126
     127        email = EmailMessage('Subject', 'Content', 'from@example.com',
     128                             ['"Sürname, Firstname" <to@example.com>',
     129                              'other@example.com'])
     130        self.assertEqual(email.message()['To'],
     131                         ('=?utf-8?q?S=C3=BCrname=2C_Firstname?= '
     132                          '<to@example.com>, other@example.com'))
     133
     134    def test_header_encoding(self):
     135        # Regression for #6918 - When a header contains unicode,
     136        # make sure headers can be set with a different encoding than utf-8
     137        email = EmailMessage('Message from Firstname Sürname', 'Content',
     138                             'from@example.com',
     139                             ['"Sürname, Firstname" <to@example.com>',
     140                              'other@example.com'])
     141        email.encoding = 'iso-8859-1'
     142        self.assertEqual(email.message()['To'],
     143                         '=?iso-8859-1?q?S=FCrname=2C_Firstname?= <to@example.com>, other@example.com')
     144        self.assertEqual(email.message()['Subject'].encode(),
     145                         u'=?iso-8859-1?q?Message_from_Firstname_S=FCrname?=')
     146
     147    def test_header_encoding_multipart(self):
     148        # Make sure headers can be set with a different encoding than
     149        # utf-8 in SafeMIMEMultipart as well
     150        headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000",
     151                   "Message-ID": "foo"}
     152        subject, from_email, to = 'hello', 'from@example.com', '"Sürname, Firstname" <to@example.com>'
     153        text_content = 'This is an important message.'
     154        html_content = '<p>This is an <strong>important</strong> message.</p>'
     155        msg = EmailMultiAlternatives('Message from Firstname Sürname',
     156                                     text_content, from_email, [to],
     157                                     headers=headers)
     158        msg.attach_alternative(html_content, "text/html")
     159        msg.encoding = 'iso-8859-1'
     160        self.assertEqual(msg.message()['To'],
     161                         '=?iso-8859-1?q?S=FCrname=2C_Firstname?= <to@example.com>')
     162        self.assertEqual(msg.message()['Subject'].encode(),
     163                         u'=?iso-8859-1?q?Message_from_Firstname_S=FCrname?=')
     164
     165    def test_body_encoding(self):
     166        # Regression for #12791 - Encode body correctly with other
     167        # encodings than utf-8
     168        email = EmailMessage('Subject', 'Firstname Sürname is a great guy.',
     169                             'from@example.com', ['other@example.com'])
     170        email.encoding = 'iso-8859-1'
     171        message = email.message()
     172        self.assertEqual(str(message['Content-Type']),
     173                         'text/plain; charset="iso-8859-1"')
     174        self.assertEqual(message.get_payload(),
     175                         'Firstname S=FCrname is a great guy.')
     176
     177    def test_attachment_encoding(self):
     178        # Make sure MIME attachments also works correctly with other
     179        # encodings than utf-8
     180        text_content = 'Firstname Sürname is a great guy.'
     181        html_content = '<p>Firstname Sürname is a <strong>great</strong> guy.</p>'
     182        email = EmailMultiAlternatives('Subject', text_content,
     183                                       'from@example.com', ['to@example.com'])
     184        email.encoding = 'iso-8859-1'
     185        email.attach_alternative(html_content, 'text/html')
     186        message = email.message()
     187        payload0 = message.get_payload(0)
     188        payload1 = message.get_payload(1)
     189        self.assertEqual(payload0['Content-Type'],
     190                         'text/plain; charset="iso-8859-1"')
     191        self.assertEqual(payload0.get_payload(),
     192                         'Firstname S=FCrname is a great guy.')
     193        self.assertEqual(payload1['Content-Type'],
     194                         'text/html; charset="iso-8859-1"')
     195        self.assertEqual(payload1.get_payload(),
     196                         '<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>')
     197
     198    def test_handle_attachments(self):
     199        # Handle attachments within an multipart/alternative mail
     200        # correctly (#9367) (test is not as precise/clear as it could
     201        # be w.r.t. email tree structure, but it's good enough.)
     202        headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000",
     203                   "Message-ID": "foo"}
     204        subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
     205        text_content = 'This is an important message.'
     206        html_content = '<p>This is an <strong>important</strong> message.</p>'
     207        email = EmailMultiAlternatives(subject, text_content, from_email,
     208                                       [to], headers=headers)
     209        email.attach_alternative(html_content, "text/html")
     210        email.attach("an attachment.pdf", "%PDF-1.4.%...",
     211                     mimetype="application/pdf")
     212        message = email.message()
     213        payload0 = message.get_payload(0)
     214        payload1 = message.get_payload(1)
     215        self.assert_(payload0['Content-Type'].startswith('multipart/alternative'))
     216        self.assertEqual(payload0.get_payload(0)['Content-Type'],
     217                         'text/plain; charset="utf-8"')
     218        self.assertEqual(payload0.get_payload(1)['Content-Type'],
     219                         'text/html; charset="utf-8"')
     220        self.assertEqual(payload0.get_payload(0)['Content-Transfer-Encoding'],
     221                         'quoted-printable')
     222        self.assertEqual(payload0.get_payload(1)['Content-Transfer-Encoding'],
     223                         'quoted-printable')
     224        self.assertEqual(payload0.get_payload(0).get_payload(),
     225                         'This is an important message.')
     226        self.assertEqual(payload0.get_payload(1).get_payload(),
     227                         '<p>This is an <strong>important</strong> message.</p>')
     228        self.assertEqual(payload1['Content-Type'], 'application/pdf')
     229        self.assertEqual(payload1['Content-Disposition'],
     230                         'attachment; filename="an attachment.pdf"')
     231        self.assertEqual(payload1['Content-Transfer-Encoding'], 'base64')
     232
     233    def test_console_backend(self):
     234        # Make sure that the console backend write to arbitrary streams.
     235        stream = StringIO()
     236        connection = console.EmailBackend(stream=stream)
     237        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     238                             ['to@example.com'],
     239                             headers={'From': 'from@example.com'})
     240        self.assertEqual(connection.send_messages([email]), 1)
     241        lines = stream.getvalue().splitlines()
     242        self.assert_('MIME-Version: 1.0' in lines)
     243        self.assert_('Subject: Subject' in lines)
     244        self.assert_('From: from@example.com' in lines)
     245        self.assert_('To: to@example.com' in lines)
     246
     247    def test_dummy_backend(self):
     248        # Make sure that dummy backends returns correct number of sent
     249        # messages
     250        connection = dummy.EmailBackend()
     251        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     252                             ['to@example.com'],
     253                             headers={'From': 'from@example.com'})
     254        self.assertEqual(connection.send_messages([email, email, email]), 3)
     255
     256    def test_locmem_backend(self):
     257        # Make sure that locmen backend populates the outbox
     258        mail.outbox = []
     259        connection = locmem.EmailBackend()
     260        email1 = EmailMessage('Subject', 'Content', 'bounce@example.com',
     261                              ['to@example.com'],
     262                              headers={'From': 'from@example.com'})
     263        email2 = EmailMessage('Subject 2', 'Content', 'bounce@example.com',
     264                              ['to@example.com'],
     265                              headers={'From': 'from@example.com'})
     266        self.assertEqual(connection.send_messages([email1, email2]), 2)
     267        self.assertEqual(len(mail.outbox), 2)
     268        self.assertEqual(mail.outbox[0].subject, 'Subject')
     269        self.assertEqual(mail.outbox[1].subject, 'Subject 2')
     270
     271    def test_locmem_backend_multiple(self):
     272        # Make sure that multiple locmem connections share mail.outbox
     273        mail.outbox = []
     274        connection1 = locmem.EmailBackend()
     275        connection2 = locmem.EmailBackend()
     276        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     277                             ['to@example.com'],
     278                             headers={'From': 'from@example.com'})
     279        self.assertEqual(connection1.send_messages([email]), 1)
     280        self.assertEqual(connection2.send_messages([email]), 1)
     281        self.assertEqual(len(mail.outbox), 2)
     282
     283    def test_file_backend(self):
     284        # Make sure that the file backend write to the right location
     285        tmp_dir = tempfile.mkdtemp()
     286        connection = filebased.EmailBackend(file_path=tmp_dir)
     287        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     288                             ['to@example.com'],
     289                             headers={'From': 'from@example.com'})
     290        self.assertEqual(connection.send_messages([email]), 1)
     291        self.assertEqual(len(os.listdir(tmp_dir)), 1)
     292        fp = open(os.path.join(tmp_dir, os.listdir(tmp_dir)[0]))
     293        message = message_from_file(fp)
     294        fp.close()
     295        self.assertEqual(message['Content-Type'],
     296                         'text/plain; charset="utf-8"')
     297        self.assertEqual(message['Subject'], 'Subject')
     298        self.assertEqual(message['From'], 'from@example.com')
     299        self.assertEqual(message['To'], 'to@example.com')
     300
     301        connection2 = filebased.EmailBackend(file_path=tmp_dir)
     302        self.assertEqual(connection2.send_messages([email]), 1)
     303        self.assertEqual(len(os.listdir(tmp_dir)), 2)
     304        self.assertEqual(connection.send_messages([email]), 1)
     305        self.assertEqual(len(os.listdir(tmp_dir)), 2)
     306
     307        email.connection = filebased.EmailBackend(file_path=tmp_dir)
     308        connection.open()
     309        email.send()
     310        self.assertEqual(len(os.listdir(tmp_dir)), 3)
     311        email.send()
     312        self.assertEqual(len(os.listdir(tmp_dir)), 3)
     313        connection.close()
     314        shutil.rmtree(tmp_dir)
     315
     316    def test_get_connection(self):
     317        # Make sure that get_connection() accepts arbitrary keyword
     318        # that might be used with custom backends.
     319        c = mail.get_connection(fail_silently=True, foo='bar')
     320        self.assertEqual(c.fail_silently, True)
     321
     322    def test_custom_backend(self):
     323        # Test custom backend defined in this suite.
     324        conn = mail.get_connection(
     325            'regressiontests.mail.custombackend.EmailBackend')
     326        self.assert_(hasattr(conn, 'test_outbox'))
     327        email = EmailMessage('Subject', 'Content', 'bounce@example.com',
     328                             ['to@example.com'],
     329                             headers={'From': 'from@example.com'})
     330        self.assertEqual(conn.send_messages([email]), 1)
     331        self.assertEqual(len(conn.test_outbox), 1)
     332
     333    def test_builtin_backends(self):
     334        # Test backend argument of mail.get_connection()
     335        path = 'django.core.mail.backends.%s.EmailBackend'
     336        self.assert_(isinstance(mail.get_connection(path % 'smtp'),
     337                                smtp.EmailBackend))
     338        self.assert_(isinstance(mail.get_connection(path % 'locmem'),
     339                                locmem.EmailBackend))
     340        self.assert_(isinstance(mail.get_connection(path % 'dummy'),
     341                                dummy.EmailBackend))
     342        self.assert_(isinstance(mail.get_connection(path % 'console'),
     343                                console.EmailBackend))
     344        tmp_dir = tempfile.mkdtemp()
     345        self.assert_(isinstance(mail.get_connection(path % 'filebased',
     346                                                    file_path=tmp_dir),
     347                                filebased.EmailBackend))
     348        shutil.rmtree(tmp_dir)
     349        # the default (for tests)
     350        self.assert_(isinstance(mail.get_connection(), locmem.EmailBackend))
     351
     352    def test_connection_argument(self):
     353        # Test connection argument of send_mail() et al
     354        stream = StringIO()
     355        connection = mail.get_connection(
     356            'django.core.mail.backends.console.EmailBackend', stream=stream)
     357        self.assertEqual(send_mail('Subject', 'Content', 'from@example.com',
     358                                   ['to@example.com'], connection=connection),
     359                         1)
     360        message = message_from_string(stream.getvalue())
     361        self.assertEqual(message['Content-Type'],
     362                         'text/plain; charset="utf-8"')
     363        self.assertEqual(message['Subject'], 'Subject')
     364        self.assertEqual(message['From'], 'from@example.com')
     365
     366        stream = StringIO()
     367        connection = mail.get_connection(
     368            'django.core.mail.backends.console.EmailBackend', stream=stream)
     369        self.assertEqual(send_mass_mail([
     370            ('Subject1', 'Content1',
     371             'from1@example.com', ['to1@example.com']),
     372            ('Subject2', 'Content2',
     373             'from2@example.com', ['to2@example.com'])
     374            ], connection=connection), 2)
     375        # message separator in stream is '-'*79
     376        raw = [x.strip() for x in stream.getvalue().split('-'*79)]
     377        first, second, _ = map(message_from_string, raw)
     378        self.assertEqual(first['Subject'], 'Subject1')
     379        self.assertEqual(second['Subject'], 'Subject2')
     380        self.assertEqual(first.get_payload(), 'Content1')
     381        self.assertEqual(second.get_payload(), 'Content2')
     382
     383        stream = StringIO()
     384        connection = mail.get_connection(
     385            'django.core.mail.backends.console.EmailBackend', stream=stream)
     386        old_admins = settings.ADMINS
     387        settings.ADMINS = [('nobody','nobody@example.com')]
     388        try:
     389            mail_admins('Subject', 'Content', connection=connection)
     390        finally:
     391            settings.ADMINS = old_admins
     392        message = message_from_string(stream.getvalue())
     393        self.assertEqual(message['From'], 'root@localhost')
     394        self.assertEqual(message['To'], 'nobody@example.com')
     395
     396        stream = StringIO()
     397        connection = mail.get_connection(
     398            'django.core.mail.backends.console.EmailBackend', stream=stream)
     399        old_managers = settings.MANAGERS
     400        settings.MANAGERS = [('nobody','nobody@example.com')]
     401        try:
     402            mail_managers('Subject', 'Content', connection=connection)
     403        finally:
     404            settings.MANAGERS = old_managers
     405        message = message_from_string(stream.getvalue())
     406        self.assertEqual(message['From'], 'root@localhost')
     407        self.assertEqual(message['To'], 'nobody@example.com')
     408
     409    def test_cc(self):
     410        # Add Cc to the email argument list (#7722)
     411        email = EmailMessage('Subject', 'Content', 'from@example.com',
     412                             ['to@example.com'], cc=['cc@example.com'])
     413        message = email.message()
     414        self.assertEqual(message['Cc'], 'cc@example.com')
     415        self.assertEqual(email.recipients(), ['to@example.com',
     416                                              'cc@example.com'])
     417
     418        email = EmailMessage('Subject', 'Content', 'from@example.com',
     419                             ['to@example.com','other@example.com'],
     420                             cc=['cc@example.com', 'cc.other@example.com'])
     421        message = email.message()
     422        self.assertEqual(message['Cc'],
     423                         'cc@example.com, cc.other@example.com')
     424        self.assertEqual(email.recipients(),
     425                         ['to@example.com', 'other@example.com',
     426                          'cc@example.com', 'cc.other@example.com'])
     427
     428    def test_bcc(self):
     429        email = EmailMessage('Subject', 'Content', 'from@example.com',
     430                             ['to@example.com','other@example.com'],
     431                             cc=['cc@example.com', 'cc.other@example.com'],
     432                             bcc=['bcc@example.com'])
     433        self.assertEqual(email.recipients(),
     434                         ['to@example.com', 'other@example.com',
     435                          'cc@example.com', 'cc.other@example.com',
     436                          'bcc@example.com'])
Back to Top