Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Extract calendar events and action points from forwarded emails, store them for review, and create calendar events with duplicate detection. Use when the user forwards an email containing meeting invites, events, deadlines, or action items, and wants to extract structured items for calendar creation. Also use when the user asks to review previously extracted items or create calendar events from them.
Extract calendar events and action points from forwarded emails, store them for review, and create calendar events with duplicate detection. Use when the user forwards an email containing meeting invites, events, deadlines, or action items, and wants to extract structured items for calendar creation. Also use when the user asks to review previously extracted items or create calendar events from them.
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
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.
IMPORTANT: Before you can extract events, you must read the email body. Use the wrapper scripts. 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 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.
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")
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).
Read the email and extract events as structured data. Include for each event: title: Descriptive name (max 80 chars) date: Event date(s) day_of_week: For verification time: Start/end times (default: 9 AM - 5 PM) is_multi_day: Whether it spans multiple days is_recurring: 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.) deadline_date: RSVP/registration/ticket deadline date (if found) deadline_action: What user needs to do (e.g., "RSVP", "get tickets", "register") deadline_url: 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.
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: 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)
Apply event rules, then present with numbered selection: 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'. STOP AND WAIT for user response. After presenting, record pending invites for follow-up reminders: # 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"}]'
ALWAYS check before creating any event: # 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 Use LLM semantic matching for fuzzy duplicates (e.g., "Team Offsite" vs "Team Offsite 5-6pm").
Use create_event.sh (recommended) - handles date parsing, tracking, and changelog: # 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" For direct gog commands and advanced options, see references/gog-commands.md.
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: "$SCRIPTS_DIR/disposition_email.sh" --email-id "$EMAIL_ID" To process calendar reply emails (accepts, declines, tentatives): "$SCRIPTS_DIR/process_calendar_replies.sh" # Process all "$SCRIPTS_DIR/process_calendar_replies.sh" --dry-run # Preview only # End activity session "$SCRIPTS_DIR/activity_log.sh" end-session
Single-day events: Default 9:00 AM - 5:00 PM Multi-day events (e.g., Feb 2-6): Use --rrule "RRULE:FREQ=DAILY;COUNT=N" Events with specific times: Use exact time from email
Format event descriptions in this order: ACTION WARNING (if deadline exists): *** ACTION REQUIRED: [ACTION] BY [DATE] *** Event Link (if URL found): Event Link: [URL] Event Details: Information extracted from the email Example WITH deadline: *** 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 Example WITHOUT deadline: Event Link: https://example.com/event Spring Concert at Downtown Theater Doors open at 7 PM
Consider it a duplicate if: Same date AND similar title (semantic matching) AND overlapping time Always update existing events rather than creating duplicates.
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): "$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. Deadline Reminder Event (separate event on the deadline date): # 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 Event Properties: Title format: DEADLINE: [Action] for [Event Name] 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
# 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
Changes can be undone within 24 hours: # 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"
Events not immediately actioned are tracked for reminders: # 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
# 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
FilePurpose~/.config/email-to-calendar/config.jsonUser configuration~/.openclaw/workspace/memory/email-extractions/Extracted data~/.openclaw/workspace/memory/email-extractions/index.jsonProcessing index~/.openclaw/workspace/memory/email-to-calendar/events.jsonEvent tracking~/.openclaw/workspace/memory/email-to-calendar/pending_invites.jsonPending invites~/.openclaw/workspace/memory/email-to-calendar/activity.jsonActivity log~/.openclaw/workspace/memory/email-to-calendar/changelog.jsonChange history~/.openclaw/workspace/skills/email-to-calendar/scripts/Utility scripts~/.openclaw/workspace/skills/email-to-calendar/MEMORY.mdUser preferences
Setup Guide: SETUP.md - Configuration and onboarding CLI Reference: references/gog-commands.md - Detailed gog CLI usage Extraction Patterns: references/extraction-patterns.md - Date/time parsing Workflow Example: references/workflow-example.md - Complete example
Handles common formats: January 15, 2026, Wednesday January 15 01/15/2026, 15/01/2026 Date ranges like "Feb 2-6"
All times assumed local timezone. Time zone info preserved in descriptions.
Workflow acceleration for inboxes, docs, calendars, planning, and execution loops.
Largest current source with strong distribution and engagement signals.