62 lines
2.4 KiB
Python
62 lines
2.4 KiB
Python
"""邮件发送工具(基于标准库 smtplib,465 端口 SSL)。
|
||
|
||
配置来自 app.config.setting.settings(SMTP_HOST/PORT/USER/PASSWORD/FROM/FROM_NAME/TLS)。
|
||
"""
|
||
from email.header import Header
|
||
from email.mime.text import MIMEText
|
||
from smtplib import SMTP_SSL, SMTPException
|
||
|
||
from app.config.setting import settings
|
||
from app.core.logger import logger
|
||
|
||
|
||
def send_email(to_addr: str, subject: str, html_body: str) -> None:
|
||
"""发送一封 HTML 邮件(同步,内部阻塞;服务层用线程池调用)。
|
||
|
||
参数:
|
||
- to_addr (str): 收件人邮箱
|
||
- subject (str): 邮件主题
|
||
- html_body (str): HTML 正文
|
||
|
||
异常:
|
||
- SMTPException: 发送失败时抛出,由调用方捕获并处理
|
||
"""
|
||
if not settings.SMTP_HOST or not settings.SMTP_USER:
|
||
raise RuntimeError("SMTP 未配置:请在 .env 中设置 SMTP_HOST/SMTP_USER/SMTP_PASSWORD")
|
||
|
||
from_addr = settings.SMTP_FROM or settings.SMTP_USER
|
||
display = settings.SMTP_FROM_NAME or from_addr
|
||
# 显示名单独编码,邮箱地址保持 ASCII
|
||
from_header = f"{Header(display, 'utf-8').encode()} <{from_addr}>"
|
||
|
||
msg = MIMEText(html_body, "html", "utf-8")
|
||
msg["From"] = from_header
|
||
msg["To"] = to_addr
|
||
msg["Subject"] = Header(subject, "utf-8").encode()
|
||
|
||
with SMTP_SSL(settings.SMTP_HOST, settings.SMTP_PORT, timeout=10) as server:
|
||
server.login(settings.SMTP_USER, settings.SMTP_PASSWORD)
|
||
server.sendmail(from_addr, [to_addr], msg.as_string())
|
||
|
||
|
||
def send_reset_code_email(to_addr: str, code: str, expire_seconds: int) -> None:
|
||
"""发送找回密码验证码邮件。"""
|
||
try:
|
||
send_email(
|
||
to_addr=to_addr,
|
||
subject="【dpb】找回密码验证码",
|
||
html_body=(
|
||
f"<p>您好,</p>"
|
||
f"<p>您正在申请找回密码,验证码为:</p>"
|
||
f'<p style="font-size:24px;font-weight:bold;color:#1677ff;letter-spacing:4px;">{code}</p>'
|
||
f"<p>验证码 {expire_seconds // 60} 分钟内有效,请勿泄露给他人。</p>"
|
||
f"<p>若非本人操作,请忽略本邮件。</p>"
|
||
),
|
||
)
|
||
except SMTPException as e:
|
||
logger.error(f"发送验证码邮件失败 -> {to_addr}: {e!s}")
|
||
raise
|
||
except Exception as e: # noqa: BLE001
|
||
logger.error(f"发送验证码邮件异常 -> {to_addr}: {e!s}")
|
||
raise
|