init: 初始化 dpb 桃育种系统代码库

前后端 + 后端 FastAPI 全量源码、部署脚本与文档。
This commit is contained in:
34047007@qq.com
2026-08-06 00:17:49 +08:00
commit b95053c52c
1469 changed files with 322298 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
"""邮件发送工具(基于标准库 smtplib,465 端口 SSL)。
配置来自 app.config.setting.settingsSMTP_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