calendaring_jmap.objects.contact module#

JMAP Contacts objects (RFC 9610).

AddressBook and ContactCard, as returned by AddressBook/get and ContactCard/get. ContactCard properties follow JSContact (RFC 9553).

Rights maps (share_with, my_rights) and the raw JSContact name/ emails dicts are all kept as untyped dicts rather than typed sub-objects, matching JMAPCalendar's own share_with/my_rights convention.

class calendaring_jmap.objects.contact.JMAPAddressBook(id, name, description=None, sort_order=0, is_default=False, is_subscribed=True, share_with=None, my_rights=dict())[source]#

Bases: object

A JMAP AddressBook object (RFC 9610 Section 2).

Variables:
  • id (str) – Server-assigned identifier.

  • name (str) – Display name, non-empty, at most 255 UTF-8 octets.

  • description (str | None) – Optional longer description.

  • sort_order (int) – Hint for display ordering (lower = first). Default 0.

  • is_default (bool) – True for at most one address book in the account (RFC 9610 Section 2 says this SHOULD be true for exactly one, but only MUST NOT be true for more than one), server-set.

  • is_subscribed (bool) – Whether the user is subscribed to this address book.

  • share_with (dict | None) – Map of Principal id (RFC 9670 Section 2) to a dict of AddressBookRights (mayRead, mayWrite, mayShare, mayDelete). None if unshared or the server lacks RFC 9670 support (RFC 9610 Section 2), verified against Cyrus. Stalwart behaves differently: it returns {} here instead when unshared, not None, found by testing directly against it. A caller checking "is this shared" should treat the value as falsy (not address_book.share_with), not test for is None specifically.

  • my_rights (dict) – AddressBookRights dict for the current user, server-set.

description: str | None = None#
classmethod from_jmap(data)[source]#

Construct a JMAPAddressBook from a raw JMAP AddressBook JSON dict.

Unknown keys in data are silently ignored so that forward compatibility is maintained as the spec evolves.

Return type:

JMAPAddressBook

id: str#
is_default: bool = False#
is_subscribed: bool = True#
my_rights: dict#
name: str#
share_with: dict | None = None#
sort_order: int = 0#
class calendaring_jmap.objects.contact.JMAPContact(id, uid=None, address_book_ids=dict(), kind='individual', name=None, emails=None)[source]#

Bases: object

A JMAP ContactCard object (RFC 9610 Section 3), a JSContact Card (RFC 9553 Section 2) plus JMAP's own id/addressBookIds.

Variables:
  • id (str) – Server-assigned identifier. May differ from uid.

  • uid (str | None) – The card's own JSContact uid (RFC 9553 Section 2.1.9). That section marks it mandatory on every Card, but confirmed live that Stalwart's ContactCard/get never returns it at all, even when explicitly requested via properties. Unlike id, this is not required here: a strict-missing check would raise on every Stalwart contact. Cyrus does return it.

  • address_book_ids (dict) – Map of AddressBook id to True; a card belongs to at least one address book.

  • kind (str) – JSContact Card kind (RFC 9553 Section 2.1.4): one of "individual" (default), "group", "org", "location", "device", "application".

  • name (dict | None) – Raw JSContact Name dict (RFC 9553 Section 2.2.1), or None. Its own shape (full vs. components) is read through display_name(), not by exposing typed fields here.

  • emails (dict | None) – Raw JSContact EmailAddress map (RFC 9553 Section 2.3.1): {id: {"address": str, "contexts": {...}, "pref": int, ...}}, or None.

address_book_ids: dict#
display_name()[source]#

Best-effort human-readable name.

RFC 9553 Section 2.2.1.1: a Name object has either full or components present, not necessarily both. Prefers full; falls back to components otherwise. When isOrdered is true, a "separator" component's own value (or defaultSeparator if there's no explicit one at that position, or a single space if neither is set) is inserted between the surrounding non-separator components, per the RFC's own guidance, e.g. given="Jean", separator="-", surname="Paul" joins to "Jean-Paul", not "Jean Paul". When isOrdered is false, the RFC forbids any "separator" component at all, so components are simply space-joined in list order. Returns None if neither full nor components is present.

Return type:

str | None

emails: dict | None = None#
classmethod from_jmap(data)[source]#

Construct a JMAPContact from a raw JMAP ContactCard JSON dict.

Unknown keys (including JSContact properties this client doesn't model, e.g. organizations, addresses, notes) are silently ignored for forward compatibility.

Return type:

JMAPContact

id: str#
kind: str = 'individual'#
name: dict | None = None#
primary_email()[source]#

Return one email address for this contact, or None.

Picks the entry with the lowest pref (RFC 9553 Section 1.5.3: 1 is most preferred, 100 least; an entry with no pref at all, or an explicit null, is treated as least preferred of all).

Return type:

str | None

uid: str | None = None#

Last updated on 2026-11-01.