# Weekly Report Email

> 通用周报收集和邮件推送技能，支持交互式填写周报内容，自动计算周数和日期范围，生成美观的HTML格式邮件。

- Skill: `lord1egypt/weekly-report-email` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lord1egypt/weekly-report-email`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lord1egypt/weekly-report-email/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: Lord1Egypt (https://skillmd.com/u/lord1egypt)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/lord1egypt/weekly-report-email

---


# 周报技能 - xl-weekly-report-email

一个通用的周报收集和邮件推送技能，安装后配置邮箱即可使用。

## 触发方式
在对话中说"写周报"即可触发周报生成流程。

配置邮箱时说"配置周报邮箱"。

---

## ⚠️ 重要：执行此技能时必须严格遵循以下步骤，不得省略或跳过任何步骤！

**最关键的规则：**
- **每次只问一个问题，等用户回复后再问下一个**
- **绝对禁止一次性抛出所有问题**
- **绝对禁止在没有用户确认的情况下自动发送邮件！**
- **必须等待用户明确确认后才能发送邮件！**
- **任何用户回复的内容都应该被记录，除非用户明确回复"无"、"空"、"不需要"、"跳过"等否定词**
- **即使内容很短（如"2"、"无内容"等非否定词），也应该记录**
- **即使内容不按格式写，也应该直接展示，不当作空值处理**

---

## 📋 完整工作流程

### 第零步：检查配置

首次使用需要配置邮箱参数和报告参数。发送"配置周报邮箱"命令会自动引导你完成配置。

配置内容包括：
1. **SMTP服务器**：选择预设（腾讯企业邮箱、阿里企业邮箱、Gmail 等）或自定义
2. **SMTP端口**：通常是465（SSL）或587（TLS）
3. **邮箱账号**：你的邮箱地址
4. **邮箱密码**：邮箱登录密码或授权码
5. **发件人**：发件人邮箱地址（通常与账号相同）
6. **组织/部门名称**（可选）：如"XX公司"，会显示在邮件标题开头
7. **你的姓名**：如"张三"
8. **你的职位**：如"后端工程师"
9. **周报收件人**：接收周报的邮箱地址
10. **周报抄送人**（可选）：抄送周报的邮箱地址

**注意：**
- 组织/部门名称（`company`）字段可选，如果配置了会显示在邮件标题开头；如果不配置或为空，邮件标题中不会显示组织/部门名称和前面的"-"。
- 默认抄送人（`cc`）字段可选，如果配置了每次发送时都会抄送这些邮箱；如果不配置，则不抄送（除非发送时额外添加）。
- 邮箱配置会自动保存到 `.env` 文件（包含敏感信息，不会被发布到 clawhub）。
- 报告配置会保存到 `config.json` 文件。

### 第一步：计算并展示日期信息
**必须先执行这一步！**

自动计算并展示以下信息（所有时间必须是东八区）：
- 周数 = ISO周数（周五/周六/周日不减1，周四/周四之前减1）
- 截止日期 = 下周周四（YYYYMMDD 格式）
- 时间范围 = 本周四 到 下周三（中文格式：YYYY年MM月DD日）

**示例输出（如果今天是周五）：**
```
📊 周报日期信息：
- 周数：13
- 截止日期：20260402
- 时间范围：2026年3月26日 至 2026年4月1日
```

**⚠️ 警告：在计算并展示日期信息之前，不要询问任何周报内容！**

---

### 第二步：逐项收集周报内容

**⚠️ 关键规则：必须一个一个询问！禁止一次性抛出所有问题！**

每次只问一个问题，等用户回复后再问下一个。绝对不能把所有问题一次性列出来！

#### 第一部分：遗留问题/阻碍因素跟进

**执行顺序：**
1. 先给描述
2. 再给格式提示
3. 最后给示例
4. 等用户回复

**描述：**
列出上周遗留问题或当前最大的阻碍因素的跟进情况。

**格式：**
[问题描述][当前状态]：进展详情
**重要：** 必须使用方括号 `[]` 包裹问题描述和当前状态，否则没有样式！

**示例：**
```
1. [测试环境资源不足][已解决]：已申请新服务器，问题解决，进度已恢复。
2. [数据接口延迟问题][跟进中]：已联系数据负责人，承诺本周五前修复，目前正在联调。
```

**状态样式说明：**
- `已解决` 或 `Done` → 绿色样式 ✓
- 其他所有状态 → 蓝色样式 →

**⚠️ 格式提示与用户坚持的规则（重要！）：**

**用户输入内容不按格式时的处理流程：**

**情况1：用户第一次输入不按格式（如"111"、"完成开发任务"等）**
- AI **只提示一次**："建议格式是 [问题描述][当前状态]：进展详情，您确定要这样写吗？"
- 如果用户回复"确定"、"是的"、"就这么写"等确认词 → **直接记录用户之前输入的内容**（"111"）
- 如果用户回复"好的"、"明白了"等 → 重新询问用户第一部分内容
- 如果用户继续输入新的内容（不是确认词） → **直接记录用户新输入的内容**

**情况2：用户坚持使用不按格式的内容**
- 任何用户输入的内容，都应该被记录，除非用户明确回复"无"、"空"、"不需要"、"跳过"等否定词
- 即使内容很短（如"111"、"222"），也应该记录
- 即使内容不按格式写，也应该直接展示，用普通样式展示

**记住：**
- 格式提示只提示一次，不要重复提示
- 用户输入任何内容（除了明确的否定词），都要记录
- 不要问"您确定要这样写吗？"多次

**⚠️ 关键规则：**
- **任何用户回复的内容都应该被记录，除非用户明确回复"无"、"空"、"不需要"、"跳过"等否定词**
- **即使内容很短（如"2"、"123"），也应该记录**
- **即使内容不按格式写，也应该直接展示，不当作空值处理**

**⚠️ 禁止：** 不要问"第一部分是什么"，直接按照"描述→格式→示例"的顺序给用户！也不要继续问第二部分，等用户回复第一部分后再问！

---

#### 第二部分：本周具体产出

**执行顺序：**
1. 先给描述
2. 再给格式提示
3. 最后给示例
4. 等用户回复

**描述：**
列出本周具体的产出，建议按项目或模块分类。

**格式：**
[项目 xxx] 子项目名 + 项目状态 (Done/Doing 进度 X%/ Delay/ Suspend) + 进度详情/阶段成果/阻塞原因
**重要：** 必须使用方括号 `[]` 包裹项目名，状态必须用圆括号 `()` 包裹，否则没有样式！

**示例：**
```
1. [项目 A] 画像标签开发 (Doing 80%)
   完成了用户活跃度标签的逻辑重构，性能提升 30%。
   正在与业务方进行数据验收。
