"""FlowDeck — Email notifications via SMTP (v4.9.0). If SMTP is not configured (smtp_host empty) this is a safe no-op, so the application works locally out of the box while still logging intent. """ from __future__ import annotations import logging import smtplib from email.message import EmailMessage from app.config import settings logger = logging.getLogger(__name__) def _configured() -> bool: return bool(settings.smtp_host) def _html_body(body_text: str, cta_url: str = "") -> str: cta = "" if cta_url: cta = ( '

' f'Open in FlowDeck →

' ) return f"""
FlowDeck

{body_text}

{cta}

You received this because your notifications preferences in FlowDeck allow it.

""" def send_email(to_email: str, subject: str, body_text: str, cta_url: str = "") -> bool: """Send an email. Returns True on success, False if skipped or failed.""" if not to_email or not _configured(): return False try: msg = EmailMessage() msg["Subject"] = subject msg["From"] = settings.smtp_from msg["To"] = to_email msg.set_content(body_text) msg.add_alternative(_html_body(body_text, cta_url), subtype="html") with smtplib.SMTP(settings.smtp_host, settings.smtp_port, timeout=15) as server: if settings.smtp_use_tls: server.starttls() if settings.smtp_user: server.login(settings.smtp_user, settings.smtp_password) server.send_message(msg) logger.info("Email sent to %s: %s", to_email, subject) return True except Exception as e: # never break the request on mail failure logger.warning("Email send failed to %s: %s", to_email, e) return False def notify_user( user_id: int, subject: str, body_text: str, cta_url: str = "", prefs_key: str = "mentions", ) -> bool: """Resolve a user's email + preferences and send an email notification.""" from app.db import get_conn from app.services import notifications with get_conn() as conn: row = conn.execute("SELECT id, email FROM users WHERE id=?", (user_id,)).fetchone() if not row or not row["email"]: return False prefs = notifications.get_user_prefs(user_id) if not prefs.get(prefs_key, True): return False return send_email(row["email"], subject, body_text, cta_url)