Calendar invites for AI agents
An agent inbox reads meeting invitations, answers them, schedules its own meetings, and shares a calendar a person can follow in Google, Apple or Outlook.
How it works
A calendar invitation is an email with a calendar file inside. Every agent inbox understands that file: invitations it receives land on its calendar, it can accept or decline them, and it can send its own invitations that show Yes and No buttons in Gmail, Outlook and Apple Calendar. There is no Google account and no OAuth, only email. Invitations need a plain agent inbox; an end-to-end encrypted inbox never reads mail content, so it has no calendar. On the Free plan without a verified domain, the invitations an inbox sends go only to your own addresses.
Read an invitation that arrives
The message carries a parsed summary of the invitation, and the event lives on the inbox calendar with its current state. It stays there after retention deletes the email, so an agent can still ask what was booked for tomorrow.
msg = inbox.wait_for_message(timeout=60)
invite = msg.calendar_event # None when the mail carries no invitation
event = inbox.calendar_event(invite["event_id"])
print(event["title"], event["start"], event["my_status"])
Answer it
The answer goes back to the organizer as a standard calendar reply, so their Google, Outlook or Apple calendar shows it. It is sent like any mail from the inbox and is not retried on its own, because a retry after a lost response would answer twice.
inbox.rsvp(event["id"], "accepted", comment="See you then")
Schedule a meeting
The inbox is the organizer. Give the time with an offset, or without one plus a time zone name; a time that could mean two different hours is refused rather than guessed. Add a video link as the location: MailFlat does not create one for you.
res = inbox.create_calendar_event(
"Intro call", "2026-10-06T14:00:00", timezone="America/New_York",
duration_minutes=30, attendees=["ali@example.com"],
location="https://meet.google.com/abc-defg-hij")
event_id = res["event"]["id"]
Move it or cancel it
Pass only what changes. The same event updates in every guest's calendar, with no duplicate, and a new time asks everyone again. A cancellation removes it from their calendars.
inbox.update_calendar_event(event_id, start="2026-10-07T14:00:00-04:00")
inbox.cancel_calendar_event(event_id, message="Something came up")
Know when guests answer
Add a webhook in the dashboard (Webhooks) with the event calendar.* and your endpoint hears about every change: calendar.event.created, updated and cancelled for invitations the inbox receives, and calendar.attendee.responded when a guest answers a meeting it organized.
@app.post("/mailflat")
def mailflat_hook(payload: dict):
if payload["event"] == "calendar.attendee.responded":
ev = payload["calendar_event"]
going = [a["email"] for a in ev["attendees"] if a["status"] == "accepted"]
print(ev["title"], "confirmed by", going)
Let a person follow the calendar
Hand a person the read-only subscribe link and they see the inbox's meetings, guests and answers in their own calendar app. Every call returns the same link, so sharing it twice never breaks a subscription; rotate it if it leaks. Apple Calendar and Outlook refresh it often, Google every 8 to 24 hours, so use the API above for live state.
feed = inbox.calendar_feed()
print(feed["subscribe_links"]["google"]) # also apple, outlook
inbox.rotate_calendar_feed() # the link leaked: the old one stops at once
Worth knowing
Prefer clicking? Use the dashboard
Open an inbox and choose the Calendar tab. New meeting sends invitations from the inbox, each meeting row lets you edit or cancel it, invitations you received have Accept and Decline, and the subscribe strip adds the calendar to Google, Apple or Outlook in one click. A booking page where people pick a free slot is not part of this, and recurring meetings are shown as one entry that repeats.
See also
Agent calendar
How an agent inbox reads meeting invitations, answers them, schedules its own meetings and shares a calendar you can follow in Google, Apple or Outlook.
Sending emailPoint it the other way: send real mail from a MailFlat address and check that your application handles what arrives.
WebhooksPush incoming mail to your own endpoint instead of polling: registration, payload shape, signature verification and retry behaviour.