65 lines
2.1 KiB
Python
65 lines
2.1 KiB
Python
|
|
"""Operational mail for account links. No dialogue content, no model egress."""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import logging
|
||
|
|
import os
|
||
|
|
import smtplib
|
||
|
|
from email.message import EmailMessage
|
||
|
|
|
||
|
|
from env_loader import env_flag, runtime_env
|
||
|
|
|
||
|
|
log = logging.getLogger("kansho.mail")
|
||
|
|
|
||
|
|
OUTBOX: list[dict] = []
|
||
|
|
|
||
|
|
|
||
|
|
class MailNotConfigured(RuntimeError):
|
||
|
|
"""SMTP is required and neither configured nor in the development log path."""
|
||
|
|
|
||
|
|
|
||
|
|
def clear_outbox() -> None:
|
||
|
|
OUTBOX.clear()
|
||
|
|
|
||
|
|
|
||
|
|
def smtp_configured() -> bool:
|
||
|
|
return bool((os.environ.get("SMTP_HOST") or "").strip() and (os.environ.get("SMTP_FROM") or "").strip())
|
||
|
|
|
||
|
|
|
||
|
|
def send_mail(recipients: list[str], subject: str, body: str) -> None:
|
||
|
|
cleaned: list[str] = []
|
||
|
|
for item in recipients:
|
||
|
|
address = (item or "").strip().lower()
|
||
|
|
if address and address not in cleaned:
|
||
|
|
cleaned.append(address)
|
||
|
|
if not cleaned:
|
||
|
|
raise MailNotConfigured("Mailversand ist nicht konfiguriert")
|
||
|
|
if env_flag("KANSHO_FAKE_MAIL"):
|
||
|
|
OUTBOX.append({"to": cleaned, "subject": subject, "body": body})
|
||
|
|
return
|
||
|
|
host = (os.environ.get("SMTP_HOST") or "").strip()
|
||
|
|
sender = (os.environ.get("SMTP_FROM") or "").strip()
|
||
|
|
if not host or not sender:
|
||
|
|
if runtime_env() == "development":
|
||
|
|
log.warning("Kansho mail (development, SMTP fehlt): %s", body)
|
||
|
|
return
|
||
|
|
raise MailNotConfigured("Mailversand ist nicht konfiguriert")
|
||
|
|
port = int((os.environ.get("SMTP_PORT") or "587").strip() or "587")
|
||
|
|
user = (os.environ.get("SMTP_USER") or "").strip()
|
||
|
|
password = os.environ.get("SMTP_PASSWORD") or ""
|
||
|
|
message = EmailMessage()
|
||
|
|
message["Subject"] = subject
|
||
|
|
message["From"] = sender
|
||
|
|
message["To"] = ", ".join(cleaned)
|
||
|
|
message.set_content(body)
|
||
|
|
if port == 465:
|
||
|
|
with smtplib.SMTP_SSL(host, port, timeout=20) as smtp:
|
||
|
|
if user:
|
||
|
|
smtp.login(user, password)
|
||
|
|
smtp.send_message(message)
|
||
|
|
return
|
||
|
|
with smtplib.SMTP(host, port, timeout=20) as smtp:
|
||
|
|
smtp.starttls()
|
||
|
|
if user:
|
||
|
|
smtp.login(user, password)
|
||
|
|
smtp.send_message(message)
|