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. 提取事件(由代理直接执行)
读取邮件并将事件提取为结构化数据。为每个事件包含:
- - 标题:描述性名称(最多 80 个字符)
- 日期:事件日期
- 星期几:用于验证
- 时间:开始/结束时间(默认:上午 9 点 - 下午 5 点)
- 是否多日:是否跨越多个日期
- 是否重复:是否重复(及模式)
- 置信度:高/中/低
- 网址:邮件中找到的任何网址(必填——始终查找注册链接、信息页面、票务网站等)
- 截止日期:RSVP/注册/购票截止日期(如果找到)
- 截止操作:用户需要做什么(例如“RSVP”、“购票”、“注册”)
- 截止网址:执行操作的直接链接(通常与事件网址相同)
网址提取规则: 始终扫描邮件中的网址,并将最相关的网址放在事件描述的开头。
2.1 截止日期检测
扫描邮件中指示需要在事件前采取行动的截止日期模式:
常见截止日期模式:
- - “请于 [日期] 前 RSVP”、“请在 [日期] 前 RSVP”
- “请于 [日期] 前注册”、“注册于 [日期] 截止”
- “门票有效期至 [日期]”、“请在 [日期] 前购票”
- “早鸟优惠于 [日期] 结束”、“早鸟注册截止日期 [日期]”
- “必须在 [日期] 前回复”、“请于 [日期] 前回复”
- “请于 [日期] 前报名”、“报名截止日期 [日期]”
- “截止日期:[日期]”、“截止于 [日期]”
- “最后一天 [操作]:[日期]”
当找到截止日期时:
- 1. 提取截止日期
- 确定所需操作(RSVP、注册、购票等)
- 查找执行该操作的网址
- 标记事件进行特殊处理(参见以下章节)
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