~ubuntu-branches/ubuntu/saucy/python-django/saucy-updates

« back to all changes in this revision

Viewing changes to tests/regressiontests/mail/tests.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone, Jakub Wilk, Luke Faraone
  • Date: 2013-05-09 15:10:47 UTC
  • mfrom: (1.1.21) (4.4.27 sid)
  • Revision ID: package-import@ubuntu.com-20130509151047-aqv8d71oj9wvcv8c
Tags: 1.5.1-2
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Luke Faraone ]
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# coding: utf-8
 
2
from __future__ import unicode_literals
 
3
 
2
4
import asyncore
3
5
import email
4
6
import os
5
7
import shutil
6
8
import smtpd
7
9
import sys
8
 
from StringIO import StringIO
9
10
import tempfile
10
11
import threading
11
12
 
16
17
from django.core.mail.message import BadHeaderError
17
18
from django.test import TestCase
18
19
from django.test.utils import override_settings
 
20
from django.utils.encoding import force_str, force_text
 
21
from django.utils.six import PY3, StringIO
19
22
from django.utils.translation import ugettext_lazy
20
23
 
21
24
 
27
30
    def test_ascii(self):
28
31
        email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'])
29
32
        message = email.message()
30
 
        self.assertEqual(message['Subject'].encode(), 'Subject')
 
33
        self.assertEqual(message['Subject'], 'Subject')
31
34
        self.assertEqual(message.get_payload(), 'Content')
32
35
        self.assertEqual(message['From'], 'from@example.com')
33
36
        self.assertEqual(message['To'], 'to@example.com')
35
38
    def test_multiple_recipients(self):
36
39
        email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com', 'other@example.com'])
37
40
        message = email.message()
38
 
        self.assertEqual(message['Subject'].encode(), 'Subject')
 
41
        self.assertEqual(message['Subject'], 'Subject')
39
42
        self.assertEqual(message.get_payload(), 'Content')
40
43
        self.assertEqual(message['From'], 'from@example.com')
41
44
        self.assertEqual(message['To'], 'to@example.com, other@example.com')
75
78
        """
76
79
        Test for space continuation character in long (ascii) subject headers (#7747)
77
80
        """
78
 
        email = EmailMessage('Long subject lines that get wrapped should use a space continuation character to get expected behavior in Outlook and Thunderbird', 'Content', 'from@example.com', ['to@example.com'])
 
81
        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'])
79
82
        message = email.message()
80
 
        self.assertEqual(message['Subject'], 'Long subject lines that get wrapped should use a space continuation\n character to get expected behavior in Outlook and Thunderbird')
 
83
        # Note that in Python 3, maximum line length has increased from 76 to 78
 
84
        self.assertEqual(message['Subject'].encode(), b'Long subject lines that get wrapped should contain a space continuation\n character to get expected behavior in Outlook and Thunderbird')
81
85
 
82
86
    def test_message_header_overrides(self):
83
87
        """
86
90
        """
