Для відправлення листів електронною поштою на певних поштових системах
потрібно застосовувати свій персональний сертифікат користувача, у парі з
закритим ключем.
Властивості сертифіката для підключення клієнта |
Але, пробуючи відправити листа у Django з'ясував що листи не відправляються з помилкою:
SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)')
Аналізуючи приклад з прямим надсиланням email через smtplib, з'ясував -
що працює відправлення коли контекст створений з використанням
purpose = ssl.Purpose.SERVER_AUTH.
А у базовому EmailBackend у Dajngo контекст без цього.
class EmailBackend(BaseEmailBackend): ... @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: return ssl.create_default_context()
Тому створив новий власний Backend котрий розширює EmailBackend.
Для розв'язання проблем з сертифікатами у macOS помилки (ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)) додано використання "certifi"
та cafile=certifi.where().
cert_email_backend.py:
import ssl
import certifi
from django.core.mail.backends.smtp import EmailBackend from django.utils.functional import cached_property class CertEmailBackend(EmailBackend):
@cached_property def ssl_context(self): if self.ssl_certfile or self.ssl_keyfile: ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=certifi.where()) # 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(cafile=certifi.where())
А в налаштуваннях settings.py змінив EMAIL_BACKEND.
# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_BACKEND = "your_project.cert_email_backend.CertEmailBackend"Змінні оточення використовую в settings.py для визначення шляху до файлу сертифіката та ключа що знаходяться у теці .certs так:
BASE_DIR = Path(__file__).resolve().parent.parent
EMAIL_SSL_CERTFILE = os.getenv("EMAIL_SSL_CERTFILE") EMAIL_SSL_KEYFILE = os.getenv("EMAIL_SSL_KEYFILE") if EMAIL_SSL_CERTFILE: EMAIL_SSL_CERTFILE = BASE_DIR.parent.joinpath(".certs").joinpath(EMAIL_SSL_CERTFILE) if EMAIL_SSL_KEYFILE: EMAIL_SSL_KEYFILE = BASE_DIR.parent.joinpath(".certs").joinpath(EMAIL_SSL_KEYFILE)
Для тестування налаштувань зручно використати django-admin tools manage.py
python manage.py sendtestemail some@example.net
Для конвертування ключів з файлу .p12 до файлу .pem використати можна openssl:
openssl pkcs12 -info -in path.p12 -nodes -nocerts -out newfile.pem
Немає коментарів:
Дописати коментар