Ticket #17471: patch_ticket_17471_c.txt

File patch_ticket_17471_c.txt, 8.1 KB (added by senko, 11 years ago)

Update to previous patch to suppress UnicodeDecodeError

Line 
1diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
2index bf0dea5..19258fb 100644
3--- a/django/conf/global_settings.py
4+++ b/django/conf/global_settings.py
5@@ -184,6 +184,7 @@ EMAIL_PORT = 25
6 EMAIL_HOST_USER = ''
7 EMAIL_HOST_PASSWORD = ''
8 EMAIL_USE_TLS = False
9+EMAIL_USE_SSL = False
10
11 # List of strings representing installed apps.
12 INSTALLED_APPS = ()
13diff --git a/django/core/mail/backends/smtp.py b/django/core/mail/backends/smtp.py
14index e456b78..fc77080 100644
15--- a/django/core/mail/backends/smtp.py
16+++ b/django/core/mail/backends/smtp.py
17@@ -15,7 +15,7 @@ class EmailBackend(BaseEmailBackend):
18 A wrapper that manages the SMTP network connection.
19 """
20 def __init__(self, host=None, port=None, username=None, password=None,
21- use_tls=None, fail_silently=False, **kwargs):
22+ use_tls=None, fail_silently=False, use_ssl=None, **kwargs):
23 super(EmailBackend, self).__init__(fail_silently=fail_silently)
24 self.host = host or settings.EMAIL_HOST
25 self.port = port or settings.EMAIL_PORT
26@@ -31,6 +31,13 @@ class EmailBackend(BaseEmailBackend):
27 self.use_tls = settings.EMAIL_USE_TLS
28 else:
29 self.use_tls = use_tls
30+ if use_ssl is None:
31+ self.use_ssl = settings.EMAIL_USE_SSL
32+ else:
33+ self.use_ssl = use_ssl
34+ if self.use_ssl and self.use_tls:
35+ raise ValueError(
36+ "EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set one of those settings to True.")
37 self.connection = None
38 self._lock = threading.RLock()
39
40@@ -45,12 +52,18 @@ class EmailBackend(BaseEmailBackend):
41 try:
42 # If local_hostname is not specified, socket.getfqdn() gets used.
43 # For performance, we use the cached FQDN for local_hostname.
44- self.connection = smtplib.SMTP(self.host, self.port,
45+ if self.use_ssl:
46+ self.connection = smtplib.SMTP_SSL(self.host, self.port,
47+ local_hostname=DNS_NAME.get_fqdn())
48+ else:
49+ self.connection = smtplib.SMTP(self.host, self.port,
50 local_hostname=DNS_NAME.get_fqdn())
51- if self.use_tls:
52- self.connection.ehlo()
53- self.connection.starttls()
54- self.connection.ehlo()
55+ # TLS/SSL are mutually exclusive, so only attempt TLS over
56+ # non-secure connections.
57+ if self.use_tls:
58+ self.connection.ehlo()
59+ self.connection.starttls()
60+ self.connection.ehlo()
61 if self.username and self.password:
62 self.connection.login(self.username, self.password)
63 return True
64diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
65index 30e7e84..350e8ec 100644
66--- a/docs/ref/settings.txt
67+++ b/docs/ref/settings.txt
68@@ -1055,6 +1055,26 @@ EMAIL_USE_TLS
69 Default: ``False``
70
71 Whether to use a TLS (secure) connection when talking to the SMTP server.
72+This is used for explicit TLS connections, generally on port 587. If you are
73+experiencing hanging connections, see the implicit TLS setting
74+:setting:`EMAIL_USE_SSL`.
75+
76+.. setting:: EMAIL_USE_SSL
77+
78+EMAIL_USE_SSL
79+-------------
80+
81+.. versionadded:: 1.6
82+
83+Default: ``False``
84+
85+Whether to use an implicit TLS (secure) connection when talking to the SMTP
86+server. In most email documentation this type of TLS connection is referred
87+to as SSL. It is generally used on port 465. If you are experiencing problems,
88+see the explicit TLS setting :setting:`EMAIL_USE_TLS`.
89+
90+Note that :setting:`EMAIL_USE_TLS`/:setting:`EMAIL_USE_SSL` are mutually
91+exclusive, so only set one of those settings to ``True``.
92
93 .. setting:: FILE_CHARSET
94
95diff --git a/docs/topics/email.txt b/docs/topics/email.txt
96index b3d7254..8bf501c 100644
97--- a/docs/topics/email.txt
98+++ b/docs/topics/email.txt
99@@ -27,7 +27,8 @@ Mail is sent using the SMTP host and port specified in the
100 :setting:`EMAIL_HOST` and :setting:`EMAIL_PORT` settings. The
101 :setting:`EMAIL_HOST_USER` and :setting:`EMAIL_HOST_PASSWORD` settings, if
102 set, are used to authenticate to the SMTP server, and the
103-:setting:`EMAIL_USE_TLS` setting controls whether a secure connection is used.
104+:setting:`EMAIL_USE_TLS` and :setting:`EMAIL_USE_SSL` settings control whether
105+a secure connection is used.
106
107 .. note::
108
109@@ -408,8 +409,8 @@ SMTP backend
110 This is the default backend. Email will be sent through a SMTP server.
111 The server address and authentication credentials are set in the
112 :setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`,
113-:setting:`EMAIL_HOST_PASSWORD` and :setting:`EMAIL_USE_TLS` settings in your
114-settings file.
115+:setting:`EMAIL_HOST_PASSWORD`, :setting:`EMAIL_USE_TLS` and
116+:setting:`EMAIL_USE_SSL` settings in your settings file.
117
118 The SMTP backend is the default configuration inherited by Django. If you
119 want to specify it explicitly, put the following in your settings::
120diff --git a/tests/mail/tests.py b/tests/mail/tests.py
121index c90dc7e..822c572 100644
122--- a/tests/mail/tests.py
123+++ b/tests/mail/tests.py
124@@ -9,6 +9,8 @@ import smtpd
125 import sys
126 import tempfile
127 import threading
128+from smtplib import SMTPException
129+from ssl import SSLError
130
131 from django.core import mail
132 from django.core.mail import (EmailMessage, mail_admins, mail_managers,
133@@ -621,11 +623,23 @@ class ConsoleBackendTests(BaseEmailBackendTests, TestCase):
134 self.assertTrue(s.getvalue().startswith('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: '))
135
136
137+class FakeSMTPChannel(smtpd.SMTPChannel):
138+
139+ def collect_incoming_data(self, data):
140+ try:
141+ super(FakeSMTPChannel, self).collect_incoming_data(data)
142+ except UnicodeDecodeError:
143+ # ignore decode error in SSL/TLS connection tests as we only care
144+ # whether the connection attempt was made
145+ pass
146+
147+
148 class FakeSMTPServer(smtpd.SMTPServer, threading.Thread):
149 """
150 Asyncore SMTP server wrapped into a thread. Based on DummyFTPServer from:
151 http://svn.python.org/view/python/branches/py3k/Lib/test/test_ftplib.py?revision=86061&view=markup
152 """
153+ channel_class = FakeSMTPChannel
154
155 def __init__(self, *args, **kwargs):
156 threading.Thread.__init__(self)
157@@ -738,3 +752,44 @@ class SMTPBackendTests(BaseEmailBackendTests, TestCase):
158 backend.close()
159 except Exception as e:
160 self.fail("close() unexpectedly raised an exception: %s" % e)
161+
162+ @override_settings(EMAIL_USE_TLS=True)
163+ def test_email_tls_use_settings(self):
164+ backend = smtp.EmailBackend()
165+ self.assertTrue(backend.use_tls)
166+
167+ @override_settings(EMAIL_USE_TLS=True)
168+ def test_email_tls_override_settings(self):
169+ backend = smtp.EmailBackend(use_tls=False)
170+ self.assertFalse(backend.use_tls)
171+
172+ def test_email_tls_default_disabled(self):
173+ backend = smtp.EmailBackend()
174+ self.assertFalse(backend.use_tls)
175+
176+ @override_settings(EMAIL_USE_SSL=True)
177+ def test_email_ssl_use_settings(self):
178+ backend = smtp.EmailBackend()
179+ self.assertTrue(backend.use_ssl)
180+
181+ @override_settings(EMAIL_USE_SSL=True)
182+ def test_email_ssl_override_settings(self):
183+ backend = smtp.EmailBackend(use_ssl=False)
184+ self.assertFalse(backend.use_ssl)
185+
186+ def test_email_ssl_default_disabled(self):
187+ backend = smtp.EmailBackend()
188+ self.assertFalse(backend.use_ssl)
189+
190+ @override_settings(EMAIL_USE_TLS=True)
191+ def test_email_tls_attempts_starttls(self):
192+ backend = smtp.EmailBackend()
193+ self.assertTrue(backend.use_tls)
194+ self.assertRaisesMessage(SMTPException,
195+ 'STARTTLS extension not supported by server.', backend.open)
196+
197+ @override_settings(EMAIL_USE_SSL=True)
198+ def test_email_ssl_attempts_ssl_connection(self):
199+ backend = smtp.EmailBackend()
200+ self.assertTrue(backend.use_ssl)
201+ self.assertRaises(SSLError, backend.open)
Back to Top