87
91
        headers = {"date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
88
92
        email = EmailMessage('subject', 'content', 'from@example.com', ['to@example.com'], headers=headers)
89
 
        self.assertEqual(email.message().as_string(), 'Content-Type: text/plain; charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nSubject: subject\nFrom: from@example.com\nTo: to@example.com\ndate: Fri, 09 Nov 2001 01:08:47 -0000\nMessage-ID: foo\n\ncontent')
 
93
 
 
94
        self.assertEqual(sorted(email.message().items()), [
 
95
            ('Content-Transfer-Encoding', '7bit'),
 
96
            ('Content-Type', 'text/plain; charset="utf-8"'),
 
97
            ('From', 'from@example.com'),
 
98
            ('MIME-Version', '1.0'),
 
99
            ('Message-ID', 'foo'),
 
100
            ('Subject', 'subject'),
 
101
            ('To', 'to@example.com'),
 
102
            ('date', 'Fri, 09 Nov 2001 01:08:47 -0000'),
 
103
        ])
90
104
 
91
105
    def test_from_header(self):
92
106
        """
137
151
        self.assertEqual(email.message()['To'], '=?utf-8?q?S=C3=BCrname=2C_Firstname?= <to@example.com>, other@example.com')
138
152
 
139
153
    def test_unicode_headers(self):
140
 
        email = EmailMessage(u"Gżegżółka", "Content", "from@example.com", ["to@example.com"],
 
154
        email = EmailMessage("Gżegżółka", "Content", "from@example.com", ["to@example.com"],
141
155
                             headers={"Sender": '"Firstname Sürname" <sender@example.com>',
142
156
                                      "Comments": 'My Sürname is non-ASCII'})
143
157
        message = email.message()
158
172
        msg.attach_alternative(html_content, "text/html")
159
173
        msg.encoding = 'iso-8859-1'
160
174
        self.assertEqual(msg.message()['To'], '=?iso-8859-1?q?S=FCrname=2C_Firstname?= <to@example.com>')
161
 
        self.assertEqual(msg.message()['Subject'].encode(), u'=?iso-8859-1?q?Message_from_Firstname_S=FCrname?=')
 
175
        self.assertEqual(msg.message()['Subject'], '=?iso-8859-1?q?Message_from_Firstname_S=FCrname?=')
162
176
 
163
177
    def test_encoding(self):
164
178
        """
188
202
        html_content = '<p>This is an <strong>important</strong> message.</p>'
189
203
        msg = EmailMultiAlternatives(subject, text_content, from_email, [to], headers=headers)
190
204
        msg.attach_alternative(html_content, "text/html")
191
 
        msg.attach("an attachment.pdf", "%PDF-1.4.%...", mimetype="application/pdf")
 
205
        msg.attach("an attachment.pdf", b"%PDF-1.4.%...", mimetype="application/pdf")
192
206
        msg_str = msg.message().as_string()
193
207
        message = email.message_from_string(msg_str)
194
208
        self.assertTrue(message.is_multipart())
205
219
        content = 'This is the message.'
206
220
        msg = EmailMessage(subject, content, from_email, [to], headers=headers)
207
221
        # Unicode in file name
208
 
        msg.attach(u"une pièce jointe.pdf", "%PDF-1.4.%...", mimetype="application/pdf")
 
222
        msg.attach("une pièce jointe.pdf", b"%PDF-1.4.%...", mimetype="application/pdf")
209
223
        msg_str = msg.message().as_string()
210
224
        message = email.message_from_string(msg_str)
211
225
        payload = message.get_payload()
212
 
        self.assertEqual(payload[1].get_filename(), u'une pièce jointe.pdf')
 
226
        self.assertEqual(payload[1].get_filename(), 'une pièce jointe.pdf')
213
227
 
214
228
    def test_dummy_backend(self):
215
229
        """
307
321
        # Shouldn't use quoted printable, should detect it can represent content with 8 bit data
308
322
        msg = EmailMessage('Subject', 'Body with latin characters: àáä.', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
309
323
        s = msg.message().as_string()
310
 
        self.assertFalse('Content-Transfer-Encoding: quoted-printable' in s)
311
 
        self.assertTrue('Content-Transfer-Encoding: 8bit' in s)
 
324
        self.assertFalse(str('Content-Transfer-Encoding: quoted-printable') in s)
 
325
        self.assertTrue(str('Content-Transfer-Encoding: 8bit') in s)
312
326
 
313
 
        msg = EmailMessage('Subject', u'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
 
327
        msg = EmailMessage('Subject', 'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
314
328
        s = msg.message().as_string()
315
 
        self.assertFalse('Content-Transfer-Encoding: quoted-printable' in s)
316
 
        self.assertTrue('Content-Transfer-Encoding: 8bit' in s)
 
329
        self.assertFalse(str('Content-Transfer-Encoding: quoted-printable') in s)
 
330
        self.assertTrue(str('Content-Transfer-Encoding: 8bit') in s)
317
331
 
318
332
 
319
333
class BaseEmailBackendTests(object):
354
368
        self.assertEqual(message["from"], "from@example.com")
355
369
        self.assertEqual(message.get_all("to"), ["to@example.com"])
356
370
 
 
371
    def test_send_unicode(self):
 
372
        email = EmailMessage('Chère maman', 'Je t\'aime très fort', 'from@example.com', ['to@example.com'])
 
373
        num_sent = mail.get_connection().send_messages([email])
 
374
        self.assertEqual(num_sent, 1)
 
375
        message = self.get_the_message()
 
376
        self.assertEqual(message["subject"], '=?utf-8?q?Ch=C3=A8re_maman?=')
 
377
        self.assertEqual(force_text(message.get_payload()), 'Je t\'aime très fort')
 
378
 
357
379
    def test_send_many(self):
358
380
        email1 = EmailMessage('Subject', 'Content1', 'from@example.com', ['to@example.com'])
359
381
        email2 = EmailMessage('Subject', 'Content2', 'from@example.com', ['to@example.com'])
444
466
        """
445
467
        Regression test for #14301
446
468
        """
447
 
        self.assertTrue(send_mail('Subject', 'Content', 'from@öäü.com', [u'to@öäü.com']))
 
469
        self.assertTrue(send_mail('Subject', 'Content', 'from@öäü.com', ['to@öäü.com']))
448
470
        message = self.get_the_message()
449
471
        self.assertEqual(message.get('subject'), 'Subject')
450
472
        self.assertEqual(message.get('from'), 'from@xn--4ca9at.com')
452
474
 
453
475
        self.flush_mailbox()
454
476
        m = EmailMessage('Subject', 'Content', 'from@öäü.com',
455
 
                     [u'to@öäü.com'], cc=[u'cc@öäü.com'])
 
477
                     ['to@öäü.com'], cc=['cc@öäü.com'])
456
478
        m.send()
457
479
        message = self.get_the_message()
458
480
        self.assertEqual(message.get('subject'), 'Subject')
470
492
        self.assertEqual(message.get('from'), "tester")
471
493
        self.assertEqual(message.get('to'), "django")
472
494
 
 
495
    def test_close_connection(self):
 
496
        """
 
497
        Test that connection can be closed (even when not explicitely opened)
 
498
        """
 
499
        conn = mail.get_connection(username='', password='')
 
500
        try:
 
501
            conn.close()
 
502
        except Exception as e:
 
503
            self.fail("close() unexpectedly raised an exception: %s" % e)
 
504
 
473
505
 
474
506
class LocmemBackendTests(BaseEmailBackendTests, TestCase):
475
507
    email_backend = 'django.core.mail.backends.locmem.EmailBackend'
495
527
        connection2.send_messages([email])
496
528
        self.assertEqual(len(mail.outbox), 2)
497
529
 
 
530
    def test_validate_multiline_headers(self):
 
531
        # Ticket #18861 - Validate emails when using the locmem backend
 
532
        with self.assertRaises(BadHeaderError):
 
533
            send_mail('Subject\nMultiline', 'Content', 'from@example.com', ['to@example.com'])
 
534
 
498
535
 
499
536
class FileBackendTests(BaseEmailBackendTests, TestCase):
500
537
    email_backend = 'django.core.mail.backends.filebased.EmailBackend'
501
538
 
502
539
    def setUp(self):
 
540
        super(FileBackendTests, self).setUp()
503
541
        self.tmp_dir = tempfile.mkdtemp()
504
542
        self.addCleanup(shutil.rmtree, self.tmp_dir)
505
 
        self.settings_override = override_settings(EMAIL_FILE_PATH=self.tmp_dir)
506
 
        self.settings_override.enable()
507
 
        super(FileBackendTests, self).setUp()
 
543
        self._settings_override = override_settings(EMAIL_FILE_PATH=self.tmp_dir)
 
544
        self._settings_override.enable()
508
545
 
509
546
    def tearDown(self):
510
 
        self.settings_override.disable()
 
547
        self._settings_override.disable()
511
548
        super(FileBackendTests, self).tearDown()
512
549
 
513
550
    def flush_mailbox(self):
517
554
    def get_mailbox_content(self):
518
555
        messages = []
519
556
        for filename in os.listdir(self.tmp_dir):
520
 
            session = open(os.path.join(self.tmp_dir, filename)).read().split('\n' + ('-' * 79) + '\n')
521
 
            messages.extend(email.message_from_string(m) for m in session if m)
 
557
            with open(os.path.join(self.tmp_dir, filename), 'r') as fp:
 
558
                session = force_text(fp.read()).split('\n' + ('-' * 79) + '\n')
 
559
            messages.extend(email.message_from_string(force_str(m)) for m in session if m)
522
560
        return messages
523
561
 
524
562
    def test_file_sessions(self):
528
566
        connection.send_messages([msg])
529
567
 
530
568
        self.assertEqual(len(os.listdir(self.tmp_dir)), 1)
531
 
        message = email.message_from_file(open(os.path.join(self.tmp_dir, os.listdir(self.tmp_dir)[0])))
 
569
        with open(os.path.join(self.tmp_dir, os.listdir(self.tmp_dir)[0])) as fp:
 
570
            message = email.message_from_file(fp)
532
571
        self.assertEqual(message.get_content_type(), 'text/plain')
533
572
        self.assertEqual(message.get('subject'), 'Subject')
534
573
        self.assertEqual(message.get('from'), 'from@example.com')
548
587
        msg.send()
549
588
        self.assertEqual(len(os.listdir(self.tmp_dir)), 3)
550
589
 
 
590
        connection.close()
 
591
 
551
592
 
552
593
class ConsoleBackendTests(BaseEmailBackendTests, TestCase):
553
594
    email_backend = 'django.core.mail.backends.console.EmailBackend'
567
608
        self.stream = sys.stdout = StringIO()
568
609
 
569
610
    def get_mailbox_content(self):
570
 
        messages = self.stream.getvalue().split('\n' + ('-' * 79) + '\n')
571
 
        return [email.message_from_string(m) for m in messages if m]
 
611
        messages = force_text(self.stream.getvalue()).split('\n' + ('-' * 79) + '\n')
 
612
        return [email.message_from_string(force_str(m)) for m in messages if m]
572
613
 
573
614
    def test_console_stream_kwarg(self):
574
615
        """
596
637
 
597
638
    def process_message(self, peer, mailfrom, rcpttos, data):
598
639
        m = email.message_from_string(data)
599
 
        maddr = email.Utils.parseaddr(m.get('from'))[1]
 
640
        if PY3:
 
641
            maddr = email.utils.parseaddr(m.get('from'))[1]
 
642
        else:
 
643
            maddr = email.Utils.parseaddr(m.get('from'))[1]
600
644
        if mailfrom != maddr:
601
645
            return "553 '%s' != '%s'" % (mailfrom, maddr)
602
 
        self.sink_lock.acquire()
603
 
        self._sink.append(m)
604
 
        self.sink_lock.release()
 
646
        with self.sink_lock:
 
647
            self._sink.append(m)
605
648
 
606
649
    def get_sink(self):
607
 
        self.sink_lock.acquire()
608
 
        try:
 
650
        with self.sink_lock:
609
651
            return self._sink[:]
610
 
        finally:
611
 
            self.sink_lock.release()
612
652
 
613
653
    def flush_sink(self):
614
 
        self.sink_lock.acquire()
615
 
        self._sink[:] = []
616
 
        self.sink_lock.release()
 
654
        with self.sink_lock:
 
655
            self._sink[:] = []
617
656
 
618
657
    def start(self):
619
658
        assert not self.active
625
664
        self.active = True
626
665
        self.__flag.set()
627
666
        while self.active and asyncore.socket_map:
628
 
            self.active_lock.acquire()
629
 
            asyncore.loop(timeout=0.1, count=1)
630
 
            self.active_lock.release()
 
667
            with self.active_lock:
 
668
                asyncore.loop(timeout=0.1, count=1)
631
669
        asyncore.close_all()
632
670
 
633
671
    def stop(self):
634
 
        assert self.active
635
 
        self.active = False
636
 
        self.join()
 
672
        if self.active:
 
673
            self.active = False
 
674
            self.join()
637
675
 
638
676
 
639
677
class SMTPBackendTests(BaseEmailBackendTests, TestCase):
642
680
    @classmethod
643
681
    def setUpClass(cls):
644
682
        cls.server = FakeSMTPServer(('127.0.0.1', 0), None)
645
 
        cls.settings_override = override_settings(
 
683
        cls._settings_override = override_settings(
646
684
            EMAIL_HOST="127.0.0.1",
647
685
            EMAIL_PORT=cls.server.socket.getsockname()[1])
648
 
        cls.settings_override.enable()
 
686
        cls._settings_override.enable()
649
687
        cls.server.start()
650
688
 
651
689
    @classmethod
652
690
    def tearDownClass(cls):
653
 
        cls.settings_override.disable()
 
691
        cls._settings_override.disable()
654
692
        cls.server.stop()
655
693
 
656
694
    def setUp(self):
687
725
        backend = smtp.EmailBackend(username='', password='')
688
726
        self.assertEqual(backend.username, '')
689
727
        self.assertEqual(backend.password, '')
 
728
 
 
729
    def test_server_stopped(self):
 
730
        """
 
731
        Test that closing the backend while the SMTP server is stopped doesn't
 
732
        raise an exception.
 
733
        """
 
734
        backend = smtp.EmailBackend(username='', password='')
 
735
        backend.open()
 
736
        self.server.stop()
 
737
        try:
 
738
            backend.close()
 
739
        except Exception as e:
 
740
            self.fail("close() unexpectedly raised an exception: %s" % e)