async_client: Async JMAP calendar client#

Asynchronous JMAP client.

Mirrors JMAPClient with all public methods as coroutines. Uses niquests’ AsyncSession for HTTP: the one part of calendaring-jmap with no fallback to another HTTP library. See calendaring_jmap._http.

All response-parsing logic lives in _JMAPClientBase (client.py); each method here is a ~3-line async wrapper: get session, send request, delegate to parser.

class calendaring_jmap.async_client.AsyncJMAPClient(url: str, username: str | None = None, password: str | None = None, auth=None, auth_type: str | None = None, timeout: int = 30)[source]#

Bases: _JMAPClientBase

Asynchronous JMAP client for calendar operations.

The JMAP support is experimental, the API may change in minor-releases

Usage:

from calendaring_jmap import get_async_jmap_client
async with get_async_jmap_client(url="https://jmap.example.com/.well-known/jmap",
                                  username="alice", password="secret") as client:
    calendars = await client.get_calendars()
Parameters:
  • url – URL of the JMAP session endpoint (/.well-known/jmap).

  • username – Username for Basic auth.

  • password – Password for Basic auth, or bearer token if no username.

  • auth – A pre-built niquests-compatible auth object. Takes precedence over username/password if provided.

  • auth_type – Force a specific auth type: "basic" or "bearer".

  • timeout – HTTP request timeout in seconds.

Unless a method’s own docstring says otherwise, its account_id parameter is the JMAP account to operate on, defaulting to the authenticated user’s own primary account; pass a different account (typically one shared with you via share_calendar) to operate on that account’s data instead.

async accept_invitation(event_id: str, own_email: str, account_id: str | None = None) → None[source]#

Accept a meeting invitation, notifying the organizer.

See accept_invitation() for the full semantics.

async aclose() → None[source]#

Release the persistent HTTP session and its connection pool.

Only needed when the client was not used as an async context manager: the documented Quick Start builds one directly. Idempotent; the session is recreated on the next request.

async attach_to_event(event_id: str, blob_id: str, name: str, content_type: str, account_id: str | None = None) → None[source]#

Attach an uploaded blob to a calendar event.

See attach_to_event() for the full semantics.

async confirm_push_verification(subscription_id: str, verification_code: str) → None[source]#

Submit the verification code the server POSTed to callback_url.

See confirm_push_verification() for the full semantics.

async create_calendar(name: str, color: str | None = None, timezone: str | None = None) → str[source]#

Create a calendar.

Returns:

The server-assigned JMAP calendar ID.

Raises:

JMAPMethodError – If the server rejects the create request.

async create_event(calendar_id: str, ical_str: str, account_id: str | None = None) → str[source]#

Create a calendar event from an iCalendar string.

Parameters:
  • calendar_id – The JMAP calendar ID to create the event in.

  • ical_str – A VCALENDAR string representing the event.

  • account_id – The account owning calendar_id; pass the owner’s account here to add an event to a calendar shared with you (see get_calendars(account_id=...)).

Returns:

The server-assigned JMAP event ID.

Raises:
  • JMAPMethodError – If the server rejects the create request.

  • ValueError – If ical_str is malformed in a way ical_to_jscal rejects (missing UID/DTSTART, a negative duration, mismatched DTSTART/DTEND value types).

async create_task(task_list_id: str, title: str, **kwargs) → str[source]#

Create a task in a task list.

Parameters:
  • task_list_id – The JMAP task list ID to create the task in.

  • title – Task title (maps to VTODO SUMMARY).

  • **kwargs – Optional JMAP Task fields using wire names: description, due, start, timeZone, estimatedDuration, percentComplete, progress, priority.

Returns:

The server-assigned JMAP task ID.

Raises:

JMAPMethodError – If the server rejects the create request.

async decline_invitation(event_id: str, own_email: str, account_id: str | None = None) → None[source]#

Decline a meeting invitation, notifying the organizer.

Same as accept_invitation(), setting participationStatus to declined instead.

async delete_calendar(calendar_id: str, on_destroy_remove_events: bool = False, account_id: str | None = None) → None[source]#

