from __future__ import annotations import logging from html import escape from typing import Any import resend from flask import current_app class EmailConfigurationError(RuntimeError): """Raised when transactional email has not been configured.""" class EmailDeliveryError(RuntimeError): """Raised when Resend rejects or cannot deliver an email request.""" def render_transactional_email(*, title: str, content: str) -> str: """Render a conservative table-based email layout for broad client support.""" return f"""
供水管道健康评估系统

{escape(title)}

{content}
此邮件由系统自动发送,请勿直接回复。
如非本人操作,请忽略此邮件并及时检查账户安全。
""" def verification_code_email(*, code: str, minutes: int, purpose: str) -> str: """Render the verification email without exposing dynamic HTML to callers.""" content = f"""

你正在进行{escape(purpose)}。请在 {minutes} 分钟内输入下方验证码。

{escape(code)}

验证码仅可使用一次,请勿向任何人透露。

""" return render_transactional_email(title="邮箱验证码", content=content) def password_reset_notice_email(*, username: str, reset_url: str, minutes: int) -> str: """Render a one-time password reset link email.""" safe_url = escape(reset_url, quote=True) content = f"""

{escape(username)},请通过下方按钮设置新密码。

该链接仅可使用一次,并将在 {minutes} 分钟后失效。

重置密码

""" return render_transactional_email(title="重置账户密码", content=content) def registration_invitation_email(*, invitation_url: str, minutes: int) -> str: """Render a one-time invitation link email for an administrator-created account.""" safe_url = escape(invitation_url, quote=True) content = f"""

管理员邀请你加入供水管道健康评估系统。

请通过下方按钮设置显示名和密码。该链接仅可使用一次,并将在 {minutes} 分钟后失效。

接受邀请并注册

""" return render_transactional_email(title="管理员邀请你注册", content=content) def send_transactional_email(*, to: str, subject: str, html: str) -> dict[str, Any]: """Send one application-generated email through Resend.""" api_key = current_app.config["RESEND_API_KEY"] from_email = current_app.config["RESEND_FROM_EMAIL"] if not api_key or not from_email: raise EmailConfigurationError( "邮件服务尚未配置,请设置 RESEND_API_KEY 和 RESEND_FROM_EMAIL。" ) resend.api_key = api_key try: return resend.Emails.send( { "from": from_email, "to": [to], "subject": subject, "html": html, } ) except Exception as exc: logging.exception("Resend 邮件发送失败: %s", exc) raise EmailDeliveryError("邮件发送失败,请稍后重试。") from exc