Fixed #20743 -- Added support for keyfile/certfile in SMTP connections.
Thanks jwmayfield, serg.partizan, and Wojciech Banaś for work on the patch.
This commit is contained in:
parent
61f56e239f
commit
00535e8e6b
|
@ -194,6 +194,8 @@ EMAIL_HOST_USER = ''
|
|||
EMAIL_HOST_PASSWORD = ''
|
||||
EMAIL_USE_TLS = False
|
||||
EMAIL_USE_SSL = False
|
||||
EMAIL_SSL_CERTFILE = None
|
||||
EMAIL_SSL_KEYFILE = None
|
||||
|
||||
# List of strings representing installed apps.
|
||||
INSTALLED_APPS = ()
|
||||
|
|
|
@ -15,6 +15,7 @@ class EmailBackend(BaseEmailBackend):
|
|||
"""
|
||||
def __init__(self, host=None, port=None, username=None, password=None,
|
||||
use_tls=None, fail_silently=False, use_ssl=None, timeout=None,
|
||||
ssl_keyfile=None, ssl_certfile=None,
|
||||
**kwargs):
|
||||
super(EmailBackend, self).__init__(fail_silently=fail_silently)
|
||||
self.host = host or settings.EMAIL_HOST
|
||||
|
@ -24,6 +25,8 @@ class EmailBackend(BaseEmailBackend):
|
|||
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
|
||||
self.ssl_keyfile = settings.EMAIL_SSL_KEYFILE if ssl_keyfile is None else ssl_keyfile
|
||||
self.ssl_certfile = settings.EMAIL_SSL_CERTFILE if ssl_certfile is None else ssl_certfile
|
||||
if self.use_ssl and self.use_tls:
|
||||
raise ValueError(
|
||||
"EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set "
|
||||
|
@ -46,6 +49,11 @@ class EmailBackend(BaseEmailBackend):
|
|||
connection_params = {'local_hostname': DNS_NAME.get_fqdn()}
|
||||
if self.timeout is not None:
|
||||
connection_params['timeout'] = self.timeout
|
||||
if self.use_ssl:
|
||||
connection_params.update({
|
||||
'keyfile': self.ssl_keyfile,
|
||||
'certfile': self.ssl_certfile,
|
||||
})
|
||||
try:
|
||||
self.connection = connection_class(self.host, self.port, **connection_params)
|
||||
|
||||
|
@ -53,7 +61,7 @@ class EmailBackend(BaseEmailBackend):
|
|||
# non-secure connections.
|
||||
if not self.use_ssl and self.use_tls:
|
||||
self.connection.ehlo()
|
||||
self.connection.starttls()
|
||||
self.connection.starttls(keyfile=self.ssl_keyfile, certfile=self.ssl_certfile)
|
||||
self.connection.ehlo()
|
||||
if self.username and self.password:
|
||||
self.connection.login(self.username, self.password)
|
||||
|
|
|
@ -1228,6 +1228,38 @@ see the explicit TLS setting :setting:`EMAIL_USE_TLS`.
|
|||
Note that :setting:`EMAIL_USE_TLS`/:setting:`EMAIL_USE_SSL` are mutually
|
||||
exclusive, so only set one of those settings to ``True``.
|
||||
|
||||
.. setting:: EMAIL_SSL_CERTFILE
|
||||
|
||||
EMAIL_SSL_CERTFILE
|
||||
------------------
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
Default: ``None``
|
||||
|
||||
If :setting:`EMAIL_USE_SSL` or :setting:`EMAIL_USE_TLS` is ``True``, you can
|
||||
optionally specify the path to a PEM-formatted certificate chain file to use
|
||||
for the SSL connection.
|
||||
|
||||
.. setting:: EMAIL_SSL_KEYFILE
|
||||
|
||||
EMAIL_SSL_KEYFILE
|
||||
-----------------
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
Default: ``None``
|
||||
|
||||
If :setting:`EMAIL_USE_SSL` or :setting:`EMAIL_USE_TLS` is ``True``, you can
|
||||
optionally specify the path to a PEM-formatted private key file to use for the
|
||||
SSL connection.
|
||||
|
||||
Note that setting :setting:`EMAIL_SSL_CERTFILE` and :setting:`EMAIL_SSL_KEYFILE`
|
||||
doesn't result in any certificate checking. They're passed to the underlying SSL
|
||||
connection. Please refer to the documentation of Python's
|
||||
:func:`python:ssl.wrap_socket` function for details on how the certificate chain
|
||||
file and private key file are handled.
|
||||
|
||||
.. setting:: FILE_CHARSET
|
||||
|
||||
FILE_CHARSET
|
||||
|
@ -2926,6 +2958,8 @@ Email
|
|||
* :setting:`EMAIL_HOST_PASSWORD`
|
||||
* :setting:`EMAIL_HOST_USER`
|
||||
* :setting:`EMAIL_PORT`
|
||||
* :setting:`EMAIL_SSL_CERTFILE`
|
||||
* :setting:`EMAIL_SSL_KEYFILE`
|
||||
* :setting:`EMAIL_SUBJECT_PREFIX`
|
||||
* :setting:`EMAIL_USE_TLS`
|
||||
* :setting:`MANAGERS`
|
||||
|
|
|
@ -140,6 +140,10 @@ Email
|
|||
* :ref:`Email backends <topic-email-backends>` now support the context manager
|
||||
protocol for opening and closing connections.
|
||||
|
||||
* The SMTP email backend now supports ``keyfile`` and ``certfile``
|
||||
authentication with the :setting:`EMAIL_SSL_CERTFILE` and
|
||||
:setting:`EMAIL_SSL_KEYFILE` settings.
|
||||
|
||||
File Storage
|
||||
^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -426,6 +426,7 @@ Palau
|
|||
params
|
||||
parens
|
||||
pdf
|
||||
PEM
|
||||
perl
|
||||
permalink
|
||||
pessimization
|
||||
|
|
|
@ -445,13 +445,14 @@ can :ref:`write your own email backend <topic-custom-email-backend>`.
|
|||
SMTP backend
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. class:: backends.smtp.EmailBackend([host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, **kwargs])
|
||||
.. class:: backends.smtp.EmailBackend([host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs])
|
||||
|
||||
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.
|
||||
:setting:`EMAIL_HOST_PASSWORD`, :setting:`EMAIL_USE_TLS`,
|
||||
:setting:`EMAIL_USE_SSL`, :setting:`EMAIL_SSL_CERTFILE` and
|
||||
:setting:`EMAIL_SSL_KEYFILE` 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::
|
||||
|
@ -481,6 +482,11 @@ SMTP backend
|
|||
If unspecified, the default ``timeout`` will be the one provided by
|
||||
:func:`socket.getdefaulttimeout()`, which defaults to ``None`` (no timeout).
|
||||
|
||||
.. versionchanged:: 1.8
|
||||
|
||||
The ``ssl_keyfile`` and ``ssl_certfile`` parameters and
|
||||
corresponding settings were added.
|
||||
|
||||
.. _topic-email-console-backend:
|
||||
|
||||
Console backend
|
||||
|
|
|
@ -969,6 +969,34 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase):
|
|||
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.assertEqual(backend.ssl_certfile, None)
|
||||
|
||||
@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.assertEqual(backend.ssl_keyfile, None)
|
||||
|
||||
@override_settings(EMAIL_USE_TLS=True)
|
||||
def test_email_tls_attempts_starttls(self):
|
||||
backend = smtp.EmailBackend()
|
||||
|
|
Loading…
Reference in New Issue