Delete a calendar.

Parameters:
  • calendar_id – The JMAP calendar ID to delete.

  • on_destroy_remove_events – If False (the default), deleting a calendar that still has events fails with a calendarHasEvent error instead of deleting anything. Pass True to remove those events along with the calendar.

  • account_id – The account owning calendar_id; pass the owner’s account here to delete a calendar shared with you.

Raises:

JMAPMethodError – If the server rejects the delete. error_type is "calendarHasEvent" when the calendar still has events and on_destroy_remove_events was left False.

async delete_event(event_id: str, account_id: str | None = None, send_scheduling_messages: bool = False) → None[source]#

Delete a calendar event.

Parameters:
  • event_id – The JMAP event ID to delete.

  • account_id – The account owning event_id; pass the owner’s account here to delete an event on a calendar shared with you.

  • send_scheduling_messages – If true, and this account is the event’s origin, the server sends an iTIP CANCEL to the event’s participants (draft-ietf-jmap-calendars section 5.9.2.2).

Raises:

JMAPMethodError – If the server rejects the delete.

async delete_task(task_id: str) → None[source]#

Delete a task.

Parameters:

task_id – The JMAP task ID to delete.

Raises:

JMAPMethodError – If the server rejects the delete.

async download_attachment(blob_id: str, content_type: str | None = None, filename: str | None = None, account_id: str | None = None) → bytes[source]#

Download a JMAP blob by id.

See download_attachment() for the full semantics.

async get_address_books(account_id: str | None = None) → list[JMAPAddressBook][source]#

Fetch all address books for an account.

See get_address_books() for the full semantics, including the capability-fallback behavior.

async get_availability(account_ids: list[str], start: str, end: str, show_details: bool = False) → dict[str, list[BusyInterval]][source]#

Return busy intervals for each of your own accounts over a time period.

See get_availability() for the full semantics.

async get_calendar_subscriptions() → list[JMAPCalendar[Literal[True]]][source]#

Fetch the calendars the authenticated account is subscribed to.

JMAP Calendars has no separate subscription object; this is get_calendars() filtered to is_subscribed.

Returns:

List of JMAPCalendar objects with is_subscribed set.

async get_calendars(account_id: str | None = None) → list[JMAPCalendar[Literal[True]]][source]#

Fetch all calendars for an account.

Parameters:

account_id – Pass a different account here to browse calendars another user has shared with you, once share_calendar has granted access; the session only lists accounts you can actually reach (see Session.raw["accounts"]).

Returns:

List of JMAPCalendar objects.

async get_event(event_id: str, account_id: str | None = None) → JMAPCalendarObject[source]#

Fetch a calendar event as an iCalendar string.

Parameters:
  • event_id – The JMAP event ID to retrieve.

  • account_id – The account owning event_id; pass the owner’s account here to fetch an event on a calendar shared with you.

Returns:

A JMAPCalendarObject wrapping the raw JSCalendar dict. parent is None since no JMAPCalendar is available at the client level.

Raises:

JMAPMethodError – If the event is not found.

async get_event_attachments(event_id: str, account_id: str | None = None) → list[JMAPAttachment][source]#

Return the attachments on a calendar event.

See get_event_attachments() for the full semantics.

async get_objects_by_sync_token(sync_token: str) → tuple[list[JMAPCalendarObject], list[JMAPCalendarObject], list[str], str][source]#

Fetch events changed since a previous sync token.

Calls CalendarEvent/changes to discover which events were created, modified, or destroyed since sync_token was issued. Created and modified events are returned as JMAPCalendarObject instances; destroyed events are returned as IDs (the objects no longer exist on the server).

Parameters:

sync_token – A state string previously returned by get_sync_token() or by a prior call to this method.

Returns:

  • added: objects for newly created events (parent is None).

  • modified: objects for updated events (parent is None).

  • deleted: Event IDs that were destroyed.

  • new_sync_token: Pass to the next call to this method as sync_token.

Return type:

A 4-tuple (added, modified, deleted, new_sync_token)

