文件预览

send_email.py

查看 GoToEmail — 邮箱绑定 技能包中的文件内容。

文件内容

scripts/send_email.py

#!/usr/bin/env python3
"""
GoToEmail — send_email.py
通过 SMTP SSL 发送邮件。

输入(JSON via stdin):
{
  "email":      "sender@163.com",
  "password":   "授权码",
  "smtp_host":  "smtp.163.com",
  "smtp_port":  465,                          // 可选,默认 465
  "to":         "recipient@example.com",      // 字符串或列表
  "subject":    "邮件主题",
  "body":       "纯文本正文",
  "html_body":  "<p>HTML正文</p>",            // 可选
  "cc":         ["cc1@example.com"],          // 可选,字符串或列表
  "bcc":        []                            // 可选,字符串或列表
}

输出(JSON):
成功: {"ok": true, "message": "邮件已成功发送至 recipient@example.com"}
失败: {"ok": false, "error": "SMTP认证失败: ..."}
"""

import smtplib
import ssl
import json
import sys
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart


def to_list(val) -> list:
    """将字符串或列表统一转为列表,过滤空值。"""
    if not val:
        return []
    if isinstance(val, str):
        return [v.strip() for v in val.split(",") if v.strip()]
    return [str(v).strip() for v in val if str(v).strip()]


def main():
    try:
        data = json.load(sys.stdin)
    except json.JSONDecodeError as e:
        print(json.dumps({"ok": False, "error": f"JSON解析失败: {e}"}, ensure_ascii=False))
        sys.exit(1)

    email_addr = data.get("email", "").strip()
    password   = data.get("password", "")
    smtp_host  = data.get("smtp_host", "").strip()
    smtp_port  = int(data.get("smtp_port", 465))

    to_list_   = to_list(data.get("to", []))
    cc_list    = to_list(data.get("cc", []))
    bcc_list   = to_list(data.get("bcc", []))
    subject    = data.get("subject", "(无主题)")
    body       = data.get("body", "")
    html_body  = data.get("html_body", "")

    if not all([email_addr, password, smtp_host]):
        print(json.dumps({"ok": False, "error": "缺少必要字段:email / password / smtp_host"}, ensure_ascii=False))
        sys.exit(1)

    if not to_list_:
        print(json.dumps({"ok": False, "error": "缺少收件人 (to)"}, ensure_ascii=False))
        sys.exit(1)

    # 构建邮件
    if html_body:
        msg = MIMEMultipart("alternative")
        msg.attach(MIMEText(body or "", "plain", "utf-8"))
        msg.attach(MIMEText(html_body, "html", "utf-8"))
    else:
        msg = MIMEText(body, "plain", "utf-8")

    msg["From"]    = email_addr
    msg["To"]      = ", ".join(to_list_)
    msg["Subject"] = subject
    if cc_list:
        msg["Cc"] = ", ".join(cc_list)

    all_recipients = to_list_ + cc_list + bcc_list

    try:
        ctx = ssl.create_default_context()
        with smtplib.SMTP_SSL(smtp_host, smtp_port, context=ctx) as s:
            s.login(email_addr, password)
            s.sendmail(email_addr, all_recipients, msg.as_string())

        print(json.dumps({
            "ok":      True,
            "message": f"邮件已成功发送至 {', '.join(to_list_)}",
        }, ensure_ascii=False))

    except smtplib.SMTPAuthenticationError as e:
        print(json.dumps({"ok": False, "error": f"SMTP认证失败: {e}"}, ensure_ascii=False))
        sys.exit(1)
    except smtplib.SMTPRecipientsRefused as e:
        print(json.dumps({"ok": False, "error": f"收件人被拒绝: {e}"}, ensure_ascii=False))
        sys.exit(1)
    except Exception as e:
        print(json.dumps({"ok": False, "error": str(e)}, ensure_ascii=False))
        sys.exit(1)


if __name__ == "__main__":
    main()