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
|