Raises:

JMAPMethodError – If the server reports hasMoreChanges: true.

async get_sync_token() → str[source]#

Return the current CalendarEvent state string for use as a sync token.

Calls CalendarEvent/get with an empty ID list, so no event data is transferred, only the state field from the response.

Returns:

Opaque state string. Pass to get_objects_by_sync_token() to retrieve only what changed since this point.

async get_task(task_id: str) → dict[source]#

Fetch a task by ID.

Parameters:

task_id – The JMAP task ID to retrieve.

Returns:

Raw JMAP Task dict as returned by the server.

Raises:

JMAPMethodError – If the task is not found.

async get_task_lists() → list[dict][source]#

Fetch all task lists for the authenticated account.

Returns:

List of raw JMAP TaskList dicts as returned by the server.

async get_task_sync_token() → str[source]#

Return the current Task state string for use as a sync token.

Calls Task/get with an empty ID list, so no task data is transferred, only the state field from the response. Reads the Task type’s own state counter, not TaskList’s: RFC 8620 Section 5.2’s /changes is scoped per type, and get_tasks_by_sync_token() calls Task/changes, which only accepts a state previously returned for Task itself.

Returns:

Opaque state string. Pass to get_tasks_by_sync_token() to retrieve only what changed since this point.

async get_tasks_by_sync_token(sync_token: str) → tuple[list[dict], list[dict], list[str], str][source]#

Fetch tasks changed since a previous sync token.

Calls Task/changes to discover which tasks were created, modified, or destroyed since sync_token was issued. Created and modified tasks are returned as raw JMAP Task dicts, matching every other task method’s own return convention; destroyed tasks are returned as IDs.

Parameters:

sync_token – A state string previously returned by get_task_sync_token() or by a prior call to this method.

Returns:

  • added: raw dicts for newly created tasks.

  • modified: raw dicts for updated tasks.

  • deleted: Task IDs that were destroyed.

  • new_sync_token: Pass to the next call to this method as sync_token.

Return type:

A 4-tuple (added, modified, deleted, new_sync_token)

Raises:

JMAPMethodError – If the server reports hasMoreChanges: true.

async renew_push(subscription_id: str, expires: str | None = None) → None[source]#

Extend (or shorten) a push subscription’s expiry.

See renew_push() for the full semantics.

async search_contacts(text: str | None = None, email: str | None = None, account_id: str | None = None) → list[JMAPContact][source]#

Search for contact cards.

See search_contacts() for the full semantics.

async search_events(calendar_id: str | None = None, start: str | None = None, end: str | None = None, text: str | None = None, has_attachment: bool | None = None, participant_email: str | None = None, participation_status: str | None = None, participant_role: str | None = None, account_id: str | None = None) → list[JMAPCalendarObject][source]#

Search for calendar events.

See search_events() for the full semantics, including why has_attachment/participant_email/ participation_status/participant_role filter client-side and their confirmed server-specific false-negatives.

async search_tasks(text: str | None = None, due_before: str | None = None, due_after: str | None = None, progress: str | None = None) → list[dict][source]#

Search for tasks.

See search_tasks() for the full semantics, including why due_before/due_after/progress filter client-side and what the Task/query-unsupported fallback can and cannot help with.

async send_invite(calendar_id: str, ical_str: str, account_id: str | None = None) → str[source]#

Create a calendar event and notify its participants.

Identical to create_event(), except the server actually dispatches iTIP invitations to the event’s participants (an iCalendar string with ATTENDEE/ORGANIZER properties). create_event itself never sends scheduling messages; use this instead when the event has participants who need to be notified.

Parameters:
  • calendar_id – The JMAP calendar ID to create the event in.

  • ical_str – A VCALENDAR string representing the event.

  • account_id – The account owning calendar_id, same as create_event().

Returns:

The server-assigned JMAP event ID.

Raises:
  • JMAPMethodError – If the server rejects the create request, or with error_type == "noSupportedScheduleMethods" if a participant has no usable delivery method.

  • ValueError – Same conditions as create_event().

