Files
TK-Wiki-Newsletter/app/services/smtp_sender.py
smueller 654276f6b5 Enhance newsletter generation and dashboard functionality
- Introduce a new period selection feature in the dashboard for generating newsletters, allowing users to choose between "last month" and "last X days."
- Refactor newsletter generation logic to support filtering by article type (new, edited, or all) and improve the handling of filters in the dashboard.
- Update the dashboard template to include new input fields for period and article type, enhancing user experience.
- Improve CSS styles for send notifications and sections in the dashboard, providing clearer feedback on newsletter sending status.
2026-07-07 14:20:21 +02:00

99 lines
3.7 KiB
Python

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()