Opened 12 months ago

Closed 12 months ago

Last modified 12 months ago

#34524 closed Bug (duplicate)

Error while sending TLS smtp email on "self-signed certificate" server

Reported by: Buky Owned by: nobody
Component: Core (Mail) Version: 4.2
Severity: Normal Keywords: ssl
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Buky)

The issue appears in Django 4.2 (tested with Python 3.11 and Python 3.9).
Correctly works with previous versions of Django: 3.2 and 4.1

Context: I use locally use the protonmail-bridge solution that locally bind an IMAP and SMTP ports with STARTTLS. Then, I use in my project config the EmailBackend to connect to the solution and send emails.

Here is the traceback, when I try to send emails with Django 4.2:

Traceback (most recent call last):
  File "/home/user/my-project/manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/management/base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/management/base.py", line 458, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/my-project/my-app/management/commands/send-mail.py", line 62, in handle
    send_mail(f"[My subject] {options['subject']}",
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/mail/__init__.py", line 87, in send_mail
    return mail.send()
           ^^^^^^^^^^^
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/mail/message.py", line 298, in send
    return self.get_connection(fail_silently).send_messages([self])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/mail/backends/smtp.py", line 127, in send_messages
    new_conn_created = self.open()
                       ^^^^^^^^^^^
  File "/home/user/.virtualenvs/env/lib/python3.11/site-packages/django/core/mail/backends/smtp.py", line 92, in open
    self.connection.starttls(context=self.ssl_context)
  File "/usr/lib/python3.11/smtplib.py", line 790, in starttls
    self.sock = context.wrap_socket(self.sock,
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ssl.py", line 517, in wrap_socket
    return self.sslsocket_class._create(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ssl.py", line 1075, in _create
    self.do_handshake()
  File "/usr/lib/python3.11/ssl.py", line 1346, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:992)

I found another ticket recently created ticket related to SSL issue, but the issue doesn't exactly the same and the issue doesn't precisely mention when the patch will be merged: [4.2.x] Fixed.

I have tried to export the TLS certificate and key of the solution and add them in my settings.py like:

EMAIL_SSL_CERTFILE="/tmp/cert.pem"
EMAIL_SSL_KEYFILE="/tmp/key.pem"

And to put them in the trust store of the system:

cp /tmp/cert.pem /usr/local/share/ca-certificates/protonmail-bridge.crt
cp /tmp/key.pem /etc/ssl/private/protonmail-bridge.key
update-ca-certificates

But both tests didn't work.

I suppose ssl lib need an extra argument to allow SSL context with self-signed certificate.

Change History (6)

comment:1 by Buky, 12 months ago

Description: modified (diff)

comment:2 by Buky, 12 months ago

Description: modified (diff)

comment:3 by Mariusz Felisiak, 12 months ago

Resolution: duplicate
Status: newclosed

#34386 will be released in Django 4.2.1.

This is a duplicate of #34504. You can subclass EmailBackend and override ssl_context to avoid host verification (but I would advise against it.)

comment:4 by Buky, 12 months ago

Hello Mariusz and thank for the quick reply,

I looked at the patch note of the version 4.2.1 but I didn't see any mention of backward incompatibility for SSL.
So, it's a good idea to add it. Thank for the quick PR.

Could I recommend an example in the Django documentation for creating a proper subclass EmailBackend and dealing with ssl_context?
Because the documentation is quite poor on this topic.

Last edited 12 months ago by Buky (previous) (diff)

comment:5 by aliceni81, 12 months ago

I have the same error as yours. Have your figured out the solution instead of subclass EmailBackend?

in reply to:  5 comment:6 by aliceni81, 12 months ago

Just figure it out without defining certfile and keyfile:

  1. Add the cert to trusted root CA
  2. Use the hostname as EMAIL_HOST instead of IP

Replying to aliceni81:

I have the same error as yours. Have your figured out the solution instead of subclass EmailBackend?

Note: See TracTickets for help on using tickets.
Back to Top