57 lines
1.6 KiB
Python
57 lines
1.6 KiB
Python
# app/services/mailer.py
|
||
import smtplib
|
||
import ssl
|
||
from email.message import EmailMessage
|
||
|
||
from app.core.config import get_app_settings
|
||
|
||
|
||
def send_email(to_email: str, subject: str, html: str) -> None:
|
||
"""
|
||
发送邮件:
|
||
- 端口为 465 时使用 SSL 直连(SMTP_SSL)
|
||
- 其他端口:按配置 smtp_tls 决定是否 STARTTLS
|
||
"""
|
||
s = get_app_settings()
|
||
|
||
host = s.smtp_host
|
||
port = int(s.smtp_port)
|
||
use_starttls = bool(s.smtp_tls)
|
||
|
||
# SecretStr / Optional 兼容处理
|
||
smtp_user = s.smtp_user.get_secret_value() if getattr(s, "smtp_user", None) else None
|
||
smtp_pass = s.smtp_password.get_secret_value() if getattr(s, "smtp_password", None) else None
|
||
|
||
msg = EmailMessage()
|
||
msg["From"] = str(s.mail_from) # EmailStr -> str
|
||
msg["To"] = to_email
|
||
msg["Subject"] = subject
|
||
# 纯文本 + HTML(多部件)
|
||
msg.set_content("Your mail client does not support HTML.")
|
||
msg.add_alternative(html, subtype="html")
|
||
|
||
ctx = ssl.create_default_context()
|
||
|
||
# === 建立连接 ===
|
||
if port == 465:
|
||
server = smtplib.SMTP_SSL(host, port, context=ctx, timeout=20)
|
||
else:
|
||
server = smtplib.SMTP(host, port, timeout=20)
|
||
server.ehlo()
|
||
if use_starttls:
|
||
server.starttls(context=ctx)
|
||
server.ehlo()
|
||
|
||
try:
|
||
# 如配置了用户名/密码,则登录
|
||
if smtp_user and smtp_pass:
|
||
server.login(smtp_user, smtp_pass)
|
||
|
||
server.send_message(msg)
|
||
finally:
|
||
try:
|
||
server.quit()
|
||
except Exception:
|
||
# 连接已断开也无妨,忽略
|
||
pass
|