Django5にして依存ライブラリも更新したら、メール送信で SSL: CERTIFICATE_VERIFY_FAILED エラーが出るようになった

Django
2024-04-15 17:35 (1年前) ytyng
View in English
この記事を歌う

問題の内容

Django を 5.0 にアップデートし、他のライブラリも更新した所、下記のメール送信のコードを実行した所

message = EmailMessage(
    subject='検証用メール',
    body='検証用のメールを送信しています。無視してください。',
    from_email='developer@example.com',
    to=['test-user@example.com'],
    reply_to=['developer@example.com'],
)
send_result = message.send()

下記のようなエラーメッセージが出た。

Traceback (most recent call last):
  File "<...>python3.11/site-packages/django/core/management/base.py", line 413, in run_from_argv
    self.execute(*args, **cmd_options)
  File "<...>python3.11/site-packages/django/core/management/base.py", line 459, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<...>management/commands/send_test_mail.py", line 34, in handle
    send_result = message.send()
                  ^^^^^^^^^^^^^^
  File "<...>python3.11/site-packages/django/core/mail/message.py", line 300, in send
    return self.get_connection(fail_silently).send_messages([self])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<...>python3.11/site-packages/django/core/mail/backends/smtp.py", line 128, in send_messages
    new_conn_created = self.open()
                       ^^^^^^^^^^^
  File "<...>python3.11/site-packages/django/core/mail/backends/smtp.py", line 93, in open
    self.connection.starttls(context=self.ssl_context)
  File "<...>lib/python3.11/smtplib.py", line 790, in starttls
    self.sock = context.wrap_socket(self.sock,
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<...>lib/python3.11/ssl.py", line 517, in wrap_socket
    return self.sslsocket_class._create(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<...>lib/python3.11/ssl.py", line 1108, in _create
    self.do_handshake()
  File "<...>lib/python3.11/ssl.py", line 1379, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1006)

接続先のSMTPサーバーは、EC2 に Postfix をインストールして作ったもの。

自己署名証明書がベリファイできないとこのエラーが出るようになってしまったようだ。

smtplib を使ってメール送信をした場合

ちなみに、同サーバーを使う際、 smtplib を使って

s = smtplib.SMTP(...)
s.starttls()
s.ehlo()
s.login(...)
s.sendmail(...)

とした場合、上記エラーは出なかった。

対応案

とりいそぎの対応として、メール送信箇所のコードの下記箇所について

self.connection.starttls(context=self.ssl_context)

context に、 ssl._create_unverified_context() を入れれば動く。(本来は ssl.create_default_context() を入れている)

証明書のベリファイをスキップするので良い方法ではない。

緊急的な対応方法

例えば、下記のような関数を作り、EmailMessage.send の代わりに使えば、警告とベリファイをキャンセルして送信ができる。

def send_message_use_unverified_backend(email_message, *, fail_silently=False):
    if not email_message.recipients():
        return 0
    connection = email_message.get_connection(fail_silently=fail_silently)
    connection.ssl_context = ssl._create_unverified_context()
    return connection.send_messages([email_message])

message = EmailMessage(...)

send_message_use_unverified_backend(message)

本来は、上記対応よりも Amazon SES とか Sendgrid 等のマネージドな SMTP を使ったほうが良い。

現在未評価
タイトルとURLをコピー
著者は、アプリケーション開発会社 Cyberneura を運営しています。
開発相談をお待ちしています。

アーカイブ

2026
2025
2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
2012
2011