"""Magic-link delivery. SMTP when configured, dev log fallback otherwise. Mail design follows the web branding (see frontend/src/theme.ts): kirchenblau header, serif headline, white card on paper background. Email-safe by construction: table layout, inline styles only, system fonts, no external images (many clients block them / track opens). """ from __future__ import annotations import logging import smtplib from email.message import EmailMessage from app.settings import settings logger = logging.getLogger(__name__) # Brand palette (mirrors frontend/src/theme.ts kirchenblau). BLUE = "#1d4a79" BLUE_LIGHT = "#eef4fb" INK = "#162f4c" MUTED = "#5b6b7c" def magic_link(token: str) -> str: return f"{settings.frontend_url.rstrip('/')}/login?token={token}" def _page(title: str, intro: str, button_label: str, button_url: str | None, note: str) -> str: """Branded HTML mail body (table layout, inline styles, no images).""" button = "" if button_url: button = ( '' f'
' f'{button_label}
' ) return f"""
Kirche Einfach

{title}

{intro}

{button}

{note}

""" def _send(message: EmailMessage) -> None: with smtplib.SMTP(settings.smtp_host, settings.smtp_port, timeout=10) as smtp: smtp.starttls() if settings.smtp_username: smtp.login(settings.smtp_username, settings.smtp_password) smtp.send_message(message) def _branded_mail( subject: str, to_email: str, headline: str, intro: str, button_label: str, button_url: str, note: str, ) -> EmailMessage: """Text + branded HTML alternative; the link is a real button.""" message = EmailMessage() message["Subject"] = subject message["To"] = to_email message["From"] = settings.mail_from or settings.contact_to or to_email if settings.contact_to: message["Reply-To"] = settings.contact_to message.set_content(f"{headline}\n\n{intro}\n\n{button_label}:\n{button_url}\n\n{note}\n") # Email-safe HTML: tables + inline CSS; some clients strip