v1.7.0: 每日定时报告(工作日9:00盘前分析/15:30盘后总结) - 全球市场数据+报告引擎(简版邮件正文+详细版HTML附件)+cron定时+手动触发+发送日志; 修复模拟数据换手率失真

This commit is contained in:
2026-08-20 00:08:39 +08:00
parent 7d8ed3d7de
commit adc54d509f
8 changed files with 631 additions and 6 deletions
+17 -3
View File
@@ -30,11 +30,25 @@ STRONG_WORDS = ["回购", "中标", "减持", "问询", "停牌", "重组", "预
# ===================================================================== 邮件
def send_email(subject, html_body, to=None, cfg=None, sender_name=None):
"""发送 HTML 邮件。cfg 来自设置;失败抛异常(调用方捕获)"""
def send_email(subject, html_body, to=None, cfg=None, sender_name=None, attachments=None):
"""发送 HTML 邮件。cfg 来自设置;attachments: [{filename, content(bytes)}]失败抛异常"""
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
cfg = cfg or mail_config()
to = to or cfg["email_to"]
msg = MIMEText(html_body, "html", "utf-8")
if attachments:
msg = MIMEMultipart()
msg.attach(MIMEText(html_body, "html", "utf-8"))
for att in attachments:
part = MIMEBase("application", "octet-stream")
part.set_payload(att.get("content") or b"")
encoders.encode_base64(part)
part.add_header("Content-Disposition", "attachment",
filename=("utf-8", "", att.get("filename", "report.html")))
msg.attach(part)
else:
msg = MIMEText(html_body, "html", "utf-8")
msg["From"] = formataddr((sender_name or cfg["sender_name"], cfg["smtp_user"]))
msg["To"] = to
msg["Subject"] = subject