[Django] #34504: SSLCertVerificationError on outgoing emails for some mailboxes

98 views
Skip to first unread message

Django

unread,
Apr 19, 2023, 5:16:21 AM4/19/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: bay-kamen | Owner: nobody
Type: Bug | Status: new
Component: Core | Version: 4.2
(Mail) | Keywords: smtplib, ssl,
Severity: Normal | Django4.2
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
It looks like this was previously reported in a different scenario and
marked as fixed but is still not working as expected. Downgrading Django
to 4.1.7 fixes the problem with outgoing messages to the mailbox.

Environment:

{{{
Python3.10.6
Django4.2
}}}

Link to previously reported issue:
https://code.djangoproject.com/ticket/34386

Stacktrace:

{{{
File "/usr/local/lib/env3/lib/python3.10/site-
packages/django/core/mail/message.py" line 298 in send [args] [locals]
return self.get_connection(fail_silently).send_messages([self])
File "/usr/local/lib/env3/lib/python3.10/site-
packages/django/core/mail/backends/smtp.py" line 127 in send_messages
[args] [locals]
new_conn_created = self.open()
File "/usr/local/lib/env3/lib/python3.10/site-
packages/django/core/mail/backends/smtp.py" line 85 in open [args]
[locals]
self.connection = self.connection_class(
File "/usr/lib/python3.10/smtplib.py" line 1050 in __init__ [args]
[locals]
SMTP.__init__(self, host, port, local_hostname, timeout,
File "/usr/lib/python3.10/smtplib.py" line 255 in __init__ [args] [locals]
(code, msg) = self.connect(host, port)
File "/usr/lib/python3.10/smtplib.py" line 341 in connect [args] [locals]
self.sock = self._get_socket(host, port, self.timeout)
File "/usr/lib/python3.10/smtplib.py" line 1057 in _get_socket [args]
[locals]
new_socket = self.context.wrap_socket(new_socket,
File "/usr/lib/python3.10/ssl.py" line 513 in wrap_socket [args] [locals]
return self.sslsocket_class._create(
File "/usr/lib/python3.10/ssl.py" line 1071 in _create [args] [locals]
self.do_handshake()
File "/usr/lib/python3.10/ssl.py" line 1342 in do_handshake [args]
[locals]
self._sslobj.do_handshake()
SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate
verify failed: unable to get local issuer certificate (_ssl.c:997)
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/34504>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Apr 19, 2023, 5:20:57 AM4/19/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: new
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution:
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Kamen Kalchev:

Old description:

New description:

It looks like this was previously reported in a different scenario and
marked as fixed but is still not working as expected. Downgrading Django
to 4.1.7 fixes the problem with outgoing messages to the mailbox.

Environment:

{{{
Python3.10.6
Django4.2
EMAIL_USE_SSL=True
EMAIL_USE_TLS=False

EMAIL_SSL_CERTFILE=Does not make a difference if we provide a file
location or not
EMAIL_SSL_KEYFILE=Does not make a difference if we provide a file location
or not
}}}

Stacktrace:

--

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:1>

Django

unread,
Apr 19, 2023, 5:57:53 AM4/19/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed

Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo

Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed
* resolution: => needsinfo


Comment:

Thanks for the ticket, however I don't see much difference between the
current implementation and Python < 3.12 behavior in creating a default
SSL context. The only difference is that now `check_hostname` is set to
`True`, does it work for you with the following diff?
{{{#!diff
diff --git a/django/core/mail/backends/smtp.py
b/django/core/mail/backends/smtp.py
index 1ee48269ae..132bed29be 100644
--- a/django/core/mail/backends/smtp.py
+++ b/django/core/mail/backends/smtp.py
@@ -60,6 +60,7 @@ 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)
+ ssl_context.check_hostname = False
return ssl_context
else:
return ssl.create_default_context()
}}}

I'm not sure we'd like to change that.

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:2>

Django

unread,
Apr 19, 2023, 10:16:10 AM4/19/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Kamen Kalchev):

Hello and thank you for the prompt answer, Mariusz.

We have played around with your suggestion and what worked in our case was
adding **check_hostname = False** and **verify_mode = ssl.CERT_NONE** in
the else clause (since we are not passing in a specific cert/ key file) in
an overridden **ssl_context** method for a child class of
**EmailBackend**.

To be honest, we are not sure if this should be changed for everyone but
it looks like something was omitted in creating the default ssl context,
as in Django version 4.1.7 we did not have to manually set those params
and it worked. Anyway, we really appreciate your response and wish you a
good week ahead.

{{{
@cached_property
def ssl_context(self):


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:
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
return ssl_context
}}}


Replying to [comment:2 Mariusz Felisiak]:


> Thanks for the ticket, however I don't see much difference between the
current implementation and Python < 3.12 behavior in creating a default
SSL context. The only difference is that now `check_hostname` is set to
`True`, does it work for you with the following diff?
> {{{#!diff
> diff --git a/django/core/mail/backends/smtp.py
b/django/core/mail/backends/smtp.py
> index 1ee48269ae..132bed29be 100644
> --- a/django/core/mail/backends/smtp.py
> +++ b/django/core/mail/backends/smtp.py
> @@ -60,6 +60,7 @@ 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)
> + ssl_context.check_hostname = False
> return ssl_context
> else:
> return ssl.create_default_context()
> }}}
>
> I'm not sure we'd like to change that.

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:3>

Django

unread,
Apr 19, 2023, 12:47:37 PM4/19/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* cc: Adam Johnson (added)


Comment:

Yes, sorry `check_hostname = False` should be in the "default context"
branch.

It's from `ssl._create_unverified_context()` that is ''"less restrict than
`create_default_context()` to increase backward compatibility."''. It
worked because the host wasn't checked. As far as I'm aware, this shows a
problem with verification of host certificate chain.

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:4>

Django

unread,
Apr 28, 2023, 4:56:47 AM4/28/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak):

#34524 was a duplicate.

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:5>

Django

unread,
Apr 28, 2023, 5:09:28 AM4/28/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak):

Kamen, what do you think about adding a backward incompatibility note? see
[https://github.com/django/django/pull/16812 PR].

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:6>

Django

unread,
Apr 28, 2023, 7:04:35 AM4/28/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by GitHub <noreply@…>):

In [changeset:"5a6d4d3bfde07daab9777545694beb014c832264" 5a6d4d3b]:
{{{
#!CommitTicketReference repository=""
revision="5a6d4d3bfde07daab9777545694beb014c832264"
Refs #34118, Refs #34504 -- Added backward incompatibility note about
EmailBackend.ssl_context.

Follow up to 2848e5d0ce5cf3c31fe87525536093b21d570f69.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:7>

Django

unread,
Apr 28, 2023, 7:05:18 AM4/28/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak <felisiak.mariusz@…>):

In [changeset:"4f343a10f765c4a6672c8ef4c39d044dd7d6653f" 4f343a1]:
{{{
#!CommitTicketReference repository=""
revision="4f343a10f765c4a6672c8ef4c39d044dd7d6653f"
[4.2.x] Refs #34118, Refs #34504 -- Added backward incompatibility note
about EmailBackend.ssl_context.

Follow up to 2848e5d0ce5cf3c31fe87525536093b21d570f69.
Backport of 5a6d4d3bfde07daab9777545694beb014c832264 from main
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:8>

Django

unread,
Apr 28, 2023, 7:12:52 AM4/28/23
to django-...@googlegroups.com
#34504: SSLCertVerificationError on outgoing emails for some mailboxes
-------------------------------------+-------------------------------------
Reporter: Kamen Kalchev | Owner: nobody
Type: Bug | Status: closed
Component: Core (Mail) | Version: 4.2
Severity: Normal | Resolution: needsinfo
Keywords: smtplib, ssl, | Triage Stage:
Django4.2 | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Kamen Kalchev):

Looks good, Mariusz. Thank you once again for looking into this ticket.

Replying to [comment:6 Mariusz Felisiak]:


> Kamen, what do you think about adding a backward incompatibility note?
see [https://github.com/django/django/pull/16812 PR].

--
Ticket URL: <https://code.djangoproject.com/ticket/34504#comment:9>

Reply all
Reply to author
Forward
0 new messages