From 0712fbb486dabed2290be3c5eede9ea39c819456 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 21 Aug 2026 01:55:19 +0000 Subject: [PATCH] Add mailer.py --- mailer.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 mailer.py diff --git a/mailer.py b/mailer.py new file mode 100644 index 0000000..ef05620 --- /dev/null +++ b/mailer.py @@ -0,0 +1,34 @@ +"""Optional SMTP delivery of tenant reports.""" +import asyncio +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +from config import Settings + + +class MailNotConfigured(RuntimeError): + pass + + +def _send_sync(s: Settings, to: str, subject: str, html: str): + msg = MIMEMultipart("alternative") + msg["Subject"] = subject + msg["From"] = s.smtp_from + msg["To"] = to + msg.attach(MIMEText(html, "html")) + + with smtplib.SMTP(s.smtp_host, s.smtp_port, timeout=30) as server: + if s.smtp_tls: + server.starttls() + if s.smtp_user: + server.login(s.smtp_user, s.smtp_password) + server.send_message(msg) + + +async def send_report(s: Settings, to: str, subject: str, html: str): + if not s.smtp_host: + raise MailNotConfigured( + "SMTP not configured — set BILLING_SMTP_HOST etc. in .env" + ) + await asyncio.to_thread(_send_sync, s, to, subject, html)