2. [数据治理] 人员数据质量优化 (Done)
   完成了历史脏数据的清洗工作，并补充了缺失的日志数据。
3. [项目 B] 人员表开发（Doing 80%/Delay）
   完成了 xxxx 的开发
   需求变动导致 delay
```

**状态样式说明：**
- `Done` → 绿色样式
- `Delay` → 橙色样式
- `Suspend` → 灰色样式
- `Doing 进度X%` 或其他状态 → 蓝色样式
- 组合状态（如 `Doing 80%/Delay`）会拆分成多个状态标签，分别显示对应样式

**⚠️ 格式提示与用户坚持的规则（重要！）：**

**用户输入内容不按格式时的处理流程：**

**情况1：用户第一次输入不按格式（如"222"、"完成开发任务"等）**
- AI **只提示一次**："建议格式是 [项目名] 任务名 (状态)，您确定要这样写吗？"
- 如果用户回复"确定"、"是的"、"就这么写"等确认词 → **直接记录用户之前输入的内容**（"222"）
- 如果用户回复"好的"、"明白了"等 → 重新询问用户第二部分内容
- 如果用户继续输入新的内容（不是确认词） → **直接记录用户新输入的内容**

**情况2：用户坚持使用不按格式的内容**
- 任何用户输入的内容，都应该被记录，除非用户明确回复"无"、"空"、"不需要"、"跳过"等否定词
- 即使内容很短（如"222"、"123"），也应该记录
- 即使内容不按格式写，也应该直接展示，用普通样式展示

**记住：**
- 格式提示只提示一次，不要重复提示
- 用户输入任何内容（除了明确的否定词），都要记录
- 不要问"您确定要这样写吗？"多次

**⚠️ 关键规则：**
- **任何用户回复的内容都应该被记录，除非用户明确回复"无"、"空"、"不需要"、"跳过"等否定词**
- **即使内容很短（如"2"、"123"），也应该记录**
- **即使内容不按格式写，也应该直接展示，不当作空值处理**

**⚠️ 禁止：** 同上，等用户回复第一部分后再问第二部分！不要问"第二部分是什么"，直接按顺序给！

---

#### 第三部分：技术难点/业务卡点

**执行顺序：**
1. 先给描述
2. 最后给示例
3. 等用户回复

**描述：**
这里重点写本周遇到的技术难点或业务卡点，以及你打算怎么解决。

**示例：**
```
1. 问题描述：需求频繁变更，导致开发返工。
   解决方案：已与产品经理约定，后续需求变更需通过 TAPD 更新 PRD 并邮件周知，重大变更需重新评估工时。
