import html import smtplib import ssl from email.message import EmailMessage from email.utils import formataddr from .models import AppSettings, User def _settings_ready(settings: AppSettings | None) -> bool: return bool(settings and settings.smtp_host and settings.smtp_from_email) def send_html_email(settings: AppSettings, recipient: str, subject: str, body_html: str, body_text: str): if not _settings_ready(settings): raise ValueError("SMTP settings are incomplete") message = EmailMessage() message["Subject"] = subject message["From"] = formataddr((settings.smtp_from_name or "Cluedo HP", settings.smtp_from_email)) message["To"] = recipient message.set_content(body_text) message.add_alternative(body_html, subtype="html") context = ssl.create_default_context() with smtplib.SMTP(settings.smtp_host, settings.smtp_port or 587, timeout=20) as server: server.ehlo() if settings.smtp_use_tls: server.starttls(context=context) server.ehlo() if settings.smtp_username: server.login(settings.smtp_username, settings.smtp_password) server.send_message(message) def send_user_invite(settings: AppSettings, user: User, invite_url: str): name = html.escape(user.display_name or user.email) safe_url = html.escape(invite_url, quote=True) from_name = html.escape(settings.smtp_from_name or "Cluedo HP") body_html = f"""
{from_name}
Eine Einladung wartet
Hallo {name},

du wurdest eingeladen, dem digitalen Zauber-Detektiv-Notizbogen beizutreten.

Richte über den folgenden Button dein persönliches Passwort ein:

Einladung annehmen

Der Link ist 48 Stunden gültig und kann nur einmal verwendet werden.

{safe_url}

Deine Notizen bleiben privat.
""" body_text = f"Hallo {user.display_name or user.email},\n\nbitte richte dein Passwort ein: {invite_url}\n\nDer Link ist 48 Stunden gültig." send_html_email(settings, user.email, "Deine Einladung zum Zauber-Detektiv-Notizbogen", body_html, body_text)