Fixed #21271 -- Added timeout parameter to SMTP EmailBackend.
Thanks Tobias McNulty and Tim Graham for discussions and code review. Thanks Andre Cruz the suggestion and initial patch.
This commit is contained in:
parent
9eecb91695
commit
4e0a2fe59c
|
@ -15,7 +15,8 @@ class EmailBackend(BaseEmailBackend):
|
|||
A wrapper that manages the SMTP network connection.
|
||||
"""
|
||||
def __init__(self, host=None, port=None, username=None, password=None,
|
||||
use_tls=None, fail_silently=False, use_ssl=None, **kwargs):
|
||||
use_tls=None, fail_silently=False, use_ssl=None, timeout=None,
|
||||
**kwargs):
|
||||
super(EmailBackend, self).__init__(fail_silently=fail_silently)
|
||||
self.host = host or settings.EMAIL_HOST
|
||||
self.port = port or settings.EMAIL_PORT
|
||||
|
@ -23,6 +24,7 @@ class EmailBackend(BaseEmailBackend):
|
|||
self.password = settings.EMAIL_HOST_PASSWORD if password is None else password
|
||||
self.use_tls = settings.EMAIL_USE_TLS if use_tls is None else use_tls
|
||||
self.use_ssl = settings.EMAIL_USE_SSL if use_ssl is None else use_ssl
|
||||
self.timeout = timeout
|
||||
if self.use_ssl and self.use_tls:
|
||||
raise ValueError(
|
||||
"EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set "
|
||||
|
@ -38,24 +40,22 @@ class EmailBackend(BaseEmailBackend):
|
|||
if self.connection:
|
||||
# Nothing to do if the connection is already open.
|
||||
return False
|
||||
try:
|
||||
|
||||
connection_class = smtplib.SMTP_SSL if self.use_ssl else smtplib.SMTP
|
||||
# If local_hostname is not specified, socket.getfqdn() gets used.
|
||||
# For performance, we use the cached FQDN for local_hostname.
|
||||
if self.use_ssl:
|
||||
self.connection = smtplib.SMTP_SSL(self.host, self.port,
|
||||
local_hostname=DNS_NAME.get_fqdn())
|
||||
else:
|
||||
self.connection = smtplib.SMTP(self.host, self.port,
|
||||
local_hostname=DNS_NAME.get_fqdn())
|
||||
connection_params = {'local_hostname': DNS_NAME.get_fqdn()}
|
||||
if self.timeout is not None:
|
||||
connection_params['timeout'] = self.timeout
|
||||
try:
|
||||
self.connection = connection_class(self.host, self.port, **connection_params)
|
||||
|
||||
# TLS/SSL are mutually exclusive, so only attempt TLS over
|
||||
# non-secure connections.
|
||||
if self.use_tls:
|
||||
if not self.use_ssl and self.use_tls:
|
||||
self.connection.ehlo()
|
||||
self.connection.starttls()
|
||||
self.connection.ehlo()
|
||||
if self.username and self.password:
|
||||
self.connection.login(self.username, self.password)
|
||||
return True
|
||||
except smtplib.SMTPException:
|
||||
if not self.fail_silently:
|
||||
raise
|
||||
|
|
|
@ -248,6 +248,8 @@ Email
|
|||
|
||||
* :func:`~django.core.mail.send_mail` now accepts an ``html_message``
|
||||
parameter for sending a multipart ``text/plain`` and ``text/html`` email.
|
||||
* The SMTP :class:`~django.core.mail.backends.smtp.EmailBackend` now accepts a
|
||||
:attr:`~django.core.mail.backends.smtp.EmailBackend.timeout` parameter.
|
||||
|
||||
File Uploads
|
||||
^^^^^^^^^^^^
|
||||
|
|
|
@ -424,17 +424,39 @@ can :ref:`write your own email backend <topic-custom-email-backend>`.
|
|||
SMTP backend
|
||||
~~~~~~~~~~~~
|
||||
|
||||
This is the default backend. Email will be sent through a SMTP server.
|
||||
The server address and authentication credentials are set in the
|
||||
:setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`,
|
||||
:setting:`EMAIL_HOST_PASSWORD`, :setting:`EMAIL_USE_TLS` and
|
||||
:setting:`EMAIL_USE_SSL` settings in your settings file.
|
||||
.. class:: backends.smtp.EmailBackend([host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, **kwargs])
|
||||
|
||||
The SMTP backend is the default configuration inherited by Django. If you
|
||||
want to specify it explicitly, put the following in your settings::
|
||||
This is the default backend. Email will be sent through a SMTP server.
|
||||
The server address and authentication credentials are set in the
|
||||
:setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`,
|
||||
:setting:`EMAIL_HOST_PASSWORD`, :setting:`EMAIL_USE_TLS` and
|
||||
:setting:`EMAIL_USE_SSL` settings in your settings file.
|
||||
|
||||
The SMTP backend is the default configuration inherited by Django. If you
|
||||
want to specify it explicitly, put the following in your settings::
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
Here is an attribute which doesn't have a corresponding settting like the
|
||||
others described above:
|
||||
|
||||
.. attribute:: timeout
|
||||
|
||||
.. versionadded:: 1.7
|
||||
|
||||
This backend contains a ``timeout`` parameter, which can be set with
|
||||
the following sample code::
|
||||
|
||||
from django.core.mail.backends import smtp
|
||||
|
||||
class MyEmailBackend(smtp.EmailBackend):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('timeout', 42)
|
||||
super(MyEmailBackend, self).__init__(*args, **kwargs)
|
||||
|
||||
Then point the :setting:`EMAIL_BACKEND` setting at your custom backend as
|
||||
described above.
|
||||
|
||||
.. _topic-email-console-backend:
|
||||
|
||||
Console backend
|
||||
|
|
|
@ -933,3 +933,20 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase):
|
|||
backend = smtp.EmailBackend()
|
||||
self.assertTrue(backend.use_ssl)
|
||||
self.assertRaises(SSLError, backend.open)
|
||||
|
||||
def test_connection_timeout_default(self):
|
||||
"""Test that the connection's timeout value is None by default."""
|
||||
connection = mail.get_connection('django.core.mail.backends.smtp.EmailBackend')
|
||||
self.assertEqual(connection.timeout, None)
|
||||
|
||||
def test_connection_timeout_custom(self):
|
||||
"""Test that the timeout parameter can be customized."""
|
||||
class MyEmailBackend(smtp.EmailBackend):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('timeout', 42)
|
||||
super(MyEmailBackend, self).__init__(*args, **kwargs)
|
||||
|
||||
myemailbackend = MyEmailBackend()
|
||||
myemailbackend.open()
|
||||
self.assertEqual(myemailbackend.timeout, 42)
|
||||
self.assertEqual(myemailbackend.connection.timeout, 42)
|
||||
|
|
Loading…
Reference in New Issue