import smtplib from datetime import datetime from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from typing import Sequence from sqlalchemy.orm import Session from app.models.system import SendLog from app.services.config_store import get_config def get_smtp_settings(db: Session) -> dict[str, str]: return { "enabled": get_config(db, "smtp.enabled", "false"), "host": get_config(db, "smtp.host", ""), "port": get_config(db, "smtp.port", "587"), "username": get_config(db, "smtp.username", ""), "password": get_config(db, "smtp.password", ""), "from_email": get_config(db, "smtp.from_email", ""), "use_tls": get_config(db, "smtp.use_tls", "true"), "recipients": get_config(db, "smtp.recipients", ""), "schedule_time": get_config(db, "smtp.schedule_time", "08:00"), "last_scheduled_date": get_config(db, "smtp.last_scheduled_date", ""), } def send_newsletter( db: Session, subject: str, html_content: str, text_content: str, recipients: Sequence[str], scheduled: bool = False, ) -> tuple[str, str]: settings = get_smtp_settings(db) if settings["enabled"].lower() != "true": detail = "SMTP ist deaktiviert. Bitte in der SMTP-Konfiguration aktivieren." _log(db, subject, recipients, "skipped", detail, scheduled) return "skipped", detail if not settings["host"] or not settings["from_email"] or not recipients: detail = "SMTP unvollständig konfiguriert (Host, Absender oder Empfänger fehlen)." _log(db, subject, recipients, "failed", detail, scheduled) return "failed", detail msg = MIMEMultipart("alternative") msg.attach(MIMEText(text_content, "plain", "utf-8")) msg.attach(MIMEText(html_content, "html", "utf-8")) msg["Subject"] = subject msg["From"] = settings["from_email"] msg["To"] = ", ".join(recipients) try: port = int(settings["port"]) with smtplib.SMTP(settings["host"], port, timeout=20) as server: if settings["use_tls"].lower() == "true": server.starttls() if settings["username"]: server.login(settings["username"], settings["password"]) server.sendmail(settings["from_email"], list(recipients), msg.as_string()) detail = f"Versand erfolgreich an {len(recipients)} Empfänger." _log(db, subject, recipients, "sent", detail, scheduled) return "sent", detail except Exception as exc: detail = f"Versandfehler: {exc}" _log(db, subject, recipients, "failed", detail, scheduled) return "failed", detail def run_scheduled_send_if_due(db: Session, subject: str, html_content: str, text_content: str) -> None: settings = get_smtp_settings(db) if settings["enabled"].lower() != "true": return now = datetime.now() schedule_time = settings["schedule_time"] or "08:00" if now.strftime("%H:%M") < schedule_time: return today = now.strftime("%Y-%m-%d") if settings["last_scheduled_date"] == today: return recipients = [r.strip() for r in settings["recipients"].split(",") if r.strip()] send_newsletter(db, subject, html_content, text_content, recipients, scheduled=True) from app.services.config_store import set_config set_config(db, "smtp.last_scheduled_date", today) def _log(db: Session, subject: str, recipients: Sequence[str], status: str, detail: str, scheduled: bool) -> None: db.add( SendLog( subject=subject, recipients=", ".join(recipients) if recipients else "-", status=status, detail=detail, scheduled=scheduled, ) ) db.commit()