1
0
mirror of https://github.com/django/django.git synced 2025-03-31 11:37:06 +00:00

Fixed 35653 -- Added ssl_cafile to smtp email backend.

This commit is contained in:
Igor Scheller 2024-08-07 13:49:15 +02:00
parent 58e548db8b
commit 495420eec3
6 changed files with 45 additions and 5 deletions

View File

@ -206,6 +206,7 @@ EMAIL_HOST_USER = ""
EMAIL_HOST_PASSWORD = ""
EMAIL_USE_TLS = False
EMAIL_USE_SSL = False
EMAIL_SSL_CAFILE = None
EMAIL_SSL_CERTFILE = None
EMAIL_SSL_KEYFILE = None
EMAIL_TIMEOUT = None

View File

@ -28,6 +28,7 @@ class EmailBackend(BaseEmailBackend):
timeout=None,
ssl_keyfile=None,
ssl_certfile=None,
ssl_cafile=None,
**kwargs,
):
super().__init__(fail_silently=fail_silently)
@ -44,6 +45,9 @@ class EmailBackend(BaseEmailBackend):
self.ssl_certfile = (
settings.EMAIL_SSL_CERTFILE if ssl_certfile is None else ssl_certfile
)
self.ssl_cafile = (
settings.EMAIL_SSL_CAFILE if ssl_cafile is None else ssl_cafile
)
if self.use_ssl and self.use_tls:
raise ValueError(
"EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set "
@ -61,9 +65,13 @@ class EmailBackend(BaseEmailBackend):
if self.ssl_certfile or self.ssl_keyfile:
ssl_context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT)
ssl_context.load_cert_chain(self.ssl_certfile, self.ssl_keyfile)
return ssl_context
else:
return ssl.create_default_context()
ssl_context = ssl.create_default_context()
if self.ssl_cafile:
ssl_context.load_verify_locations(cafile=self.ssl_cafile)
return ssl_context
def open(self):
"""

View File

@ -1495,6 +1495,17 @@ 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_CAFILE
``EMAIL_SSL_CAFILE``
----------------------
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 authority
root certificate to validate the SSL connection.
.. setting:: EMAIL_SSL_CERTFILE
``EMAIL_SSL_CERTFILE``
@ -1517,8 +1528,9 @@ 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
Note that setting :setting:`EMAIL_SSL_CERTFILE`, :setting:`EMAIL_SSL_KEYFILE`
or :setting:`EMAIL_SSL_CAFILE` doesn't result in any certificate checking.
They're passed to the underlying SSL
connection. Please refer to the documentation of Python's
:meth:`python:ssl.SSLContext.wrap_socket` function for details on how the
certificate chain file and private key file are handled.
@ -3631,6 +3643,7 @@ Email
* :setting:`EMAIL_HOST_PASSWORD`
* :setting:`EMAIL_HOST_USER`
* :setting:`EMAIL_PORT`
* :setting:`EMAIL_SSL_CAFILE`
* :setting:`EMAIL_SSL_CERTFILE`
* :setting:`EMAIL_SSL_KEYFILE`
* :setting:`EMAIL_SUBJECT_PREFIX`

View File

@ -220,6 +220,9 @@ Email
returns a boolean indicating whether a provided text is contained in the
email ``body`` and in all attached MIME type ``text/*`` alternatives.
* The SMTP email backend now supports certificate validation using a ``cafile``
with the :setting:`EMAIL_SSL_CAFILE` setting.
Error Reporting
~~~~~~~~~~~~~~~

View File

@ -605,7 +605,7 @@ 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, ssl_keyfile=None, ssl_certfile=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, ssl_cafile=None, **kwargs)
This is the default backend. Email will be sent through a SMTP server.
@ -621,6 +621,7 @@ SMTP backend
* ``timeout``: :setting:`EMAIL_TIMEOUT`
* ``ssl_keyfile``: :setting:`EMAIL_SSL_KEYFILE`
* ``ssl_certfile``: :setting:`EMAIL_SSL_CERTFILE`
* ``ssl_cafile``: :setting:`EMAIL_SSL_CAFILE`
The SMTP backend is the default configuration inherited by Django. If you
want to specify it explicitly, put the following in your settings::

View File

@ -2269,16 +2269,30 @@ class SMTPBackendTests(BaseEmailBackendTests, SMTPBackendTestsBase):
backend = smtp.EmailBackend()
self.assertFalse(backend.use_ssl)
@override_settings(EMAIL_SSL_CAFILE="foo")
def test_email_ssl_cafile_use_settings(self):
backend = smtp.EmailBackend()
self.assertEqual(backend.ssl_cafile, "foo")
@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_CAFILE="foo")
def test_email_ssl_cafile_override_settings(self):
backend = smtp.EmailBackend(ssl_cafile="bar")
self.assertEqual(backend.ssl_cafile, "bar")
@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_cafile_default_disabled(self):
backend = smtp.EmailBackend()
self.assertIsNone(backend.ssl_cafile)
def test_email_ssl_certfile_default_disabled(self):
backend = smtp.EmailBackend()
self.assertIsNone(backend.ssl_certfile)