"""Async email sending via SMTP. Falls back to logging if SMTP is not configured.""" import logging import os from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText import aiosmtplib logger = logging.getLogger(__name__) SMTP_HOST = os.getenv("SMTP_HOST", "") SMTP_PORT = int(os.getenv("SMTP_PORT", "587")) SMTP_USER = os.getenv("SMTP_USER", "") SMTP_PASSWORD = os.getenv("SMTP_PASSWORD", "") SMTP_FROM = os.getenv("SMTP_FROM", SMTP_USER) SMTP_SSL = os.getenv("SMTP_SSL", "false").lower() == "true" SMTP_TLS = os.getenv("SMTP_TLS", "true").lower() != "false" SITE_NAME = "Skins & Pins" def _configured() -> bool: return bool(SMTP_HOST and SMTP_USER and SMTP_FROM) async def _send(to: str, subject: str, body_text: str, body_html: str) -> None: msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["From"] = f"{SITE_NAME} <{SMTP_FROM}>" msg["To"] = to msg.attach(MIMEText(body_text, "plain")) msg.attach(MIMEText(body_html, "html")) await aiosmtplib.send( msg, hostname=SMTP_HOST, port=SMTP_PORT, username=SMTP_USER, password=SMTP_PASSWORD, use_tls=SMTP_SSL, start_tls=(SMTP_TLS and not SMTP_SSL), timeout=10, ) async def send_magic_link(to: str, link: str, code: str) -> None: subject = f"Your {SITE_NAME} login code: {code}" body_text = ( f"Your login code is: {code}\n\n" f"Enter it on the app, or click the link below (both expire in 15 minutes):\n\n{link}\n\n" f"If you didn't request this, you can ignore this email." ) body_html = f"""
Enter this code in the app to log in:
Or click the button below — whichever is easier. Both expire in 15 minutes.
If the button doesn't work, copy this link:
{link}
If you didn't request this, you can ignore this email.
{invited_by_name} has invited you to join {SITE_NAME} — a golf score tracking app.
If the button doesn't work, copy this link:
{login_url}