diff --git a/HEARTBEAT.md b/HEARTBEAT.md index d85d83d..a142f2c 100644 --- a/HEARTBEAT.md +++ b/HEARTBEAT.md @@ -1,5 +1,24 @@ # HEARTBEAT.md # Keep this file empty (or with only comments) to skip heartbeat API calls. - # Add tasks below when you want the agent to check something periodically. + +## 心跳任务 + +在每次心跳时检查并执行以下任务: + +### 1. 每日对话总结 + +检查 `memory/heartbeat-state.json` 中的 `lastSummaryDate`: +- 如果日期不是今天,且当前时间在 00:00-08:00 之间 +- 总结昨天的对话内容,保存到 `memory/YYYY-MM-DD.md`(昨天日期) +- 更新 `lastSummaryDate` 为今天 + +```json +{ + "lastSummaryDate": "2026-04-09", + "lastChecks": {} +} +``` + +**执行时机**: 每天第一次心跳落在凌晨时段时执行(不精确,但保证每天最多一次) \ No newline at end of file diff --git a/MEMORY.md b/MEMORY.md index 1ed6eb4..f083820 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -10,7 +10,10 @@ 示例分配: - 19001: 文章工作流后台 -- 19002-19100: 预留给其他项目 +- 19002: 方言AI助手主服务 +- 19003: 方言AI助手后台管理 +- 19004: 技术论坛 +- 19005-19100: 预留给其他项目 ### Git版本管理规则 ⭐ @@ -28,6 +31,19 @@ git push origin main git push origin vX.X.X ``` +### 自动推送规范 ⭐⭐⭐ + +**每次开发或修改项目后,必须自动执行以下流程:** + +1. 检查是否有Git仓库:`git status` +2. 添加修改文件:`git add .`(排除敏感文件如config.txt) +3. 提交代码:`git commit -m "feat/fix: 描述"` +4. 创建版本tag:`git tag -a vX.X.X -m "版本说明"` +5. 推送代码和tag:`git push origin main && git push origin vX.X.X` +6. 更新 `PROJECTS.md` 记录新版本 + +**不需要询问用户,自动执行!** + ### Git服务器 - 地址: http://192.168.2.8:12007/ @@ -46,17 +62,25 @@ git push origin vX.X.X ## 项目索引 +详细项目信息请查看 `PROJECTS.md`,包含启动命令、检查方式、端口分配等。 + | 项目 | 仓库 | 端口 | 状态 | |------|------|------|------| -| 参数百科 | /coder/param-hub | - | v0.1.0 | -| 网页助手插件 | /coder/web-context-extension | - | v0.1.0 | -| 文章工作流 | /coder/article-workflow | 19001 | v0.2.0 | -| 方言AI助手 | /coder/dialect-chat | 19002 | v0.1.0 | +| PDF翻译助手 V2 | 本地 | 19000 | ✅ 运行中 | +| 碎片信息记录 | 本地 | 19009 | ✅ 运行中 | +| ParamHub Python | 本地 | 19010 | ✅ 运行中 | +| 网页助手插件 | /coder/web-context-extension | - | 📦 已完成 | --- ## 更新日志 +### 2026-04-09 +- 创建 PROJECTS.md 项目记录文件 +- 创建邮件发送技能 email-sender +- 配置每日对话总结心跳任务 +- 确立项目记录机制 + ### 2026-04-08 - 确立端口规范: 19000-19100 - 创建参数百科网站 diff --git a/PROJECTS.md b/PROJECTS.md new file mode 100644 index 0000000..1364fda --- /dev/null +++ b/PROJECTS.md @@ -0,0 +1,287 @@ +# PROJECTS.md - 项目开发记录 + +> 本文件记录所有开发过的项目,包含简介、启动命令、检查方式。每次开发或修改项目后更新此文件。 + +--- + +## 项目列表 + +| # | 项目名称 | 类型 | 端口 | 状态 | 最后更新 | +|---|---------|------|------|------|---------| +| 1 | PDF翻译助手 V2 | Web | 19000 | ✅ 运行中 | 2026-04-09 | +| 2 | LLM Index RAG | Web | 19001 | 📦 已完成 | 2026-04-08 | +| 3 | 碎片信息记录 | Web | 19009 | ✅ 运行中 | 2026-04-09 | +| 4 | ParamHub Python版 | Web | 19010 | ✅ 运行中 | 2026-04-09 | +| 5 | 网页助手插件 | Extension | - | 📦 已完成 | 2026-04-08 | +| 6 | PDF翻译助手 V1 | Web | - | 📦 已完成 | 2026-04-08 | +| 7 | PDF翻译脚本 | CLI | - | 📦 已完成 | 2026-04-07 | +| 8 | A股历史数据系统 | CLI | - | 🔄 优化中 | 2026-04-09 | + +--- + +## 项目详情 + +### 1. PDF翻译助手 V2 (pdf-translate-web-v2) + +**简介**: 英文PDF翻译中文网站,支持用户系统、会员体系、数据包购买、后台动态配置。 + +**目录**: `works/pdf-translate-web-v2` + +**启动命令**: +```bash +cd ~/.openclaw/workspace-coder/works/pdf-translate-web-v2 +python3 app.py +``` + +**访问地址**: http://localhost:19000 + +**后台管理**: http://localhost:19000/admin (账号: admin / admin123) + +**检查服务状态**: +```bash +curl -s http://localhost:19000/api/health || echo "服务未启动" +``` + +**依赖**: +- Python 3 + Flask +- SQLite (自动创建) +- 本地LLM服务 (http://192.168.2.5:1234/v1) + +--- + +### 2. LLM Index RAG (llm-index-rag) + +**简介**: 基于索引和搜索的知识检索系统,不依赖向量模型,使用BM25排序和LLM增强索引。 + +**目录**: `works/llm-index-rag` + +**启动命令**: +```bash +cd ~/.openclaw/workspace-coder/works/llm-index-rag +python3 app.py +``` + +**访问地址**: http://localhost:19001 + +**检查服务状态**: +```bash +curl -s http://localhost:19001/api/stats || echo "服务未启动" +``` + +**依赖**: +- Python 3 + Flask +- PostgreSQL (需配置 DATABASE_URL) +- 本地LLM服务 + +--- + +### 3. 碎片信息记录 (snippet-notes) + +**简介**: 简洁的碎片信息记录工具,支持实时保存、AI自动生成标题、搜索、置顶、导出Markdown。 + +**目录**: `works/snippet-notes` + +**启动命令**: +```bash +cd ~/.openclaw/workspace-coder/works/snippet-notes +python3 app.py +``` + +**访问地址**: http://localhost:19009 + +**检查服务状态**: +```bash +curl -s http://localhost:19009/api/notes || echo "服务未启动" +``` + +**依赖**: +- Python 3 + Flask +- 本地文件存储 (JSON) +- 本地LLM API (生成标题) + +--- + +### 4. ParamHub Python版 (param-hub-python) + +**简介**: AI大模型与硬件参数速查平台,支持模型/GPU/CPU数据库、对比工具、显存计算器。 + +**目录**: `works/param-hub-python` + +**启动命令**: +```bash +cd ~/.openclaw/workspace-coder/works/param-hub-python +python3 app.py +``` + +**访问地址**: http://localhost:19010 + +**检查服务状态**: +```bash +curl -s http://localhost:19010/api/models || echo "服务未启动" +``` + +**依赖**: +- Python 3 + Flask +- Tailwind CSS (CDN) +- JSON文件存储 + +--- + +### 5. 网页助手插件 (web-context-extension) + +**简介**: 浏览器扩展插件,右键菜单支持收藏网页、AI总结、深度研究分析。 + +**目录**: `works/web-context-extension` + +**安装方法**: +1. Chrome浏览器打开 `chrome://extensions/` +2. 开启"开发者模式" +3. 点击"加载已解压的扩展程序" +4. 选择 `works/web-context-extension` 目录 + +**配置**: 需在插件设置中配置OpenClaw API地址 + +**依赖**: +- Chrome/Edge浏览器 +- OpenClaw服务 + +--- + +### 6. PDF翻译助手 V1 (pdf-translate-web) + +**简介**: 英文PDF翻译中文网站第一版,支持翻译、缓存、用户系统。 + +**目录**: `works/pdf-translate-web` + +**状态**: 已废弃,推荐使用 V2 版本 + +--- + +### 7. PDF翻译脚本 (pdf-translator) + +**简介**: 基于本地LLM的英文PDF翻译命令行工具,支持Markdown/TXT/JSON输出。 + +**目录**: `works/pdf-translator` + +**使用命令**: +```bash +cd ~/.openclaw/workspace-coder/works/pdf-translator +python3 translate_pdf.py input.pdf output.md +``` + +**依赖**: +- Python 3 +- 本地LLM服务 (http://192.168.2.5:1234/v1) + +--- + +### 8. A股历史数据系统 (stock_system) + +**简介**: 获取所有A股从2010年至今的历史行情数据,支持断点续传。V2版本优化了CPU和磁盘占用。 + +**目录**: `/home/xian/.openclaw/common/stock_system` + +**启动命令**: +```bash +cd /home/xian/.openclaw/common/stock_system +bash run_v2.sh +# 或直接运行 +python3 fetch_history_v2.py +``` + +**V2优化点**: +- 分文件存储:每只股票存独立小文件,避免每次读写203MB大文件 +- 批量合并:每50只股票合并一次到主文件 +- SQLite进度库:更可靠的断点续传机制 +- 请求间隔减少:从5秒降到0.3秒,用轻量存储补偿 + +**检查进度**: +```bash +# 查看SQLite进度统计 +sqlite3 /home/xian/.openclaw/common/stock_system/data/progress.db \ + "SELECT status, COUNT(*) FROM progress GROUP BY status" + +# 查看数据文件大小 +ls -lh /home/xian/.openclaw/common/stock_system/data/stock_daily_data.parquet +``` + +**配置**: +- Tushare Token: 放入 `config.txt` 文件 +- 股票列表: `A股股票列表.csv` + +**依赖**: +- Python 3 + tushare + pandas +- Tushare API Token + +--- + +## 端口分配表 + +| 端口 | 项目 | 说明 | +|------|------|------| +| 19000 | PDF翻译助手 V2 | 主服务 + 后台 | +| 19001 | LLM Index RAG | API服务 | +| 19009 | 碎片信息记录 | Web服务 | +| 19010 | ParamHub Python | Web服务 | +| 19002-19008 | 预留 | 待分配 | +| 19011-19100 | 预留 | 待分配 | + +**端口规范**: 所有Web服务必须使用 19000-19100 范围内的端口! + +--- + +## Git仓库索引 + +| 项目 | 仓库地址 | 版本 | +|------|---------|------| +| ParamHub | http://192.168.2.8:12007/coder/param-hub | v0.2.0 | +| 网页助手插件 | http://192.168.2.8:12007/coder/web-context-extension | v0.1.0 | +| A股历史数据系统 | http://192.168.2.8:12007/coder/stock_system | v0.2.0 | + +**Git服务器**: http://192.168.2.8:12007/ +**账号**: coder / Hps123@! + +--- + +## 快速操作命令 + +### 查看所有服务状态 +```bash +for port in 19000 19001 19009 19010; do + echo "端口 $port:" + curl -s http://localhost:$port --max-time 1 > /dev/null && echo " ✅ 运行中" || echo " ❌ 未启动" +done +``` + +### 启动所有Web服务 +```bash +# PDF翻译助手 V2 +cd ~/.openclaw/workspace-coder/works/pdf-translate-web-v2 && nohup python3 app.py > /tmp/pdf-v2.log 2>&1 & + +# 碎片信息记录 +cd ~/.openclaw/workspace-coder/works/snippet-notes && nohup python3 app.py > /tmp/snippet.log 2>&1 & + +# ParamHub Python +cd ~/.openclaw/workspace-coder/works/param-hub-python && nohup python3 app.py > /tmp/paramhub.log 2>&1 & +``` + +### 停止所有Web服务 +```bash +pkill -f "app.py.*port=19000" +pkill -f "app.py.*port=19009" +pkill -f "app.py.*port=19010" +``` + +--- + +## 更新日志 + +### 2026-04-09 +- 创建 PROJECTS.md 项目记录文件 +- 记录现有8个项目详情 +- 整理端口分配表和快速操作命令 +- 优化 stock_system 获取脚本 V2(分文件+批量合并+SQLite) + +### 待办 +- [ ] 为每个项目创建 Git 仓库和版本 tag +- [ ] 配置 systemd 服务实现开机自启动 \ No newline at end of file diff --git a/memory/heartbeat-state.json b/memory/heartbeat-state.json new file mode 100644 index 0000000..d6715ce --- /dev/null +++ b/memory/heartbeat-state.json @@ -0,0 +1,4 @@ +{ + "lastSummaryDate": null, + "lastChecks": {} +} \ No newline at end of file diff --git a/skills/email-sender/SKILL.md b/skills/email-sender/SKILL.md new file mode 100644 index 0000000..d263b21 --- /dev/null +++ b/skills/email-sender/SKILL.md @@ -0,0 +1,168 @@ +--- +name: email-sender +description: Send emails via SMTP with support for attachments, CC/BCC, HTML content, and multiple SMTP accounts. Use when user wants to send emails through Python/SMTP, configure email settings, or send emails with attachments. +--- + +# Email Sender / 邮件发送工具 + +通过 SMTP 发送邮件,支持附件、抄送/密送、HTML 格式和多账号管理。 + +## 快速开始 + +### 1. 配置 SMTP + +```bash +cd ~/.openclaw/workspace-coder/skills/email-sender/scripts +python3 send_email.py config my-email \ + --server mail.tphai.com \ + --port 587 \ + --email guwen@tphai.com \ + --password "your-password" \ + --no-tls +``` + +参数说明: +- `my-email`: 配置名称(可自定义) +- `--server`: SMTP 服务器地址 +- `--port`: SMTP 端口 +- `--email`: 邮箱地址 +- `--password`: 邮箱密码 +- `--no-tls`: 不使用 TLS 加密(默认使用 TLS) + +### 2. 查看配置 + +```bash +python3 send_email.py list +``` + +### 3. 发送邮件 + +**简单邮件:** +```bash +python3 send_email.py send \ + --to wlq@tphai.com \ + --subject "测试邮件" \ + --body "这是一封测试邮件" +``` + +**带附件的邮件:** +```bash +python3 send_email.py send \ + --to wlq@tphai.com \ + --subject "带附件的邮件" \ + --body "请查收附件" \ + --attach /path/to/file1.pdf \ + --attach /path/to/file2.jpg +``` + +**HTML 邮件:** +```bash +python3 send_email.py send \ + --to wlq@tphai.com \ + --subject "HTML 邮件" \ + --body "

