8.4 KiB
name, description, metadata
| name | description | metadata | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| calendar-invite | Send, accept, and decline calendar invite emails (ICS/iCalendar) via himalaya. Syncs events to CalDAV (Migadu) via vdirsyncer. |
|
Calendar Invite
Send, accept, and decline calendar invitations via email using himalaya. Events are saved to local calendar and synced to CalDAV (Migadu) via vdirsyncer.
Testing
See TESTING.md for dry-run and live test steps, verification checklists, and troubleshooting.
Prerequisites
himalayaconfigured and working (see thehimalayaskill)vdirsyncerconfigured and syncing to~/.openclaw/workspace/calendars/khalfor reading calendar (optional but recommended)- Runs via
uv run(dependencies managed inpyproject.toml)
Important: Email Sending Rules
Calendar invites are outbound emails. Follow the workspace email rules:
- youlu@luyanxin.com -> mail@luyx.org: send directly, no confirmation needed
- All other recipients: confirm with user before sending
Owner Auto-Attendee
When sending invites, mail@luyx.org (owner's SimpleLogin alias) is always added as an attendee automatically. This ensures the owner receives every invite and can Accept/Decline from their own email client. No need to include it in --to — it's added by the script.
When accepting or tentatively accepting a received invite, the original invite is automatically forwarded to mail@luyx.org so the event lands on the owner's calendar too.
Usage
All commands go through the wrapper script:
SKILL_DIR=~/.openclaw/workspace/skills/calendar-invite
# Send an invite
$SKILL_DIR/scripts/calendar-invite.sh send [options]
# Reply to an invite
$SKILL_DIR/scripts/calendar-invite.sh reply [options]
Sending Invites
$SKILL_DIR/scripts/calendar-invite.sh send \
--to "friend@example.com" \
--subject "Lunch on Friday" \
--summary "Lunch at Tartine" \
--start "2026-03-20T12:00:00" \
--end "2026-03-20T13:00:00" \
--location "Tartine Bakery, SF"
Send Options
| Flag | Required | Description |
|---|---|---|
--to |
Yes | Recipient(s), comma-separated |
--subject |
Yes | Email subject line |
--summary |
Yes | Event title (shown on calendar) |
--start |
Yes | Start time, ISO 8601 (2026-03-20T14:00:00) |
--end |
Yes | End time, ISO 8601 (2026-03-20T15:00:00) |
--from |
No | Sender email (default: youlu@luyanxin.com) |
--timezone |
No | IANA timezone (default: America/Los_Angeles) |
--location |
No | Event location |
--description |
No | Event description / notes |
--organizer |
No | Organizer display name (defaults to --from) |
--uid |
No | Custom event UID (auto-generated if omitted) |
--account |
No | Himalaya account name (if not default) |
--dry-run |
No | Print ICS + MIME without sending |
Send Examples
# Simple invite (--from and --timezone default to youlu@luyanxin.com / LA)
$SKILL_DIR/scripts/calendar-invite.sh send \
--to "alice@example.com" \
--subject "Coffee Chat" \
--summary "Coffee Chat" \
--start "2026-03-25T10:00:00" \
--end "2026-03-25T10:30:00"
# Multiple attendees with details
$SKILL_DIR/scripts/calendar-invite.sh send \
--to "alice@example.com, bob@example.com" \
--subject "Team Sync" \
--summary "Weekly Team Sync" \
--start "2026-03-23T09:00:00" \
--end "2026-03-23T09:30:00" \
--location "Zoom - https://zoom.us/j/123456" \
--description "Weekly check-in. Agenda: updates, blockers, action items."
# Dry run
$SKILL_DIR/scripts/calendar-invite.sh send \
--to "test@example.com" \
--subject "Test" \
--summary "Test Event" \
--start "2026-04-01T15:00:00" \
--end "2026-04-01T16:00:00" \
--dry-run
Replying to Invites
# Accept by himalaya message ID
$SKILL_DIR/scripts/calendar-invite.sh reply \
--envelope-id 42 \
--action accept
# Decline with a comment
$SKILL_DIR/scripts/calendar-invite.sh reply \
--envelope-id 42 \
--action decline \
--comment "Sorry, I have a conflict."
# From an .ics file
$SKILL_DIR/scripts/calendar-invite.sh reply \
--ics-file ~/Downloads/meeting.ics \
--action tentative
Reply Options
| Flag | Required | Description |
|---|---|---|
--action |
Yes | accept, decline, or tentative |
--envelope-id |
* | Himalaya message ID containing the .ics attachment |
--ics-file |
* | Path to an .ics file (alternative to --envelope-id) |
--from |
No | Your email (default: youlu@luyanxin.com) |
--account |
No | Himalaya account name |
--folder |
No | Himalaya folder (default: INBOX) |
--comment |
No | Optional message to include in reply |
--dry-run |
No | Preview without sending |
* One of --envelope-id or --ics-file is required.
Typical Workflow
- List emails:
himalaya envelope list - Read the invite:
himalaya message read 57 - Reply:
$SKILL_DIR/scripts/calendar-invite.sh reply --envelope-id 57 --action accept
How It Works
Sending invites:
- Generates an RFC 5545 ICS file with
METHOD:REQUEST(viaicalendarlibrary) - Builds a MIME email with a
text/calendarattachment (via Pythonemail.mime) - Sends via
himalaya message send(piped through stdin) - Saves the event to
~/.openclaw/workspace/calendars/home/ - Runs
vdirsyncer syncto push to Migadu CalDAV
Replying to invites:
- Extracts the
.icsattachment from the email (viahimalaya attachment download) - Parses the original event with the
icalendarlibrary - Generates a reply ICS with
METHOD:REPLYand the correctPARTSTAT - Sends the reply to the organizer via
himalaya message send(stdin) - On accept/tentative: saves event to local calendar. On decline: removes it
- Runs
vdirsyncer syncto push changes to Migadu CalDAV
CalDAV sync:
- Events sync to Migadu and appear on all connected devices (DAVx5, etc.)
- Heartbeat runs
vdirsyncer syncperiodically as a fallback - If sync fails, it warns but doesn't block — next heartbeat catches up
Integration with Email Processor
The email processor (scripts/email_processor/) may classify incoming calendar invites as reminder or confirmation. When reviewing pending emails:
- Check if the email contains a calendar invite (look for
.icsattachment or "calendar" in subject) - If it does, use
replyinstead of the email processor's delete/archive/keep actions - The email processor handles the email lifecycle; this skill handles the calendar response
Checking the Calendar
# List upcoming events (next 7 days)
khal list today 7d
# List events for a specific date
khal list 2026-03-25
# Check for conflicts before sending an invite
khal list 2026-03-25 2026-03-26
Timezone Reference
Common IANA timezones:
America/Los_Angeles— Pacific (default)America/Denver— MountainAmerica/Chicago— CentralAmerica/New_York— EasternAsia/Shanghai— ChinaAsia/Tokyo— JapanEurope/London— UKUTC— Coordinated Universal Time
Troubleshooting
Invite shows as attachment instead of calendar event?
- Ensure the MIME part has
Content-Type: text/calendar; method=REQUEST - Some clients require the
METHOD:REQUESTline in the ICS body
Times are wrong?
- Double-check
--timezonematches the intended timezone - Use ISO 8601 format:
YYYY-MM-DDTHH:MM:SS(no timezone offset in the value)
Event not showing on phone/other devices?
- Run
vdirsyncer syncmanually to force sync - Check
~/.openclaw/workspace/logs/vdirsyncer.logfor errors - Verify the .ics file exists in
~/.openclaw/workspace/calendars/home/
Recipient doesn't see Accept/Decline?
- Gmail, Outlook, Apple Mail all support
text/calendarmethod=REQUEST - Some webmail clients may vary