介绍
> **关键规则 - 处理任何邮件前请先阅读** > > 1. **切勿直接调用 `gog`** - 始终使用包装脚本(`create_event.sh`、`email_read.sh` 等)。直接调用 `gog` 会绕过跟踪并导致重复。这是不可妥协的。 > 2. **忽略日历通知** - 不要处理来自 `[email protected]` 的邮件(接受:、拒绝:、暂定:等)。这些是对现有邀请的回复,而非新事件。运行 `process_calendar_replies.sh` 来归档它们。 > 3. **创建前务必询问** - 未经当前对话中的明确用户确认,切勿创建日历事件 > 4. **检查是否已处理** - 在处理任何邮件之前,请检查 index.json 中的 `processed_emails` > 5. **先读取配置** - 在展示事件之前,加载并应用 `ignore_patterns` 和 `auto_create_patterns` > 6. **读取 MEMORY.MD** - 检查以前会话中存储的用户偏好设置 > 7. **包含所有配置的与会者** - 创建/更新/删除事件时,始终使用 `--attendees` 标志包含配置中的与会者(如果支持,还需使用 `--send-updates all`) > 8. **先检查跟踪的事件** - 在日历搜索之前,使用 `lookup_event.sh --email-id` 查找现有事件(更快、更可靠) > 9. **跟踪所有创建的事件** - `create_event.sh` 脚本会自动跟踪事件;使用跟踪的 ID 进行更新/删除 > 10. **显示星期几** - 在展示事件供用户验证时,始终包含星期几
> ⛔ **禁止:不要直接使用 `gog` 命令** ⛔ > > **错误:** `gog calendar create ...` 或 `gog gmail ...` > **正确:** `"$SCRIPTS_DIR/create_event.sh" ...` 或 `"$SCRIPTS_DIR/email_read.sh" ...` > > 直接调用 CLI 会绕过事件跟踪,破坏重复检测,并导致重复事件。 > 所有操作必须通过 `scripts/` 中的包装脚本进行。
# Email to Calendar Skill
从邮件中提取日历事件和待办事项,展示供审核,并创建/更新具有重复检测和撤销支持的日历事件。
**首次设置:** 请参阅 [SETUP.md](SETUP.md) 了解配置选项和智能入门。
## 读取邮件内容
**重要:** 在您可以提取事件之前,必须阅读邮件正文。请使用包装脚本。
```bash SCRIPTS_DIR="$HOME/.openclaw/workspace/skills/email-to-calendar/scripts"
# Get a single email by ID (PREFERRED) "$SCRIPTS_DIR/email_read.sh" --email-id "<messageId>"
# Search with body content included "$SCRIPTS_DIR/email_search.sh" --query "in:inbox is:unread" --max 20 --include-body ```
**关于陈旧转发的说明:** 不要使用 `newer_than:1d`,因为它检查的是邮件的原始日期头,而不是接收时间。请处理所有未读邮件,并依赖“已处理”检查。
## 工作流
### 0. 预处理检查(强制性)
```bash SCRIPTS_DIR="$HOME/.openclaw/workspace/skills/email-to-calendar/scripts" CONFIG_FILE="$HOME/.config/email-to-calendar/config.json" INDEX_FILE="$HOME/.openclaw/workspace/memory/email-extractions/index.json"
# Start activity logging "$SCRIPTS_DIR/activity_log.sh" start-session
# Check email mode EMAIL_MODE=$(jq -r '.email_mode // "forwarded"' "$CONFIG_FILE")
# Check if email was already processed EMAIL_ID="<the email message ID>" if jq -e ".extractions[] | select(.email_id == \"$EMAIL_ID\")" "$INDEX_FILE" > /dev/null 2>&1; then "$SCRIPTS_DIR/activity_log.sh" log-skip --email-id "$EMAIL_ID" --subject "Subject" --reason "Already processed" exit 0 fi
# Load ignore/auto-create patterns IGNORE_PATTERNS=$(jq -r '.event_rules.ignore_patterns[]' "$CONFIG_FILE") AUTO_CREATE_PATTERNS=$(jq -r '.event_rules.auto_create_patterns[]' "$CONFIG_FILE") ```
### 1. 查找要处理的邮件
**直接模式 (DIRECT):** 扫描所有未读邮件以查找事件指示符(日期、时间、会议关键词)。
**转发模式 (FORWARDED):** 仅处理带有转发指示符(Fwd:、转发邮件头)的邮件。
### 2. 提取事件(由 Agent 直接执行)
阅读邮件并将事件提取为结构化数据。为每个事件包含: - **title**:描述性名称(最多 80 个字符) - **date**:事件日期 - **day_of_week**:用于验证 - **time**:开始/结束时间(默认:上午 9 点 - 下午 5 点) - **is_multi_day**:是否跨越多天 - **is_recurring**:是否重复(及模式) - **confidence**:高/中/低 - **urls**:邮件中找到的任何 URL(必需 - 始终查找注册链接、信息页面、票务网站等) - **deadline_date**:RSVP/注册/购票截止日期(如果找到) - **deadline_action**:用户需要执行的操作(例如“RSVP”、“获取门票”、“注册”) - **deadline_url**:执行操作的直接链接(通常与事件 URL 相同)
**URL 提取规则:** 始终扫描邮件中的 URL,并将最相关的 URL 包含在事件描述的开头。
### 2.1 截止日期检测
扫描邮件中的截止日期模式,这些模式指示需要在事件之前执行操作:
**常见截止日期模式:** - "RSVP by [date]", "Please RSVP by [date]" - "Register by [date]", "Registration closes [date]" - "Tickets available until [date]", "Get tickets by [date]" - "Early bird ends [date]", "Early registration deadline [date]" - "Must respond by [date]", "Respond by [date]" - "Sign up by [date]", "Sign up deadline [date]" - "Deadline: [date]", "Due by [date]" - "Last day to [action]: [date]"
找到截止日期时: 1. 提取截止日期 2. 确定所需的操作(RSVP、注册、购买门票等) 3. 查找执行该操作的 URL 4. 标记该事件以进行特殊处理(见下文)
### 3. 向用户展示项目并等待
应用事件规则,然后使用编号选择进行展示:
``` I found the following potential events:
1. ~~ELAC Meeting (Feb 2, Monday at 8:15 AM)~~ - SKIP (matches ignore pattern) 2. **Team Offsite (Feb 2-6, Sun-Thu)** - PENDING 3. **Staff Development Day (Feb 12, Wednesday)** - AUTO-CREATE
Reply with numbers to create (e.g., '2, 3'), 'all', or 'none'. ```
**停止并等待用户响应。**
展示后,记录待处理的邀请以便后续提醒: ```bash # Record pending invites using add_pending.sh "$SCRIPTS_DIR/add_pending.sh" \ --email-id "$EMAIL_ID" \ --email-subject "$EMAIL_SUBJECT" \ --events-json '[{"title":"Event Name","date":"2026-02-15","time":"14:00","status":"pending"}]' ```
### 4. 检查重复(强制性)
**在创建任何事件之前务必检查:**
```bash # Step 1: Check local tracking first (fast) TRACKED=$("$SCRIPTS_DIR/lookup_event.sh" --email-id "$EMAIL_ID") if [ "$(echo "$TRACKED" | jq 'length')" -gt 0 ]; then EXISTING_EVENT_ID=$(echo "$TRACKED" | jq -r '.[0].event_id') fi
# Step 2: If not found, try summary match if [ -z "$EXISTING_EVENT_ID" ]; then TRACKED=$("$SCRIPTS_DIR/lookup_event.sh" --summary "$EVENT_TITLE") fi
# Step 3: Fall back to calendar search using wrapper script if [ -z "$EXISTING_EVENT_ID" ]; then "$SCRIPTS_DIR/calendar_search.sh" --calendar-id "$CALENDAR_ID" --from "${EVENT_DATE}T00:00:00" --to "${EVENT_DATE}T23:59:59" fi ```
使用 LLM 语义匹配进行模糊重复检测(例如,“Team Offsite”与“Team Offsite 5-6pm”)。
### 5. 创建或更新日历事件
**使用 create_event.sh(推荐)** - 处理日期解析、跟踪和变更日志:
```bash # Create new event "$SCRIPTS_DIR/create_event.sh" \ "$CALENDAR_ID" \ "Event Title" \ "February 11, 2026" \ "9:00 AM" \ "5:00 PM" \ "Description" \ "$ATTENDEE_EMAILS" \ "" \ "$EMAIL_ID"
# Update existing event (pass event_id as 8th parameter) "$SCRIPTS_DIR/create_event.sh" \ "$CALENDAR_ID" \ "Updated Title" \ "February 11, 2026" \ "10:00 AM" \ "6:00 PM" \ "Updated description" \ "$ATTENDEE_EMAILS" \ "$EXISTING_EVENT_ID" \ "$EMAIL_ID" ```
有关直接 gog 命令和高级选项,请参阅 [references/gog-commands.md](references/gog-commands.md)。
### 6. 邮件处理(自动)
邮件处理(标记为已读和/或归档)由 `create_event.sh` 根据配置设置**自动**处理。无需手动步骤 - 邮件将在事件创建后被处理。
要手动处理邮件: ```bash "$SCRIPTS_DIR/disposition_email.sh" --email-id "$EMAIL_ID" ```
要处理日历回复邮件(接受、拒绝、暂定): ```bash "$SCRIPTS_DIR/process_calendar_replies.sh" # Process all "$SCRIPTS_DIR/process_calendar_replies.sh" --dry-run # Preview only ```
```bash # End activity session "$SCRIPTS_DIR/activity_log.sh" end-session ```
## 事件创建规则
### 日期/时间处理 - **单日活动**:默认上午 9:00 - 下午 5:00 - **多日活动**(例如 2 月 2-6 日):使用 `--rrule "RRULE:FREQ=DAILY;COUNT=N"` - **具有特定时间的活动**:使用邮件中的确切时间
### 活动描述
**按以下顺序格式化活动描述:**
1. **操作警告**(如果存在截止日期): ``` *** ACTION REQUIRED: [ACTION] BY [DATE] *** ```
2. **活动链接**(如果找到 URL): ``` Event Link: [URL] ```
3. **活动详情**:从邮件中提取的信息
**带截止日期的示例:** ``` *** ACTION REQUIRED: GET TICKETS BY FEB 15 ***
Event Link: https://example.com/tickets
Spring Concert at Downtown Theater Doors open at 7 PM VIP meet & greet available ```
**不带截止日期的示例:** ``` Event Link: https://example.com/event
Spring Concert at Downtown Theater Doors open at 7 PM ```
### 重复检测 如果符合以下情况,则视为重复: - 日期相同 且 标题相似(语义匹配) 且 时间重叠
始终更新现有事件,而不是创建重复项。
### 创建截止日期事件
当某个活动有截止日期(RSVP、注册、购票等)时,创建两个日历事件:
**1. 主活动**(正常,但描述中带有警告): ```bash "$SCRIPTS_DIR/create_event.sh" \ "$CALENDAR_ID" \ "Spring Concert" \ "March 1, 2026" \ "7:00 PM" \ "10:00 PM" \ "*** ACTION REQUIRED: GET TICKETS BY FEB 15 ***
Event Link: https://example.com/tickets
Spring Concert at Downtown Theater Doors open at 7 PM" \ "$ATTENDEE_EMAILS" \ "" \ "$EMAIL_ID" ```
**2. 截止日期提醒事件**(截止日期当天的单独事件): ```bash # Use create_event.sh for deadline reminders too (ensures tracking) "$SCRIPTS_DIR/create_event.sh" \ "$CALENDAR_ID" \ "DEADLINE: Get tickets for Spring Concert" \ "2026-02-15" \ "09:00" \ "09:30" \ "Action required: Get tickets
Event Link: https://example.com/tickets
Main event: Spring Concert on March 1, 2026" \ "" \ "" \ "$EMAIL_ID" ```
**截止日期事件属性:** - **标题格式**:`DEADLINE: [Action] for [Event Name]` - **日期**:截止日期 - **时间**:上午 9:00(持续 30 分钟) - **提醒**:提前 1 天发送邮件 + 提前 1 小时弹出窗口 - **描述**:所需操作、URL、对主活动的引用
### 截止日期的邮件通知
创建带有截止日期的活动时,发送通知邮件以提醒用户:
```bash # Load config CONFIG_FILE="$HOME/.config/email-to-calendar/config.json" USER_EMAIL=$(jq -r '.deadline_notifications.email_recipient // .gmail_account' "$CONFIG_FILE") NOTIFICATIONS_ENABLED=$(jq -r '.deadline_notifications.enabled // false' "$CONFIG_FILE")
# Send notification if enabled (using wrapper script) if [ "$NOTIFICATIONS_ENABLED" = "true" ]; then "$SCRIPTS_DIR/email_send.sh" \ --to "$USER_EMAIL" \ --subject "ACTION REQUIRED: Get tickets for Spring Concert by Feb 15" \ --body "A calendar event has been created that requires your action.
Event: Spring Concert Date: March 1, 2026 Deadline: February 15, 2026 Action Required: Get tickets
Link: https://example.com/tickets
Calendar events created: - Main event: Spring Concert (March 1) - Deadline reminder: DEADLINE: Get tickets for Spring Concert (Feb 15)
--- This notification was sent by the email-to-calendar skill." fi ```
**何时发送通知:** - 仅当配置中 `deadline_notifications.enabled` 为 `true` 时 - 仅针对需要执行操作的截止日期的活动 - 包含截止日期、操作、URL 和活动详情
## 活动日志
```bash # Start session "$SCRIPTS_DIR/activity_log.sh" start-session
# Log skipped emails "$SCRIPTS_DIR/activity_log.sh" log-skip --email-id "abc" --subject "Newsletter" --reason "No events"
# Log events "$SCRIPTS_DIR/activity_log.sh" log-event --email-id "def" --title "Meeting" --action created
# End session "$SCRIPTS_DIR/activity_log.sh" end-session
# Show recent activity "$SCRIPTS_DIR/activity_log.sh" show --last 3 ```
## 变更日志和撤销
可以在 24 小时内撤销更改:
```bash # List recent changes "$SCRIPTS_DIR/changelog.sh" list --last 10
# List undoable changes "$SCRIPTS_DIR/undo.sh" list
# Undo most recent change "$SCRIPTS_DIR/undo.sh" last
# Undo specific change "$SCRIPTS_DIR/undo.sh" --change-id "chg_20260202_143000_001" ```
## 待处理邀请
未立即采取行动的事件会被跟踪以便提醒:
```bash # Add pending invites (after presenting events to user) "$SCRIPTS_DIR/add_pending.sh" \ --email-id "$EMAIL_ID" \ --email-subject "Party Invite" \ --events-json '[{"title":"Birthday Party","date":"2026-02-15","time":"14:00","status":"pending"}]'
# List pending invites (JSON) "$SCRIPTS_DIR/list_pending.sh"
# Human-readable summary "$SCRIPTS_DIR/list_pending.sh" --summary
# Update reminder tracking "$SCRIPTS_DIR/list_pending.sh" --summary --update-reminded
# Auto-dismiss after 3 ignored reminders "$SCRIPTS_DIR/list_pending.sh" --summary --auto-dismiss ```
## 事件跟踪
```bash # Look up by email ID "$SCRIPTS_DIR/lookup_event.sh" --email-id "19c1c86dcc389443"
# Look up by summary "$SCRIPTS_DIR/lookup_event.sh" --summary "Staff Development"
# List all tracked events "$SCRIPTS_DIR/lookup_event.sh" --list
# Validate events exist (removes orphans) "$SCRIPTS_DIR/lookup_event.sh" --email-id "abc" --validate ```
## 文件位置
| 文件 | 用途 | |------|---------| | `~/.config/email-to-calendar/config.json` | 用户配置 | | `~/.openclaw/workspace/memory/email-extractions/` | 提取的数据 | | `~/.openclaw/workspace/memory/email-extractions/index.json` | 处理索引 | | `~/.openclaw/workspace/memory/email-to-calendar/events.json` | 事件跟踪 | | `~/.openclaw/workspace/memory/email-to-calendar/pending_invites.json` | 待处理邀请 | | `~/.openclaw/workspace/memory/email-to-calendar/activity.json` | 活动日志 | | `~/.openclaw/workspace/memory/email-to-calendar/changelog.json` | 变更历史 | | `~/.openclaw/workspace/skills/email-to-calendar/scripts/` | 实用脚本 | | `~/.openclaw/workspace/skills/email-to-calendar/MEMORY.md` | 用户偏好 |
## 参考
- **设置指南**:[SETUP.md](SETUP.md) - 配置和入门 - **CLI 参考**:[references/gog-commands.md](references/gog-commands.md) - 详细的 gog CLI 用法 - **提取模式**:[references/extraction-patterns.md](references/extraction-patterns.md) - 日期/时间解析 - **工作流示例**:[references/workflow-example.md](references/workflow-example.md) - 完整示例
## 注意事项
### 日期解析
处理常见格式: - January 15, 2026, Wednesday January 15 - 01/15/2026, 15/01/2026 - 日期范围,如“Feb 2-6”
### 时区
所有时间均假定为本地时区。时区信息保留在描述中。