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() security = getattr(settings, "smtp_security", "") or ("starttls" if settings.smtp_use_tls else "none") port = settings.smtp_port or (465 if security == "ssl" else 587) smtp_client = smtplib.SMTP_SSL if security == "ssl" else smtplib.SMTP connection = smtp_client(settings.smtp_host, port, timeout=20, context=context) if security == "ssl" else smtp_client(settings.smtp_host, port, timeout=20) with connection as server: server.ehlo() if security == "starttls": 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"""