Skip to navigation

Invitations

Beta
Send calendar invitations, receive them by email and respond.

Calendar is in private beta in US production (api.agentmail.to). The beta is not available in EU production (api.agentmail.eu). Organizations without access receive a 403 with the message Calendar access is not enabled for this organization. Email support@agentmail.to to request access. Upgrade to the latest Python or TypeScript SDK to use the calendar methods.

AgentMail calendars speak iMIP, the standard behind calendar invitations in email. Invitations your agent sends open as normal meeting invitations in Google Calendar, Outlook and Apple Calendar, and invitations those apps send to the inbox appear on its calendar.

Sending invitations

Add attendees and set send_invites: true when you create an event. The inbox becomes the organizer and emails an invitation to each attendee.

from agentmail import AgentMail
client = AgentMail()
created = client.inboxes.calendar.create_event(
"scheduler@agentmail.to",
title="Intro call with Acme",
start="2026-10-15T14:00:00",
end="2026-10-15T14:30:00",
timezone="America/New_York",
location="https://meet.example.com/acme-intro",
attendees=[
{"email": "jane@acme.com", "name": "Jane Doe"},
{"email": "sam@acme.com", "role": "optional"},
],
send_invites=True,
)

Each attendee receives a separate email from the inbox with the subject Invitation: <title>, a short text body describing the event, and the event as an invite.ics attachment (METHOD:REQUEST). The emails are sent like any other message from the inbox and appear among its sent messages.

Invitations are sent in the background after the event is stored. They are not sent unless you ask: send_invites defaults to false, so you can add attendees for your own records without emailing anyone.

Sending changes and cancellations

Pass send_invites again whenever attendees should hear about a change:

ActionRequestAttendees receive
Update the eventPATCH with "send_invites": true in the bodyAn updated invitation (REQUEST). Invited attendees removed by the update get a cancellation (CANCEL).
Cancel one dateDELETE a dated ID with ?send_invites=trueA cancellation for that date (CANCEL)
Delete the eventDELETE the event UUID with ?send_invites=trueA cancellation (CANCEL)

A change that is not sent stays on your calendar only; attendees keep their previous version. sequence increases whenever a change to the event affects what attendees see, so their calendar apps apply the newest update. A change to one date of a recurring event increases it only when the change is sent with send_invites.

Only events the inbox organizes can send. Using send_invites on an event that came from someone else’s invitation returns 409 calendar_response_invalid.

Send limits

Invitation emails count toward the same organization, pod and inbox send limits as any other email from the inbox. These are separate from the API’s request rate limits. A request that asks for emails is charged one send per recipient before anything is saved:

RequestCharged
Create or update with send_invites: trueOne per attendee on the event after the change. Cancellations to attendees the update removed are not charged.
Delete an event or cancel a date with send_invites=trueOne per attendee of the event
Respond with send_reply (the default)One, for the reply to the organizer

If the charge would exceed a limit, the request returns 429 rate_limit_exceeded and the event is not created or changed. Wait for the Retry-After header when present, or retry without send_invites to save the change without emailing anyone.

The charge is taken after the request passes validation and any If-Match check, so a 400 or 412 is not charged, but a request that fails after that (for example with 409) is. A create retried with the same client_id that returns the original event is not charged again. While the inbox is paused or suspended, nothing is charged and no invitations are sent.

Invitations also pass the same outbound checks as other mail, such as spam checks and the recipient limits for new senders. An invitation those checks refuse is not sent or retried; the event itself is still saved.

Attendee replies

When an attendee accepts, declines or tentatively accepts, their calendar app emails a reply to the inbox. AgentMail matches it to the event, updates that attendee’s status, comment and responded_at, and sends a calendar.event.responded webhook. A reply about a single date of a recurring event updates only that date.

A reply is only applied to the attendee whose address sent it, so one attendee cannot answer for another.

Receiving invitations

When the inbox receives an email with a calendar invitation attached, AgentMail adds the event to the inbox’s calendar automatically. The new event has source: email, organizer_email set to the sender, the attendees listed in the invitation, and origin_message_id pointing at the email. A calendar.event.created webhook follows, as well as the usual message.received for the email itself.

Later emails from the organizer keep the event in sync:

  • An updated invitation (REQUEST) updates the event, or one date of it.
  • A cancellation (CANCEL) sets the event, or one date of it, to cancelled.
  • Updates are ordered by iCalendar SEQUENCE, so an older update that arrives late does not overwrite a newer one. A change to one date is compared only with earlier changes to that same date.

Which invitations are accepted

To keep strangers from writing to your agent’s calendar, an invitation is applied only when all of these hold:

  • The email passed sender authentication and is not labeled spam, blocked or unauthenticated. Messages held for a security review are processed if they are released.
  • The authenticated sender is the event’s organizer. A forwarded invitation, or a cancellation sent by anyone other than the organizer, is ignored.
  • The invitation is a text/calendar or application/ics attachment of at most 1 MB, containing exactly one event.
  • The organization has calendar access.

Invitations that fail these checks leave the calendar unchanged. The email is still delivered to the inbox like any other message.

Current limitations

  • Outlook time zones. Invitations that name a Windows time zone (such as Pacific Standard Time) instead of an IANA zone are not imported.
  • Recurring invitations with exceptions. Invitations that bundle a series and its edited dates as several events in one file, as Google Calendar does for recurring meetings with exceptions, are not imported.
  • All-day invitations are stored with the UTC time zone.

Responding to an invitation

Use Respond to Event to accept, decline or tentatively accept an invitation the inbox received. AgentMail updates the inbox’s own attendee entry and, by default, emails the reply to the organizer.

response = client.inboxes.calendar.respond_to_event(
"scheduler@agentmail.to",
"a1d5c7e9-2b4f-4c6a-9e8d-3f7b1c5a9d20",
status="accepted",
comment="See you there.",
)
  • status is accepted, declined or tentative.
  • send_reply defaults to true. Set it to false to record your answer without emailing the organizer.
  • Pass a dated ID instead of the event UUID to answer for one date of a recurring invitation.
  • To make the response conditional, send the event’s or date’s etag in If-Match.
  • Responding only works on email events where the inbox is an attendee. Anything else returns 409 calendar_response_invalid.
  • A calendar.event.responded webhook is sent.

The reply email has the subject Responded: <title> and is threaded with the original invitation.

Editing an invitation you received

You can PATCH an email event to change your copy, for example to add metadata that links it to your own records. Those edits are not sent to the organizer. A later update from the organizer replaces the fields its invitation carries, such as the time, title and attendees; invitations never change metadata.