103 lines
2.9 KiB
Python
103 lines
2.9 KiB
Python
"""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)
|