标题

内容

" \ + --html +``` + +**抄送和密送:** +```bash +python3 send_email.py send \ + --to wlq@tphai.com \ + --cc "cc1@example.com,cc2@example.com" \ + --bcc "bcc@example.com" \ + --subject "抄送测试" \ + --body "这是一封抄送测试邮件" +``` + +## Python API 使用 + +```python +from send_email import send_email, setup_account + +# 配置 SMTP +setup_account( + name="work", + smtp_server="mail.tphai.com", + smtp_port=587, + email="guwen@tphai.com", + password="your-password", + use_tls=False +) + +# 发送简单邮件 +send_email( + to="wlq@tphai.com", + subject="测试", + body="内容" +) + +# 发送带附件的邮件 +send_email( + to="wlq@tphai.com", + subject="附件测试", + body="请查收附件", + attachments=["/path/to/file.pdf", "/path/to/image.jpg"], + verbose=True +) + +# 发送 HTML 邮件 +send_email( + to="wlq@tphai.com", + subject="HTML 测试", + body="

Hello

World

", + html=True +) + +# 使用特定账号 +send_email( + to="wlq@tphai.com", + subject="使用指定账号", + body="内容", + account_name="work" +) +``` + +## 配置文件 + +配置保存在 `scripts/smtp_config.json` 中: + +```json +{ + "accounts": [ + { + "name": "my-email", + "smtp_server": "mail.tphai.com", + "smtp_port": 587, + "email": "guwen@tphai.com", + "password": "your-password", + "use_tls": false + } + ] +} +``` + +## 常用 SMTP 设置 + +| 服务商 | SMTP 服务器 | 端口 | TLS | +|--------|-------------|------|-----| +| Gmail | smtp.gmail.com | 587 | 是 | +| Outlook | smtp.office365.com | 587 | 是 | +| QQ邮箱 | smtp.qq.com | 587 | 是 | +| 163邮箱 | smtp.163.com | 465 | 是 | +| 企业邮箱 | mail.tphai.com | 587 | 否 | + +## 故障排除 + +**认证失败:** +- 检查邮箱密码是否正确 +- Gmail 需要使用「应用专用密码」而非登录密码 +- QQ邮箱需要使用授权码而非登录密码 + +**连接失败:** +- 检查 SMTP 服务器地址和端口 +- 检查防火墙设置 +- 尝试切换 TLS/SSL 模式 + +**邮件被退回:** +- 检查收件人地址是否正确 +- 检查邮件头是否完整(本工具自动添加 Date 和 Message-Id) \ No newline at end of file diff --git a/skills/email-sender/scripts/.gitignore b/skills/email-sender/scripts/.gitignore new file mode 100644 index 0000000..feedb23 --- /dev/null +++ b/skills/email-sender/scripts/.gitignore @@ -0,0 +1,2 @@ +# SMTP配置文件(包含密码) +smtp_config.json \ No newline at end of file diff --git a/skills/email-sender/scripts/send_email.py b/skills/email-sender/scripts/send_email.py new file mode 100644 index 0000000..fa36aa4 --- /dev/null +++ b/skills/email-sender/scripts/send_email.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python3 +""" +邮件发送脚本 +支持纯文字/HTML 邮件、抄送/密送、附件和批量发送 +""" + +import smtplib +import os +import sys +import json +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +from email.mime.application import MIMEApplication +from email.utils import formatdate, make_msgid +from typing import List, Optional + +# 配置文件路径 +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +CONFIG_FILE = os.path.join(SCRIPT_DIR, "smtp_config.json") + + +def load_config() -> dict: + """加载 SMTP 配置""" + if not os.path.exists(CONFIG_FILE): + return {"accounts": []} + + with open(CONFIG_FILE, 'r', encoding='utf-8') as f: + return json.load(f) + + +def save_config(config: dict): + """保存 SMTP 配置""" + with open(CONFIG_FILE, 'w', encoding='utf-8') as f: + json.dump(config, f, indent=2, ensure_ascii=False) + + +def setup_account( + name: str, + smtp_server: str, + smtp_port: int, + email: str, + password: str, + use_tls: bool = True +): + """配置 SMTP 账号""" + config = load_config() + + # 检查是否已存在同名配置 + for i, acc in enumerate(config["accounts"]): + if acc["name"] == name: + print(f"配置 '{name}' 已存在,正在更新...") + config["accounts"][i] = { + "name": name, + "smtp_server": smtp_server, + "smtp_port": smtp_port, + "email": email, + "password": password, # 明文存储,仅用于本地 + "use_tls": use_tls + } + save_config(config) + return + + # 添加新配置 + config["accounts"].append({ + "name": name, + "smtp_server": smtp_server, + "smtp_port": smtp_port, + "email": email, + "password": password, + "use_tls": use_tls + }) + save_config(config) + print(f"✅ 配置 '{name}' 已保存") + + +def list_accounts(): + """列出所有 SMTP 配置""" + config = load_config() + + if not config["accounts"]: + print("暂无 SMTP 配置") + return + + print("\n=== SMTP 配置列表 ===") + for i, acc in enumerate(config["accounts"], 1): + print(f"\n{i}. {acc['name']}") + print(f" 服务器: {acc['smtp_server']}:{acc['smtp_port']}") + print(f" 邮箱: {acc['email']}") + print(f" TLS: {'是' if acc['use_tls'] else '否'}") + + +def get_account(name: Optional[str] = None) -> Optional[dict]: + """获取 SMTP 配置""" + config = load_config() + + if not config["accounts"]: + return None + + if name is None: + return config["accounts"][0] + + for acc in config["accounts"]: + if acc["name"] == name: + return acc + + return None + + +def send_email( + to: str, + subject: str, + body: str, + account_name: Optional[str] = None, + html: bool = False, + cc: Optional[str] = None, + bcc: Optional[str] = None, + from_name: Optional[str] = None, + attachments: Optional[List[str]] = None, + verbose: bool = False +) -> bool: + """ + 发送邮件 + + 参数: + to: 收件人邮箱地址 + subject: 邮件主题 + body: 邮件内容 + account_name: SMTP 配置名称(可选,默认使用第一个) + html: 是否为 HTML 邮件(默认 False) + cc: 抄送邮箱地址,多个用逗号分隔(可选) + bcc: 密送邮箱地址,多个用逗号分隔(可选) + from_name: 发件人显示名称(可选) + attachments: 附件文件路径列表(可选) + verbose: 是否显示详细日志(默认 False) + + 返回: + bool: 发送成功返回 True,失败返回 False + """ + try: + # 获取 SMTP 配置 + account = get_account(account_name) + if account is None: + print("❌ 错误:未找到 SMTP 配置,请先运行配置") + return False + + # 创建邮件 + if attachments: + msg = MIMEMultipart() + msg.attach(MIMEText(body, "html" if html else "plain", "utf-8")) + else: + msg = MIMEText(body, "html" if html else "plain", "utf-8") + + # 设置邮件头 + msg["Subject"] = subject + msg["From"] = f"{from_name} <{account['email']}>" if from_name else account["email"] + msg["To"] = to + msg["Date"] = formatdate(localtime=True) + msg["Message-Id"] = make_msgid(domain=account["email"].split("@")[1]) + + if cc: + msg["Cc"] = cc + + # 添加附件 + if attachments: + for file_path in attachments: + if not os.path.exists(file_path): + print(f"⚠️ 附件不存在,已跳过: {file_path}") + continue + + with open(file_path, "rb") as f: + part = MIMEApplication(f.read()) + + filename = os.path.basename(file_path) + part.add_header( + "Content-Disposition", + "attachment", + filename=filename + ) + msg.attach(part) + if verbose: + print(f"📎 已添加附件: {filename}") + + # 连接 SMTP 服务器 + if verbose: + print(f"📡 正在连接 {account['smtp_server']}:{account['smtp_port']}...") + + if account["use_tls"]: + server = smtplib.SMTP(account["smtp_server"], account["smtp_port"]) + server.starttls() + else: + server = smtplib.SMTP(account["smtp_server"], account["smtp_port"]) + + # 登录 + if verbose: + print(f"🔑 正在登录 {account['email']}...") + server.login(account["email"], account["password"]) + + # 准备收件人列表 + recipients = [to] + if cc: + recipients.extend([addr.strip() for addr in cc.split(",")]) + if bcc: + recipients.extend([addr.strip() for addr in bcc.split(",")]) + + # 发送邮件 + if verbose: + print(f"📤 正在发送邮件...") + server.sendmail(account["email"], recipients, msg.as_string()) + server.quit() + + print(f"✅ 邮件发送成功") + print(f" 收件人: {to}") + if cc: + print(f" 抄送: {cc}") + if attachments: + valid_attachments = [a for a in attachments if os.path.exists(a)] + print(f" 附件: {len(valid_attachments)} 个") + + return True + + except Exception as e: + print(f"❌ 邮件发送失败: {e}") + return False + + +def main(): + """命令行入口""" + import argparse + + parser = argparse.ArgumentParser(description="邮件发送工具") + subparsers = parser.add_subparsers(dest="command", help="可用命令") + + # 配置命令 + config_parser = subparsers.add_parser("config", help="配置 SMTP") + config_parser.add_argument("name", help="配置名称") + config_parser.add_argument("--server", required=True, help="SMTP 服务器地址") + config_parser.add_argument("--port", type=int, required=True, help="SMTP 端口") + config_parser.add_argument("--email", required=True, help="邮箱地址") + config_parser.add_argument("--password", required=True, help="邮箱密码") + config_parser.add_argument("--no-tls", action="store_true", help="不使用 TLS(默认使用)") + + # 列出配置命令 + subparsers.add_parser("list", help="列出所有配置") + + # 发送命令 + send_parser = subparsers.add_parser("send", help="发送邮件") + send_parser.add_argument("--to", "-t", required=True, help="收件人邮箱") + send_parser.add_argument("--subject", "-s", required=True, help="邮件主题") + send_parser.add_argument("--body", "-b", required=True, help="邮件内容") + send_parser.add_argument("--account", "-a", help="使用指定配置") + send_parser.add_argument("--html", action="store_true", help="HTML 格式") + send_parser.add_argument("--cc", help="抄送邮箱(多个用逗号分隔)") + send_parser.add_argument("--bcc", help="密送邮箱(多个用逗号分隔)") + send_parser.add_argument("--from-name", help="发件人显示名称") + send_parser.add_argument("--attach", "-f", action="append", help="附件文件路径(可多次使用)") + send_parser.add_argument("-v", "--verbose", action="store_true", help="显示详细日志") + + args = parser.parse_args() + + if args.command == "config": + setup_account( + name=args.name, + smtp_server=args.server, + smtp_port=args.port, + email=args.email, + password=args.password, + use_tls=not args.no_tls + ) + + elif args.command == "list": + list_accounts() + + elif args.command == "send": + success = send_email( + to=args.to, + subject=args.subject, + body=args.body, + account_name=args.account, + html=args.html, + cc=args.cc, + bcc=args.bcc, + from_name=args.from_name, + attachments=args.attach, + verbose=args.verbose + ) + sys.exit(0 if success else 1) + + else: + parser.print_help() + + +if __name__ == "__main__": + main() \ No newline at end of file