@@ -4,6 +4,7 @@ version = "0.0.1"requires-python = ">=3.10"dependencies = [ "django", "dnspython", "gunicorn", "requests", "tzdata",
@@ -0,0 +1,53 @@import loggingimport smtplibfrom concurrent.futures import ThreadPoolExecutorimport dns.resolverfrom django.core.mail.backends.base import BaseEmailBackendlog = logging.getLogger(__name__)_POOL = ThreadPoolExecutor(max_workers=4, thread_name_prefix="mailer")def _deliver(message): try: by_domain = {} for rcpt in message.to + message.cc + message.bcc: by_domain.setdefault(rcpt.rsplit("@", 1)[1], []).append(rcpt) payload = message.message().as_bytes() sender = message.from_email for domain, rcpts in by_domain.items(): mxs = sorted( dns.resolver.resolve(domain, "MX"), key=lambda r: r.preference, ) for mx in mxs: host = str(mx.exchange).rstrip(".") try: with smtplib.SMTP( host, 25, local_hostname="bythewood.me", timeout=30 ) as smtp: smtp.ehlo() try: smtp.starttls() smtp.ehlo() except smtplib.SMTPNotSupportedError: pass smtp.sendmail(sender, rcpts, payload) break except Exception as exc: log.warning("MX %s failed for %s: %s", host, domain, exc) else: log.error("all MX hosts failed for %s", domain) except Exception: log.exception("mail delivery failed")class DirectMXBackend(BaseEmailBackend): def send_messages(self, email_messages): for message in email_messages: _POOL.submit(_deliver, message) return len(email_messages)
modified
status/settings/production.py
@@ -53,10 +53,11 @@ DATABASES = {# Email# https://docs.djangoproject.com/en/4.0/topics/email/#smtp-backend# https://docs.djangoproject.com/en/4.0/topics/email/#email-backendsEMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"EMAIL_HOST = "email"EMAIL_BACKEND = "status.mailer.DirectMXBackend"DEFAULT_FROM_EMAIL = "noreply@bythewood.me"SERVER_EMAIL = "noreply@bythewood.me"# Media files (Images, Videos)
@@ -244,6 +244,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/47/3d61d611609764aa71a37f7037b870e7bfb22937366974c4fd46cada7bab/django-6.0.4-py3-none-any.whl", hash = "sha256:14359c809fc16e8f81fd2b59d7d348e4d2d799da6840b10522b6edf7b8afc1da", size = 8368342, upload-time = "2026-04-07T13:55:37.999Z" },][[package]]name = "dnspython"version = "2.8.0"source = { registry = "https://pypi.org/simple" }sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },][[package]]name = "flake8"version = "7.3.0"
@@ -558,6 +567,7 @@ dependencies = [ { name = "beautifulsoup4" }, { name = "django", version = "5.2.13", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "django", version = "6.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "dnspython" }, { name = "gunicorn" }, { name = "lxml" }, { name = "requests" },
@@ -577,6 +587,7 @@ dev = [requires-dist = [ { name = "beautifulsoup4" }, { name = "django" }, { name = "dnspython" }, { name = "gunicorn" }, { name = "lxml" }, { name = "requests" },