import logging from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText import aiosmtplib from app.config import settings logger = logging.getLogger(__name__) def build_email_shell( *, eyebrow: str, title: str, body_html: str, action_label: str | None = None, action_url: str | None = None, summary_html: str | None = None, footer_note: str = "此邮件由系统自动发送,请勿直接回复。", ) -> str: action_html = "" if action_label and action_url: action_html = f"""
{action_label}
""" summary_block = "" if summary_html: summary_block = f"""
{summary_html}
""" return f"""
{eyebrow}

香港大学中国商业学院

HKU ICB · 班级信息管理平台

{title}

{body_html}
{summary_block} {action_html}
{footer_note}
""" async def send_email(to: str, subject: str, html_body: str) -> bool: """Send HTML email via SMTP. Returns True on success.""" if not settings.smtp_host: logger.info(f"SMTP not configured, skipping email to {to}: {subject}") return False msg = MIMEMultipart("alternative") msg["From"] = f"{settings.smtp_from_name} <{settings.smtp_from_email}>" msg["To"] = to msg["Subject"] = subject msg.attach(MIMEText(html_body, "html")) try: await aiosmtplib.send( msg, hostname=settings.smtp_host, port=settings.smtp_port, username=settings.smtp_user, password=settings.smtp_password, use_tls=True, ) return True except Exception as e: logger.error(f"Failed to send email to {to}: {e}") return False async def send_account_activated_email(member_email: str) -> bool: login_url = f"{settings.frontend_url.rstrip('/')}/login" html = build_email_shell( eyebrow="Account Ready", title="账号已激活,可以开始使用", body_html="""

你的 HKU ICB 班级账号已经成功激活。

现在可以使用注册邮箱登录平台,进入班级空间查看公告、排期、资源与成员信息。

""", action_label="立即登录", action_url=login_url, ) return await send_email(member_email, "HKU ICB:账号激活成功", html) async def send_email_verification_code_email(member_email: str, code: str) -> bool: html = build_email_shell( eyebrow="Email Verification", title="请验证你的邮箱地址", body_html="""

你正在激活 HKU ICB 班级账号,请使用下方验证码完成邮箱验证。

验证码 10 分钟内有效;如果不是你本人操作,可以忽略此邮件。

""", summary_html=f"""
邮箱验证码
{code}
""", ) return await send_email(member_email, "HKU ICB:邮箱验证码", html) async def send_class_notification_email( emails: list[str], subject: str, title: str, body: str, action_url: str | None = None, eyebrow: str = "Class Update", action_label: str | None = "查看详情", summary_html: str | None = None, ): """Send a styled notification email to class members.""" normalized_body = body.replace("\n", "
") html = build_email_shell( eyebrow=eyebrow, title=title, body_html=f"
{normalized_body}
", action_label=action_label if action_url else None, action_url=action_url, summary_html=summary_html, ) for email in emails: await send_email(email, subject, html)