async set_default_alerts(calendar_id: str, alerts_with_time: dict | None = None, alerts_without_time: dict | None = None, account_id: str | None = None) → None[source]#

Set a calendar’s default alerts for new events.

alerts_with_time applies to timed events, alerts_without_time to all-day events (draft-ietf-jmap-calendars section 4). Each is a map of alert ID to Alert dict (RFC 8984 Section 4.5.2). Pass None to leave a property unchanged; pass {} to clear it.

Parameters:

account_id – The account owning calendar_id; pass the owner’s account here to set default alerts on a calendar shared with you.

Raises:

JMAPMethodError – If the server rejects the update.

async share_calendar(calendar_id: str, account_id: str, rights: dict, owning_account_id: str | None = None) → None[source]#

Share a calendar with another account.

account_id must already be a resolved JMAP Principal ID, not an email address. This client has no Principal/query/Principal/get support yet (RFC 9670), so resolving an email address to a Principal ID is left to the caller.

Replaces account_id’s entry in the calendar’s shareWith map wholesale; other accounts already sharing the calendar are left untouched. rights itself is not merged with any rights that account already had, so granting an additional right to an account that is already shared with needs the full rights dict, not just the new key. Requires the caller to already hold the mayShare right, and cannot grant a right the caller does not themselves hold.

Parameters:
  • account_id – The account to grant rights to.

  • rights – Dict of right names to bool, e.g. {"mayReadItems": True}. Replaces any rights this account already had on this calendar.

  • owning_account_id – The account owning calendar_id; pass the owner’s account here to re-share a calendar that was itself shared with you (if you hold mayShare on it).

Raises:

JMAPMethodError – If the server rejects the update, for example with forbidden when the caller lacks mayShare.

async subscribe_push(callback_url: str, device_client_id: str, types: list[str] | None = None) → str[source]#

Register a push subscription.

See subscribe_push() for the full semantics, including why this client cannot complete the verification handshake by itself.

async tentatively_accept(event_id: str, own_email: str, account_id: str | None = None) → None[source]#

Tentatively accept a meeting invitation, notifying the organizer.

Same as accept_invitation(), setting participationStatus to tentative instead.

async unsubscribe_push(subscription_id: str) → None[source]#

Destroy a push subscription.

See unsubscribe_push() for the full semantics.

async update_calendar(calendar_id: str, name: str | None = None, color: str | None = None, timezone: str | None = None, account_id: str | None = None) → None[source]#

Update a calendar’s name, color, or time zone.

name, color, and timeZone are per-user properties (draft-ietf-jmap-calendars section 4.3). Called by the calendar’s owner, this changes the value for everyone until a sharee sets their own override. Called by a sharee, it only ever changes that sharee’s own view; it can never rename or recolor the calendar for the owner or anyone else it is shared with.

Parameters:

account_id – The account owning calendar_id; pass the owner’s account here to update a calendar shared with you.

Raises:

JMAPMethodError – If the server rejects the update.

async update_event(event_id: str, ical_str: str, account_id: str | None = None) → None[source]#

Update a calendar event from an iCalendar string.

Parameters:
  • event_id – The JMAP event ID to update.

  • ical_str – A VCALENDAR string with the updated event data.

  • account_id – The account owning event_id; pass the owner’s account here to update an event on a calendar shared with you.

Raises:
  • JMAPMethodError – If the server rejects the update.

  • ValueError – If ical_str is malformed in a way ical_to_jscal rejects (missing UID/DTSTART, a negative duration, mismatched DTSTART/DTEND value types).

async update_task(task_id: str, patch: dict) → None[source]#

Update a task with a partial patch.

Parameters:
  • task_id – The JMAP task ID to update.

  • patch – Partial patch dict mapping property names to new values.

Raises:

JMAPMethodError – If the server rejects the update.

async upload_attachment(data: bytes, content_type: str, account_id: str | None = None) → str[source]#

Upload binary data as a JMAP blob.

See upload_attachment() for the full semantics.

Last updated on 2026-10-08.