CRITICAL RULES - READ BEFORE PROCESSING ANY EMAIL
- 1. NEVER CALL
gog DIRECTLY - ALWAYS use wrapper scripts (create_event.sh, email_read.sh, etc.). Direct gog calls bypass tracking and cause duplicates. THIS IS NON-NEGOTIABLE. - IGNORE CALENDAR NOTIFICATIONS - DO NOT process emails from
calendar-notification@google.com (Accepted:, Declined:, Tentative:, etc.). These are responses to existing invites, NOT new events. Run process_calendar_replies.sh to archive them. - ALWAYS ASK BEFORE CREATING - Never create calendar events without explicit user confirmation in the current conversation
- CHECK IF ALREADY PROCESSED - Before processing any email, check
processed_emails in index.json - READ CONFIG FIRST - Load and apply
ignore_patterns and auto_create_patterns before presenting events - READ MEMORY.MD - Check for user preferences stored from previous sessions
- INCLUDE ALL CONFIGURED ATTENDEES - When creating/updating/deleting events, always include attendees from config with
--attendees flag (and --send-updates all if supported) - CHECK TRACKED EVENTS FIRST - Use
lookup_event.sh --email-id to find existing events before calendar search (faster, more reliable) - TRACK ALL CREATED EVENTS - The
create_event.sh script automatically tracks events; use tracked IDs for updates/deletions - SHOW DAY-OF-WEEK - Always include the day of week when presenting events for user verification
⛔ FORBIDDEN: DO NOT USE gog COMMANDS DIRECTLY ⛔
WRONG: gog calendar create ... or gog gmail ...
RIGHT: "$SCRIPTS_DIR/create_event.sh" ... or "$SCRIPTS_DIR/email_read.sh" ...
Direct CLI calls bypass event tracking, break duplicate detection, and cause duplicate events.
ALL operations MUST go through the wrapper scripts in scripts/.
Email to Calendar Skill
Extract calendar events and action items from emails, present them for review, and create/update calendar events with duplicate detection and undo support.
First-time setup: See SETUP.md for configuration options and smart onboarding.
Reading Email Content
IMPORTANT: Before you can extract events, you must read the email body. Use the wrapper scripts.
CODEBLOCK0
Note on stale forwards: Don't use newer_than:1d because it checks the email's original date header, not when it was received. Process all UNREAD emails and rely on the "already processed" check.
Workflow
0. Pre-Processing Checks (MANDATORY)
CODEBLOCK1
1. Find Emails to Process
DIRECT mode: Scan all unread emails for event indicators (dates, times, meeting keywords).
FORWARDED mode: Only process emails with forwarded indicators (Fwd:, forwarded message headers).
2. Extract Events (Agent does this directly)
Read the email and extract events as structured data. Include for each event:
- - title: Descriptive name (max 80 chars)
- date: Event date(s)
- dayofweek: For verification
- time: Start/end times (default: 9 AM - 5 PM)
- ismultiday: Whether it spans multiple days
- isrecurring: Whether it repeats (and pattern)
- confidence: high/medium/low
- urls: Any URLs found in the email (REQUIRED - always look for registration links, info pages, ticketing sites, etc.)
- deadlinedate: RSVP/registration/ticket deadline date (if found)
- deadlineaction: What user needs to do (e.g., "RSVP", "get tickets", "register")
- deadlineurl: Direct link for taking action (often same as event URL)
URL Extraction Rule: ALWAYS scan the email for URLs and include the most relevant one at the BEGINNING of the event description.
2.1 Deadline Detection
Scan the email for deadline patterns that indicate action is required before the event:
Common Deadline Patterns:
- - "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]"
When a deadline is found:
- 1. Extract the deadline date
- Determine the required action (RSVP, register, buy tickets, etc.)
- Find the URL for taking that action
- Flag the event for special handling (see sections below)
3. Present Items to User and WAIT
Apply event rules, then present with numbered selection:
CODEBLOCK2
STOP AND WAIT for user response.
After presenting, record pending invites for follow-up reminders:
CODEBLOCK3
4. Check for Duplicates (MANDATORY)
ALWAYS check before creating any event:
CODEBLOCK4
Use LLM semantic matching for fuzzy duplicates (e.g., "Team Offsite" vs "Team Offsite 5-6pm").
5. Create or Update Calendar Events
Use create_event.sh (recommended) - handles date parsing, tracking, and changelog:
CODEBLOCK5
For direct gog commands and advanced options, see references/gog-commands.md.
6. Email Disposition (Automatic)
Email disposition (mark as read and/or archive) is handled automatically by create_event.sh based on config settings. No manual step needed - emails are dispositioned after event creation.
To manually disposition an email:
CODEBLOCK6
To process calendar reply emails (accepts, declines, tentatives):
CODEBLOCK7
CODEBLOCK8
Event Creation Rules
Date/Time Handling
- - Single-day events: Default 9:00 AM - 5:00 PM
- Multi-day events (e.g., Feb 2-6): Use INLINECODE21
- Events with specific times: Use exact time from email
Event Descriptions
Format event descriptions in this order:
- 1. ACTION WARNING (if deadline exists):
CODEBLOCK9
- 2. Event Link (if URL found):
CODEBLOCK10
- 3. Event Details: Information extracted from the email
Example WITH deadline:
CODEBLOCK11
Example WITHOUT deadline:
CODEBLOCK12
Duplicate Detection
Consider it a duplicate if:
- - Same date AND similar title (semantic matching) AND overlapping time
Always update existing events rather than creating duplicates.
Creating Deadline Events
When an event has a deadline (RSVP, registration, ticket purchase, etc.), create TWO calendar events:
1. Main Event (as normal, but with warning in description):
CODEBLOCK13
2. Deadline Reminder Event (separate event on the deadline date):
CODEBLOCK14
Deadline Event Properties:
- - Title format: INLINECODE22
- Date: The deadline date
- Time: 9:00 AM (30 minute duration)
- Reminders: Email 1 day before + popup 1 hour before
- Description: Action required, URL, reference to main event
Email Notifications for Deadlines
When creating events with deadlines, send a notification email to alert the user:
CODEBLOCK15
When to send notifications:
- - Only when
deadline_notifications.enabled is true in config - Only for events that have action-required deadlines
- Include the deadline date, action, URL, and event details
Activity Log
CODEBLOCK16
Changelog and Undo
Changes can be undone within 24 hours:
CODEBLOCK17
Pending Invites
Events not immediately actioned are tracked for reminders:
CODEBLOCK18
Event Tracking
CODEBLOCK19
File Locations
| File | Purpose |
|---|
| INLINECODE25 | User configuration |
| INLINECODE26 |
Extracted data |
|
~/.openclaw/workspace/memory/email-extractions/index.json | Processing index |
|
~/.openclaw/workspace/memory/email-to-calendar/events.json | Event tracking |
|
~/.openclaw/workspace/memory/email-to-calendar/pending_invites.json | Pending invites |
|
~/.openclaw/workspace/memory/email-to-calendar/activity.json | Activity log |
|
~/.openclaw/workspace/memory/email-to-calendar/changelog.json | Change history |
|
~/.openclaw/workspace/skills/email-to-calendar/scripts/ | Utility scripts |
|
~/.openclaw/workspace/skills/email-to-calendar/MEMORY.md | User preferences |
References
Notes
Date Parsing
Handles common formats:
- - January 15, 2026, Wednesday January 15
- 01/15/2026, 15/01/2026
- Date ranges like "Feb 2-6"
Time Zones
All times assumed local timezone. Time zone info preserved in descriptions.
关键规则 - 在处理任何邮件前请阅读
- 1. 切勿直接调用 gog - 始终使用包装脚本(createevent.sh、emailread.sh 等)。直接调用 gog 会绕过追踪机制并导致重复。此规则不可协商。
- 忽略日历通知 - 不要处理来自 calendar-notification@google.com 的邮件(已接受:、已拒绝:、暂定:等)。这些是对现有邀请的回复,而非新事件。运行 processcalendarreplies.sh 将其归档。
- 创建前务必询问 - 未经当前对话中用户明确确认,切勿创建日历事件。
- 检查是否已处理 - 在处理任何邮件前,检查 index.json 中的 processedemails。
- 先读取配置 - 在展示事件前,加载并应用 ignorepatterns 和 autocreatepatterns。
- 读取 MEMORY.MD - 检查之前会话中存储的用户偏好。
- 包含所有已配置的参与者 - 创建/更新/删除事件时,始终使用 --attendees 标志包含配置中的参与者(如果支持,加上 --send-updates all)。
- 优先检查已追踪事件 - 在日历搜索前,使用 lookupevent.sh --email-id 查找现有事件(更快、更可靠)。
- 追踪所有已创建事件 - createevent.sh 脚本会自动追踪事件;使用追踪的 ID 进行更新/删除。
- 显示星期几 - 在向用户展示事件以供验证时,始终包含星期几。
⛔ 禁止:不要直接使用 gog 命令 ⛔
错误: gog calendar create ... 或 gog gmail ...
正确: $SCRIPTSDIR/createevent.sh ... 或 $SCRIPTSDIR/emailread.sh ...
直接 CLI 调用会绕过事件追踪、破坏重复检测并导致重复事件。
所有操作必须通过 scripts/ 中的包装脚本进行。
邮件到日历技能
从邮件中提取日历事件和待办事项,呈现以供审核,并创建/更新日历事件,同时具备重复检测和撤销支持。
首次设置: 请参阅 SETUP.md 了解配置选项和智能引导。
阅读邮件内容
重要提示: 在提取事件之前,您必须阅读邮件正文。请使用包装脚本。
bash
SCRIPTS_DIR=$HOME/.openclaw/workspace/skills/email-to-calendar/scripts
按 ID 获取单封邮件(首选)
$SCRIPTS
DIR/emailread.sh --email-id
搜索并包含正文内容
$SCRIPTSDIR/emailsearch.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
开始活动日志记录
$SCRIPTSDIR/activitylog.sh start-session
检查邮件模式
EMAILMODE=$(jq -r .emailmode // forwarded $CONFIG_FILE)
检查邮件是否已处理
EMAIL_ID=<邮件消息 ID>
if jq -e .extractions[] | select(.emailid == \$EMAILID\) $INDEX_FILE > /dev/null 2>&1; then
$SCRIPTSDIR/activitylog.sh log-skip --email-id $EMAIL_ID --subject 主题 --reason 已处理
exit 0
fi
加载忽略/自动创建模式
IGNOREPATTERNS=$(jq -r .eventrules.ignorepatterns[] $CONFIGFILE)
AUTOCREATEPATTERNS=$(jq -r .eventrules.autocreatepatterns[] $CONFIGFILE)
1. 查找待处理的邮件
直接模式: 扫描所有未读邮件,查找事件指示符(日期、时间、会议关键词)。
转发模式: 仅处理带有转发指示符(Fwd:、转发消息头)的邮件。
2. 提取事件(由代理直接执行)
阅读邮件并将事件提取为结构化数据。为每个事件包含:
- - title:描述性名称(最多 80 个字符)
- date:事件日期
- dayofweek:用于验证
- time:开始/结束时间(默认:上午 9 点 - 下午 5 点)
- ismultiday:是否跨越多天
- isrecurring:是否重复(以及模式)
- confidence:高/中/低
- urls:在邮件中找到的任何 URL(必需 - 始终查找注册链接、信息页面、售票网站等)
- deadlinedate:RSVP/注册/购票截止日期(如果找到)
- deadlineaction:用户需要执行的操作(例如“RSVP”、“获取门票”、“注册”)
- deadlineurl:执行操作的直接链接(通常与事件 URL 相同)
URL 提取规则: 始终扫描邮件中的 URL,并将最相关的一个放在事件描述的开头。
2.1 截止日期检测
扫描邮件中指示需要在事件前采取行动的截止日期模式:
常见截止日期模式:
- - RSVP by [日期], Please RSVP by [日期]
- Register by [日期], Registration closes [日期]
- Tickets available until [日期], Get tickets by [日期]
- Early bird ends [日期], Early registration deadline [日期]
- Must respond by [日期], Respond by [日期]
- Sign up by [日期], Sign up deadline [日期]
- Deadline: [日期], Due by [日期]
- Last day to [操作]: [日期]
当找到截止日期时:
- 1. 提取截止日期
- 确定所需操作(RSVP、注册、购票等)
- 查找执行该操作的 URL
- 标记事件进行特殊处理(见下文各节)
3. 向用户呈现项目并等待
应用事件规则,然后使用编号选择呈现:
我找到了以下潜在事件:
- 1. ~~ELAC 会议(2月2日,星期一,上午8:15)~~ - 跳过(匹配忽略模式)
- 团队外出活动(2月2日至6日,周日至周四) - 待定
- 员工发展日(2月12日,星期三) - 自动创建
回复数字以创建(例如 2, 3)、all 或 none。
停止并等待用户响应。
呈现后,记录待定邀请以供后续提醒:
bash
使用 add_pending.sh 记录待定邀请
$SCRIPTSDIR/addpending.sh \
--email-id $EMAIL_ID \
--email-subject $EMAIL_SUBJECT \
--events-json [{title:事件名称,date:2026-02-15,time:14:00,status:pending}]
4. 检查重复项(强制)
在创建任何事件前务必检查:
bash
步骤 1:首先检查本地追踪(快速)
TRACKED=$($SCRIPTSDIR/lookupevent.sh --email-id $EMAIL_ID)
if [ $(echo $TRACKED | jq length) -gt 0 ]; then
EXISTINGEVENTID=$(echo $TRACKED | jq -r .[0].event_id)
fi
步骤 2:如果未找到,尝试摘要匹配
if [ -z $EXISTINGEVENTID ]; then
TRACKED=$($SCRIPTSDIR/lookupevent.sh --summary $EVENT_TITLE)
fi
步骤 3:回退到使用包装脚本进行日历搜索
if [ -z $EXISTINGEVENTID ]; then
$SCRIPTSDIR/calendarsearch.sh --calendar-id $CALENDARID --from ${EVENTDATE}T00:00:00 --to ${EVENT_DATE}T23:59:59
fi
使用 LLM 语义匹配进行