"""Email notification service for VoIdea. Uses aiosmtplib for async SMTP with Jinja2 templates. Falls back to logging when SMTP is not configured. """ import logging from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from pathlib import Path from jinja2 import Environment, FileSystemLoader, select_autoescape from app.core.config import get_settings logger = logging.getLogger(__name__) TEMPLATES_DIR = Path(__file__).parent.parent / "templates" / "email" _env = Environment(loader=FileSystemLoader(str(TEMPLATES_DIR)), autoescape=select_autoescape()) def _render(template_name: str, context: dict) -> str: """Render an email template. Args: template_name: Name of the template file (e.g. "welcome.html") context: Template variables Returns: Rendered HTML string, or plain text fallback """ try: template = _env.get_template(template_name) return template.render(**context) except Exception: lines = [f"{k}: {v}" for k, v in context.items()] return "\n".join(lines) async def send_email(to: str, subject: str, html: str) -> bool: """Send an email via SMTP, or log to console if SMTP not configured. Args: to: Recipient email subject: Email subject html: HTML body Returns: True if sent (or logged) successfully, False on SMTP error """ settings = get_settings() if not settings.smtp_host: logger.info( "SMTP not configured — email logged instead:\n" " To: %s\n Subject: %s\n Body:\n%s", to, subject, html, ) return True try: import aiosmtplib msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["From"] = settings.smtp_from msg["To"] = to msg.attach(MIMEText(html, "html")) await aiosmtplib.send( msg, hostname=settings.smtp_host, port=settings.smtp_port, username=settings.smtp_user or None, password=settings.smtp_pass or None, use_tls=settings.smtp_tls, ) return True except Exception: return False async def send_welcome_email(to: str, username: str) -> bool: """Send welcome email after registration. Args: to: Recipient email username: User display name """ html = _render("welcome.html", {"username": username, "project_name": "VoIdea"}) return await send_email(to, f"Добро пожаловать в VoIdea!", html) async def send_notification_email(to: str, subject: str, message: str) -> bool: """Send a notification email. Args: to: Recipient email subject: Email subject message: Plain text or HTML message """ html = _render("notification.html", {"subject": subject, "message": message}) return await send_email(to, subject, html)