68 lines
2.3 KiB
Python
68 lines
2.3 KiB
Python
import smtplib
|
|
import logging
|
|
from email.mime.text import MIMEText
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.base import MIMEBase
|
|
from email import encoders
|
|
from pathlib import Path
|
|
from src.config import EmailAccount
|
|
from src.retry import retry
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@retry()
|
|
def send_reply(account: EmailAccount, to_addr: str, subject: str, body: str,
|
|
attachments: list[tuple[str, str]] | None = None):
|
|
"""发送回复邮件,支持附件。
|
|
|
|
Args:
|
|
attachments: [(本地文件路径, mime_type), ...] 列表
|
|
"""
|
|
if not account.smtp:
|
|
raise RuntimeError(f"账号 {account.username} 未配置 SMTP")
|
|
|
|
s = account.smtp
|
|
logger.info("SMTP 连接: %s:%d (ssl=%s)", s.server, s.port, s.ssl)
|
|
if s.ssl:
|
|
conn = smtplib.SMTP_SSL(s.server, s.port, timeout=15)
|
|
else:
|
|
conn = smtplib.SMTP(s.server, s.port, timeout=15)
|
|
if s.starttls:
|
|
conn.starttls()
|
|
|
|
conn.login(account.username, account.password)
|
|
logger.info("SMTP 登录成功")
|
|
|
|
reply_subject = subject if subject.lower().startswith("re:") else f"Re: {subject}"
|
|
logger.info("SMTP 发送: to=%s subject=%s body=%d 字符 attachments=%d",
|
|
to_addr, reply_subject, len(body), len(attachments or []))
|
|
|
|
if attachments:
|
|
msg = MIMEMultipart()
|
|
msg.attach(MIMEText(body, "plain", "utf-8"))
|
|
for filepath, mime_type in attachments:
|
|
p = Path(filepath)
|
|
if not p.exists():
|
|
logger.warning(" 附件不存在: %s", filepath)
|
|
continue
|
|
maintype, subtype = mime_type.split("/", 1)
|
|
with open(p, "rb") as f:
|
|
part = MIMEBase(maintype, subtype)
|
|
part.set_payload(f.read())
|
|
encoders.encode_base64(part)
|
|
part.add_header("Content-Disposition", "attachment", filename=p.name)
|
|
msg.attach(part)
|
|
logger.info(" 添加附件: %s (%s, %d bytes)", p.name, mime_type, p.stat().st_size)
|
|
else:
|
|
msg = MIMEMultipart("alternative")
|
|
msg.attach(MIMEText(body, "plain", "utf-8"))
|
|
|
|
msg["From"] = account.username
|
|
msg["To"] = to_addr
|
|
msg["Subject"] = reply_subject
|
|
|
|
conn.sendmail(account.username, [to_addr], msg.as_string())
|
|
conn.quit()
|
|
logger.info("SMTP 发送完成")
|