2. 问题描述：ClickHouse 查询超时。
   解决方案：通过分析慢查询日志，发现索引未命中，已优化 SQL 语句并增加二级索引。
```

**⚠️ 禁止：** 同上，等用户回复后再继续！

---

#### 第四部分：下周核心计划

**执行顺序：**
1. 先给描述
2. 最后给示例
3. 等用户回复

**描述：**
按优先级列出下周的核心产出承诺。

**示例：**
```
1. [计划 1]
2. [计划 2]
3. [计划 3]
```

**⚠️ 禁止：** 同上！

---

#### 第五部分：团队协作/流程/架构思考（非必选）

**执行顺序：**
1. 先给描述
2. 最后给示例
3. 等用户回复

**描述：**
不仅限于自己的代码，着眼于团队协作、流程、架构等宏观问题。这是周报中体现思考深度的部分。

**示例：**
```
1. 协作问题：[例如：数据上游经常口头变更字段，导致下游任务失败]。建议建立字段变更通知机制，必须经过审批群周知。
2. 架构/稳定性问题：[例如：当前实时任务单点故障风险较高]。建议将核心任务迁移至 Flink 集群，并配置拉起机制。
3. 业务痛点：[例如：业务方普遍反映离线数据产出时间太晚]。建议优化 DAG 调度依赖，将核心任务优先级提高。
```

**⚠️ 禁止：** 同上！

---

#### 第六部分：自由发挥区（非必选）

**执行顺序：**
1. 先给描述
2. 等用户回复

**描述：**
自由发挥区（心得体会、GET 技能、共鸣句子、个人思考等）

**⚠️ 禁止：** 同上！

---

### 第三步：保存周报内容（临时文件）
将所有内容写入 `memory/weekly-report-YYYYMMDD.md` 文件

**注意：** 这是临时文件，发送完邮件后会自动删除，不会保留。

**保存临时文件的方式：**
```javascript
const fs = require('fs');
const path = require('path');

// 生成文件名（用当前日期）
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, ''); // YYYYMMDD
const tempFile = path.join(__dirname, 'memory', `weekly-report-${dateStr}.md`);

// 确保目录存在
const memoryDir = path.join(__dirname, 'memory');
if (!fs.existsSync(memoryDir)) {
  fs.mkdirSync(memoryDir, { recursive: true });
}

