Handle calendar invites
Handle meeting invites without leaving mxr. mxr parses text/calendar
parts and .ics attachments from stored mail, shows the invite in the
message view, collects every detected invite into a dedicated Calendar
invites page in the TUI and web app, lets you find invite-bearing
messages with search, and sends standards-based iMIP replies after a
dry-run preview.
See what mxr found
Section titled “See what mxr found”List recent invites before acting on any one message.
mxr invites list --limit 20What you get: a table of invite-bearing messages with the summary, method, UID, sequence, organizer, start time, location, attendee state, and parser warnings.
Use JSON when you are building a script or checking parser output.
mxr invites list --limit 20 --format json \ | jq -r '.[] | "\(.message_id)\t\(.metadata.summary // "(no title)")"'Inspect one invite
Section titled “Inspect one invite”Show the normalized invite attached to a message before deciding.
mxr invite show MESSAGE_ID --format jsonWhat you get: one object with message_id, local invite row metadata,
and the parsed calendar metadata: method, uid, sequence,
recurrence_id, starts_at, ends_at, organizer, attendees,
rrule, raw_ics, and warnings.
For a quick terminal read, omit JSON.
mxr invite show MESSAGE_IDReply safely
Section titled “Reply safely”Always dry-run before sending. The dry-run builds the exact iMIP
METHOD:REPLY body and calendar part, but does not contact the provider.
mxr invite reply MESSAGE_ID accept --dry-run --format jsonWhat you get: a preview with the attendee address mxr matched, organizer
address, generated subject/body, generated text/calendar reply, and any
warnings.
Send only after the preview looks right.
mxr invite reply MESSAGE_ID acceptUse the same path for maybe or no.
mxr invite reply MESSAGE_ID tentative --dry-runmxr invite reply MESSAGE_ID decline --dry-runFind invite mail
Section titled “Find invite mail”Calendar invites are indexed as a search filter.
mxr search 'has:calendar newer_than:30d' --format idsWhat you get: one message ID per invite-bearing message, ready to pass to
mxr invite show, mxr thread, or an fzf picker.
Aliases are available when you think in email-app language.
mxr search 'has:invite' --format idsmxr search 'has:invites from:alice@example.com' --format jsonBackfill after upgrade
Section titled “Backfill after upgrade”New syncs persist invite rows automatically. If you already had invite mail in SQLite before upgrading, backfill from stored body metadata.
mxr invites backfill --format jsonWhat you get: a count of invite rows restored from existing message bodies. Run it once after upgrading; future sync batches keep the table fresh.
Check the result with search.
mxr search 'has:calendar' --format ids | headIn real life
Section titled “In real life”Prepare for today’s meetings
Section titled “Prepare for today’s meetings”mxr search 'has:calendar newer_than:7d' --format json \ | jq -r '.[] | "\(.date)\t\(.from)\t\(.subject)"'What you get: a small agenda-like list from mail, useful when the calendar app is not the system of record.
Review every pending RSVP
Section titled “Review every pending RSVP”mxr invites list --format jsonl \ | jq -r 'select((.metadata.attendees // [])[]?.partstat == "NEEDS-ACTION") | .message_id' \ | while IFS= read -r id; do mxr invite show "$id" doneWhat you get: each invite that still needs action, expanded one at a time so you can decide deliberately.
Let fzf pick the meeting
Section titled “Let fzf pick the meeting”mxr invites list --format jsonl \ | jq -r '"\(.message_id)\t\(.metadata.starts_at // "")\t\(.metadata.summary // "(no title)")"' \ | fzf --delimiter='\t' --with-nth=2,3 \ | cut -f1 \ | xargs -I{} mxr invite show {}What you get: an interactive invite picker keyed by time and summary.
Agent prompts that work
Section titled “Agent prompts that work”"Find calendar invites from the last 30 days. Use `mxr search'has:calendar newer_than:30d' --format ids`, inspect each with`mxr invite show`, and do not RSVP without showing me`mxr invite reply MESSAGE_ID <action> --dry-run --format json` first."mxr invite reply MESSAGE_ID accept --dry-run --format jsonIn the apps
Section titled “In the apps”The same invites are a dedicated, scrollable surface in both UIs — one
place to see every detected invite and RSVP without opening each message.
Rows are event-centric (when, summary, organizer, your RSVP status), built
from the local invite table rather than plain message rows. All surfaces
read the same Request::ListInvites, so the list is identical whether you
use the CLI, TUI, or web.
- TUI: open Calendar invites from the sidebar (below Owed). Then
j/kto move,aaccept ·t(orm) tentative ·ddecline,A/T/Dto reply with a comment,Enter/oto open the underlying message,hback to the sidebar. An RSVP sends after a short window; pressuto undo before it goes out. The row’s status refreshes once it lands. See keybindings. - Web: the Calendar invites entry in the sidebar opens
/invites— the same list with inline Accept / Tentative / Decline buttons (and a “with comment” option in the row menu). See Web app.
See also
Section titled “See also”mxr invites list --limit 5