mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-22 13:05:18 +00:00
1. 重构后端API路由、CRUD与模块结构,整合日志管理,移除废弃demo代码 2. 优化前端组件类型定义、样式与路由配置,修复权限判断逻辑 3. 调整默认排序规则、滚动条样式与工具类函数,更新依赖与配置文件 4. 修复多处类型不匹配与默认值问题,完善表单与菜单验证逻辑
89 lines
2.1 KiB
Python
89 lines
2.1 KiB
Python
"""
|
||
email_util.py — 邮件发送工具
|
||
|
||
职责:
|
||
- 渲染 Jinja2 模板
|
||
- 通过 fastapi-mail 发送邮件
|
||
|
||
使用方:EmailService.send_email_service()
|
||
"""
|
||
|
||
from typing import Any
|
||
|
||
from fastapi_mail import ConnectionConfig, FastMail, MessageSchema, MessageType
|
||
from jinja2 import Environment, StrictUndefined
|
||
|
||
|
||
def render_template(template_str: str, variables: dict[str, Any]) -> str:
|
||
"""
|
||
使用 Jinja2 渲染邮件模板。
|
||
|
||
参数:
|
||
- template_str: Jinja2 模板字符串
|
||
- variables: 变量字典
|
||
|
||
返回:渲染后的字符串
|
||
|
||
异常:TemplateError — 模板语法错误或变量缺失
|
||
"""
|
||
env = Environment(undefined=StrictUndefined, autoescape=True)
|
||
tmpl = env.from_string(template_str)
|
||
return tmpl.render(**variables)
|
||
|
||
|
||
async def send_email(
|
||
*,
|
||
smtp_host: str,
|
||
smtp_port: int,
|
||
smtp_user: str,
|
||
smtp_password: str,
|
||
use_tls: bool,
|
||
from_name: str,
|
||
to_email: str,
|
||
to_name: str | None,
|
||
subject: str,
|
||
body_html: str,
|
||
body_text: str | None = None,
|
||
timeout: int = 30,
|
||
) -> None:
|
||
"""
|
||
异步发送邮件(通过 fastapi-mail)。
|
||
|
||
参数均为关键字参数。
|
||
|
||
异常:
|
||
- SMTPException — SMTP 协议错误
|
||
- TimeoutError — 连接/发送超时
|
||
"""
|
||
# 构建 fastapi-mail 连接配置
|
||
# 端口 465 = 隐式 SSL,端口 587 = STARTTLS
|
||
is_ssl = smtp_port == 465
|
||
|
||
conf = ConnectionConfig(
|
||
MAIL_USERNAME=smtp_user,
|
||
MAIL_PASSWORD=smtp_password,
|
||
MAIL_FROM=smtp_user,
|
||
MAIL_FROM_NAME=from_name,
|
||
MAIL_SERVER=smtp_host,
|
||
MAIL_PORT=smtp_port,
|
||
MAIL_STARTTLS=not is_ssl and use_tls,
|
||
MAIL_SSL_TLS=is_ssl,
|
||
USE_CREDENTIALS=True,
|
||
VALIDATE_CERTS=False,
|
||
MAIL_TIMEOUT=timeout,
|
||
)
|
||
|
||
# 收件人格式:支持 "姓名 <邮箱>"(若有 to_name)
|
||
recipient = f"{to_name} <{to_email}>" if to_name else to_email
|
||
|
||
# 构建邮件消息
|
||
message = MessageSchema(
|
||
subject=subject,
|
||
recipients=[recipient],
|
||
body=body_html,
|
||
subtype=MessageType.html,
|
||
)
|
||
|
||
fm = FastMail(conf)
|
||
await fm.send_message(message)
|