// 写入文件
fs.writeFileSync(tempFile, content);
```

---

### 第四步：生成 HTML 预览

**⚠️ 必须使用 main.js！禁止自己手写 HTML！**

**正确方式：**
```bash
cd /home/node/.openclaw/workspace/skills/xl-weekly-report-email
nodejs main.js
```

**调用方式：**
- 先导入：`const { generateWeeklyReport } = require('./main.js');`
- 再生成：`const report = generateWeeklyReport(content);`
- 预览：把 `report.body` 给用户看

**禁止：**
- ❌ 自己写 HTML
- ❌ 直接输出文本
- ❌ 省略样式

**⚠️ 重要：生成预览后，给用户看HTML内容，然后问用户是否确认发送！绝对不要自动发送！**

---

### 第五步：询问额外抄送人（可跳过）

**⚠️ 在发送邮件前询问！**

**执行顺序：**
1. 询问用户是否有其他抄送人
2. 让用户填写抄送邮箱地址（多个用逗号分隔，全角逗号"，"或半角逗号","都可以）
3. 如果用户不填或填写"无"，则只使用配置的抄送人（如果配置了）

**示例：**
```
这次发送周报，是否需要添加其他抄送人？（可留空，多个邮箱用逗号分隔）
例如：boss@example.com,leader@example.com
```

---

### 第六步：发送邮件

**⚠️ 关键规则：必须等待用户明确确认后才能发送邮件！绝对禁止自动发送！**

**执行顺序：**
1. 生成 HTML 格式预览给用户确认
2. **明确询问用户：是否确认发送？**
3. **等待用户明确回复"确认"、"发送"、"是"等确认词**
4. **只有收到用户明确确认后，才能调用 `main.js` 中的 `generateAndSendReport(content, additionalCc, tempFilePath)` 函数发送邮件**
5. **如果用户回复"不"、"取消"、"修改"等否定词，则不发送，询问用户需要修改什么**
6. 邮件信息（收件人、抄送、发件人）处理逻辑：
   - 配置的抄送人 + 额外填写的抄送人 = 所有抄送人（自动去重）
   - 如果两者都没有，则不抄送任何人
7. 邮件发送成功后，自动删除临时文件 `memory/weekly-report-YYYYMMDD.md`

**⚠️ 严重警告：**
- **绝对禁止在生成预览后自动发送邮件！**
- **绝对禁止在没有用户确认的情况下调用发送函数！**
- **必须明确等待用户的确认回复！**
- `tempFilePath` 参数是第三步保存的临时文件路径
- 邮件发送成功后会自动清理，无需手动删除
- 如果需要手动清理，可以调用 `cleanupTempFile(filePath)` 函数

---

## 📧 邮件规则

- **标题格式**: 从 config.json 读取配置生成（姓名、职位会自动填入）
- **收件人**: 从 config.json 读取
- **抄送**: 从 config.json 读取（可选）
- **时间计算规则**:
  - 周数 = 当前周数 - 1（使用 ISO 标准周数，通过 Python 的 `isocalendar()` 方法计算）
  - 截止日期 = 本周周四（如果今天 <= 周四则取本周，如果今天 > 周四则取下周）
  - 时间范围 = 上周四 到 本周三

---

## 🔧 技术实现

### 核心文件
- `main.js`: 周报生成和发送主逻辑（日期计算、HTML生成、内容解析）
- `mailer.js`: 邮件发送模块（基于 nodemailer）
- `setup.js`: 首次配置引导
- `config.json`: 用户配置文件

### 依赖
- nodemailer: 邮件发送

### 发送邮件的正确方式

**方式1：使用 nodemailer（main.js 中已集成）**
```javascript
const { sendWeeklyReport } = require('./mailer');
await sendWeeklyReport(subject, htmlBody, recipient, cc);
```

**方式2：使用 imap-smtp-email/smtp.js 命令行（标准）**
```bash
cd /home/node/.openclaw/workspace/skills/imap-smtp-email/scripts
nodejs smtp.js send --to target@example.com --subject "标题" --html-file email.html
```

### ⚠️ 系统环境限制
- Node.js 命令是 `nodejs` 不是 `node`
- nodemailer 依赖在 `/home/node/.openclaw/workspace/skills/xl-weekly-report-email/node_modules`

---

## 📁 配置文件格式

### config.json（报告配置）

报告配置保存在 `config.json` 中：

```json
{
  "report": {
    "company": "XX公司",
    "name": "张三",
    "position": "后端工程师",
    "recipient": "manager@example.com",
    "cc": "cc@example.com"
  }
}
```

### .env（邮箱配置）

邮箱配置保存在 `.env` 文件中（首次使用请复制 `.env.example` 为 `.env`）：

```env
# SMTP 配置（发邮件）
SMTP_HOST=smtp.qiye.aliyun.com
SMTP_PORT=465
SMTP_SECURE=true
SMTP_USER=your-email@example.com
SMTP_PASS=your-password
SMTP_FROM=your-email@example.com
```

**说明：**
- `company` 字段可选，如果不配置或为空，邮件标题中不会显示组织/部门名称和前面的"-"
- 如果配置了 `company`，邮件标题格式为：`组织/部门名称 - 职位姓名 - X周周报 - 日期`
- 如果没配置 `company`，邮件标题格式为：`职位姓名 - X周周报 - 日期`
- `.env` 文件包含敏感信息，不会被发布到 clawhub（在 .clawignore 中已排除）

---

## 🐛 常见问题

### 忘记配置了怎么办？
重新发送"配置周报邮箱"命令，会重新进入配置流程。

### 邮件发送失败怎么办？
1. 检查 `.env` 文件是否存在且配置正确
2. 检查邮箱密码是否正确（某些邮箱需要使用授权码）
3. 检查SMTP服务器地址和端口是否正确
4. 检查是否开启了SMTP服务
5. 查看 detailed 错误信息

### 如何配置邮箱？
1. 复制 `.env.example` 为 `.env`
2. 填写你的 SMTP 配置信息

### 支持哪些邮箱？
支持所有标准SMTP协议的邮箱，包括：
- 腾讯企业邮箱
- 阿里企业邮箱
- 网易企业邮箱
- Gmail（需要应用专用密码）
- Outlook
- 其他支持SMTP的邮箱

---

## 🧪 测试

运行测试脚本：
```bash
cd /home/node/.openclaw/workspace/skills/xl-weekly-report-email
nodejs test.js
```

---

**版本历史和变更日志请查看 [CHANGELOG.md](CHANGELOG.md)**
