rfc9610.original   rfc9610.txt 
JMAP N.M. Jenkins, Ed. Internet Engineering Task Force (IETF) N. Jenkins, Ed.
Internet-Draft Fastmail Request for Comments: 9610 Fastmail
Intended status: Standards Track 7 June 2024 Category: Standards Track December 2024
Expires: 9 December 2024 ISSN: 2070-1721
JMAP for Contacts JSON Meta Application Protocol (JMAP) for Contacts
draft-ietf-jmap-contacts-10
Abstract Abstract
This document specifies a data model for synchronising contacts data This document specifies a data model for synchronising contact data
with a server using JMAP. with a server using the JSON Meta Application Protocol (JMAP).
Status of This Memo Status of This Memo
This Internet-Draft is submitted in full conformance with the This is an Internet Standards Track document.
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months This document is a product of the Internet Engineering Task Force
and may be updated, replaced, or obsoleted by other documents at any (IETF). It represents the consensus of the IETF community. It has
time. It is inappropriate to use Internet-Drafts as reference received public review and has been approved for publication by the
material or to cite them other than as "work in progress." Internet Engineering Steering Group (IESG). Further information on
Internet Standards is available in Section 2 of RFC 7841.
This Internet-Draft will expire on 9 December 2024. Information about the current status of this document, any errata,
and how to provide feedback on it may be obtained at
https://www.rfc-editor.org/info/rfc9610.
Copyright Notice Copyright Notice
Copyright (c) 2024 IETF Trust and the persons identified as the Copyright (c) 2024 IETF Trust and the persons identified as the
document authors. All rights reserved. document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents (https://trustee.ietf.org/ Provisions Relating to IETF Documents
license-info) in effect on the date of publication of this document. (https://trustee.ietf.org/license-info) in effect on the date of
Please review these documents carefully, as they describe your rights publication of this document. Please review these documents
and restrictions with respect to this document. Code Components carefully, as they describe your rights and restrictions with respect
extracted from this document must include Revised BSD License text as to this document. Code Components extracted from this document must
described in Section 4.e of the Trust Legal Provisions and are include Revised BSD License text as described in Section 4.e of the
provided without warranty as described in the Revised BSD License. Trust Legal Provisions and are provided without warranty as described
in the Revised BSD License.
Table of Contents Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 1. Introduction
1.1. Notational Conventions . . . . . . . . . . . . . . . . . 3 1.1. Notational Conventions
1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 3 1.2. Terminology
1.3. Data Model Overview . . . . . . . . . . . . . . . . . . . 3 1.3. Data Model Overview
1.4. Addition to the Capabilities Object . . . . . . . . . . . 3 1.4. Addition to the Capabilities Object
1.4.1. urn:ietf:params:jmap:contacts . . . . . . . . . . . . 3 1.4.1. urn:ietf:params:jmap:contacts
2. AddressBooks . . . . . . . . . . . . . . . . . . . . . . . . 4 2. AddressBooks
2.1. AddressBook/get . . . . . . . . . . . . . . . . . . . . . 6 2.1. AddressBook/get
2.2. AddressBook/changes . . . . . . . . . . . . . . . . . . . 6 2.2. AddressBook/changes
2.3. AddressBook/set . . . . . . . . . . . . . . . . . . . . . 6 2.3. AddressBook/set
3. ContactCards . . . . . . . . . . . . . . . . . . . . . . . . 7 3. ContactCards
3.1. ContactCard/get . . . . . . . . . . . . . . . . . . . . . 8 3.1. ContactCard/get
3.2. ContactCard/changes . . . . . . . . . . . . . . . . . . . 8 3.2. ContactCard/changes
3.3. ContactCard/query . . . . . . . . . . . . . . . . . . . . 8 3.3. ContactCard/query
3.3.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 8 3.3.1. Filtering
3.3.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 11 3.3.2. Sorting
3.4. ContactCard/queryChanges . . . . . . . . . . . . . . . . 11 3.4. ContactCard/queryChanges
3.5. ContactCard/set . . . . . . . . . . . . . . . . . . . . . 11 3.5. ContactCard/set
3.6. ContactCard/copy . . . . . . . . . . . . . . . . . . . . 11 3.6. ContactCard/copy
4. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 12 4. Examples
4.1. Fetching initial data . . . . . . . . . . . . . . . . . . 12 4.1. Fetching Initial Data
4.2. Changing the default address book . . . . . . . . . . . . 14 4.2. Changing the Default Address Book
5. Internationalisation Considerations . . . . . . . . . . . . . 14 5. Internationalisation Considerations
6. Security Considerations . . . . . . . . . . . . . . . . . . . 15 6. Security Considerations
7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 15 7. IANA Considerations
7.1. JMAP capability registration for "contacts" . . . . . . . 15 7.1. JMAP Capability Registration for "contacts"
7.2. JMAP Data Type Registration for "AddressBook" . . . . . . 15 7.2. JMAP Data Type Registration for "AddressBook"
7.3. JMAP Data Type Registration for "ContactCard" . . . . . . 16 7.3. JMAP Data Type Registration for "ContactCard"
7.4. JMAP Error Codes Registry . . . . . . . . . . . . . . . . 16 7.4. JMAP Error Codes Registry
7.4.1. addressBookHasContents . . . . . . . . . . . . . . . 16 7.4.1. addressBookHasContents
7.5. JSContact Property Registrations . . . . . . . . . . . . 16 7.5. JSContact Property Registrations
7.5.1. id . . . . . . . . . . . . . . . . . . . . . . . . . 16 7.5.1. id
7.5.2. addressBookIds . . . . . . . . . . . . . . . . . . . 17 7.5.2. addressBookIds
7.5.3. blobId . . . . . . . . . . . . . . . . . . . . . . . 17 7.5.3. blobId
8. Normative References . . . . . . . . . . . . . . . . . . . . 17 8. References
9. Informative References . . . . . . . . . . . . . . . . . . . 18 8.1. Normative References
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 18 8.2. Informative References
Author's Address
1. Introduction 1. Introduction
JMAP ([RFC8620] JSON Meta Application Protocol) is a generic protocol The JSON Meta Application Protocol (JMAP) [RFC8620] is a generic
for synchronising data, such as mail, calendars or contacts, between protocol for synchronising data, such as mail, calendars, or
a client and a server. It is optimised for mobile and web contacts, between a client and a server. It is optimised for mobile
environments, and aims to provide a consistent interface to different and web environments and aims to provide a consistent interface to
data types. different data types.
This specification defines a data model for synchronising contacts This specification defines a data model for synchronising contacts
between a client and a server using JMAP. between a client and a server using JMAP.
1.1. Notational Conventions 1.1. Notational Conventions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in BCP "OPTIONAL" in this document are to be interpreted as described in
14 [RFC2119] [RFC8174] when, and only when, they appear in all BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here. capitals, as shown here.
Type signatures, examples and property descriptions in this document Type signatures, examples, and property descriptions in this document
follow the conventions established in Section 1.1 of [RFC8620]. The follow the conventions established in Section 1.1 of [RFC8620]. The
Id, UnsignedInt, and UTCDate data types defined in Sections 1.2, 1.3, Id, UnsignedInt, and UTCDate data types defined in Sections 1.2, 1.3,
and 1.4 of [RFC8620] are also used in this document. and 1.4 of [RFC8620] are also used in this document.
1.2. Terminology 1.2. Terminology
The same terminology is used in this document as in the core JMAP The same terminology used in the core JMAP specification (see
specification, see [RFC8620], Section 1.6. Section 1.6 of [RFC8620]) is also used in this document.
The terms AddressBook and ContactCard (with these specific The terms AddressBook and ContactCard (with these specific
capitalizations) are used to refer to the data types defined in this capitalizations) are used to refer to the data types defined in this
document and instances of those data types. document and instances of those data types.
1.3. Data Model Overview 1.3. Data Model Overview
An Account (see [RFC8620], Section 1.6.2) with support for the An Account (see Section 1.6.2 of [RFC8620]) with support for the
contacts data model contains zero or more AddressBook objects, which contact data model contains zero or more AddressBook objects, which
is a named collection of zero or more ContactCards. A ContactCard is is a named collection of zero or more ContactCards. A ContactCard is
a representation of a person, company, or other entity, or a group of a representation of a person, company, entity, or a group of such
such entities, in JSContact Card format, as defined in Section 2 of entities in JSContact Card format, as defined in Section 2 of
[RFC9553]. Each ContactCard belongs to one or more AddressBooks. [RFC9553]. Each ContactCard belongs to one or more AddressBooks.
In servers with support for JMAP Sharing [I-D.ietf-jmap-sharing], In servers with support for JMAP Sharing [RFC9670], users may see and
users may see and configure sharing of contact data with others. configure sharing of contact data with others. Sharing permissions
Sharing permissions are managed per AddressBook. are managed per AddressBook.
1.4. Addition to the Capabilities Object 1.4. Addition to the Capabilities Object
The capabilities object is returned as part of the JMAP Session The capabilities object is returned as part of the JMAP Session
object; see [RFC8620], Section 2. This document defines one object; see Section 2 of [RFC8620]. This document defines one
additional capability URI. additional capability URI.
1.4.1. urn:ietf:params:jmap:contacts 1.4.1. urn:ietf:params:jmap:contacts
This represents support for the AddressBook and ContactCard data This represents support for the AddressBook and ContactCard data
types and associated API methods. The value of this property in the types and associated API methods. The value of this property in the
JMAP Session capabilities property is an empty object. JMAP Session "capabilities" property is an empty object.
The value of this property in an account's accountCapabilities The value of this property in an account's "accountCapabilities"
property is an object that MUST contain the following information on property is an object that MUST contain the following information on
server capabilities and permissions for that account: server capabilities and permissions for that account:
* *maxAddressBooksPerCard*: UnsignedInt|null *maxAddressBooksPerCard*: UnsignedInt|null
The maximum number of AddressBooks (see Section 2) that can be The maximum number of AddressBooks (see Section 2) that can be
assigned to a single ContactCard object (see Section 3). This assigned to a single ContactCard object (see Section 3). This
MUST be an integer >= 1, or null for no limit (or rather, the MUST be an integer >= 1, or null for no limit (or rather, the
limit is always the number of AddressBooks in the account). limit is always the number of AddressBooks in the account).
* *mayCreateAddressBook*: Boolean
*mayCreateAddressBook*: Boolean
The user may create an AddressBook in this account if, and only The user may create an AddressBook in this account if, and only
if, this is true. if, this is true.
2. AddressBooks 2. AddressBooks
An AddressBook is a named collection of ContactCards. All An AddressBook is a named collection of ContactCards. All
ContactCards are associated with one or more AddressBook. ContactCards are associated with one or more AddressBooks.
A *AddressBook* object has the following properties:
* *id*: Id (immutable; server-set) An *AddressBook* object has the following properties:
*id*: Id (immutable; server-set)
The id of the AddressBook. The id of the AddressBook.
* *name*: String *name*: String
The user-visible name of the AddressBook. This MUST NOT be the The user-visible name of the AddressBook. This MUST NOT be the
empty string and MUST NOT be greater than 255 octets in size when empty string and MUST NOT be greater than 255 octets in size when
encoded as UTF-8. encoded as UTF-8.
* *description*: String|null (default: null) *description*: String|null (default: null)
An optional long-form description of the AddressBook that provides
An optional longer-form description of the AddressBook, to provide
context in shared environments where users need more than just the context in shared environments where users need more than just the
name. name.
* *sortOrder*: UnsignedInt (default: 0) *sortOrder*: UnsignedInt (default: 0)
Defines the sort order of AddressBooks when presented in the Defines the sort order of AddressBooks when presented in the
client's UI, so it is consistent between devices. The number MUST client's UI so it is consistent between devices. The number MUST
be an integer in the range 0 <= sortOrder < 2^(31.) be an integer in the range 0 <= sortOrder < 2^31.
An AddressBook with a lower order is to be displayed before a An AddressBook with a lower order is to be displayed before a
AddressBook with a higher order in any list of AddressBooks in the AddressBook with a higher order in any list of AddressBooks in the
client's UI. AddressBooks with equal order should be sorted in client's UI. AddressBooks with equal order should be sorted in
alphabetical order by name. The sorting should take into account alphabetical order by name. The sorting should take into account
locale-specific character order convention. locale-specific character order convention.
* *isDefault*: Boolean (server-set) *isDefault*: Boolean (server-set)
This SHOULD be true for exactly one AddressBook in any account and
This SHOULD be true for exactly one AddressBook in any account, MUST NOT be true for more than one AddressBook within an account.
and MUST NOT be true for more than one AddressBook within an The default AddressBook should be used by clients whenever they
account. The default AddressBook should be used by clients need to choose an AddressBook for the user within this account and
whenever they need to choose an AddressBook for the user within they do not have any other information on which to make a choice.
this account, and they do not have any other information on which For example, if the user creates a new contact card, the client
to make a choice. For example, if the user creates a new contact may automatically set the card as belonging to the default
card, the client may automatically set the card as belonging to AddressBook from the user's primary account.
the default AddressBook from the user's primary account.
* *isSubscribed*: Boolean
*isSubscribed*: Boolean
True if the user has indicated they wish to see this AddressBook True if the user has indicated they wish to see this AddressBook
in their client. This SHOULD default to false for AddressBooks in in their client. This SHOULD default to false for AddressBooks in
shared accounts the user has access to and true for any new shared accounts that the user has access to and true for any new
AddressBooks created by the user themself. AddressBooks created by the user themself.
If false, the AddressBook and its contents SHOULD only be If false, the AddressBook and its contents SHOULD only be
displayed when the user explicitly requests it or to offer it for displayed when the user explicitly requests it. The UI may offer
the user to subscribe to. to the user the option of subscribing to it.
* *shareWith*: Id[AddressBookRights]|null (default: null)
A map of Principal (Section 2 of [I-D.ietf-jmap-sharing]) id to
rights for principals this AddressBook is shared with. The
principal to which this AddressBook belongs MUST NOT be in this
set. This is null if the AddressBook is not shared with anyone,
or the server does not support [I-D.ietf-jmap-sharing]. The value
may be modified only if the user has the mayShare right. The
account id for the principals may be found in the
urn:ietf:params:jmap:principals:owner capability of the Account to
which the AddressBook belongs.
* *myRights*: AddressBookRights (server-set) *shareWith*: Id[AddressBookRights]|null (default: null)
A map of the Principal id (Section 2 of [RFC9670]) to rights for
Principals this AddressBook is shared with. The Principal to
which this AddressBook belongs MUST NOT be in this set. This is
null if the AddressBook is not shared with anyone or if the server
does not support [RFC9670]. The value may be modified only if the
user has the "mayShare" right. The account id for the Principals
may be found in the urn:ietf:params:jmap:principals:owner
capability of the Account to which the AddressBook belongs.
*myRights*: AddressBookRights (server-set)
The set of access rights the user has in relation to this The set of access rights the user has in relation to this
AddressBook. AddressBook.
An *AddressBookRights* object has the following properties: An *AddressBookRights* object has the following properties:
* *mayRead*: Boolean *mayRead*: Boolean
The user may fetch the ContactCards in this AddressBook. The user may fetch the ContactCards in this AddressBook.
* *mayWrite*: Boolean
The user may create, modify or destroy all ContactCards in this *mayWrite*: Boolean
The user may create, modify, or destroy all ContactCards in this
AddressBook, or move them to or from this AddressBook. AddressBook, or move them to or from this AddressBook.
* *mayShare*: Boolean
*mayShare*: Boolean
The user may modify the "shareWith" property for this AddressBook. The user may modify the "shareWith" property for this AddressBook.
* *mayDelete*: Boolean *mayDelete*: Boolean
The user may delete the AddressBook itself. The user may delete the AddressBook itself.
2.1. AddressBook/get 2.1. AddressBook/get
This is a standard "/get" method as described in [RFC8620], This is a standard "/get" method as described in Section 5.1 of
Section 5.1. The _ids_ argument may be null to fetch all at once. [RFC8620]. The "ids" argument may be null to fetch all at once.
2.2. AddressBook/changes 2.2. AddressBook/changes
This is a standard "/changes" method as described in [RFC8620], This is a standard "/changes" method as described in Section 5.2 of
Section 5.2. [RFC8620].
2.3. AddressBook/set 2.3. AddressBook/set
This is a standard "/set" method as described in [RFC8620], This is a standard "/set" method as described in Section 5.3 of
Section 5.3 but with the following additional request argument: [RFC8620], but with the following additional request arguments:
* *onDestroyRemoveContents*: Boolean (default: false)
*onDestroyRemoveContents*: Boolean (default: false)
If false, any attempt to destroy an AddressBook that still has a If false, any attempt to destroy an AddressBook that still has a
ContactCard in it will be rejected with an addressBookHasContents ContactCard in it will be rejected with an
SetError. If true, any ContactCard that is in the AddressBook "addressBookHasContents" SetError. If true, any ContactCard that
will be removed from it, and if such a ContactCard does not belong is in the AddressBook will be removed from it, and if such a
to any other AddressBook it will be destroyed. ContactCard does not belong to any other AddressBook, it will be
destroyed.
* *onSuccessSetIsDefault*: Id|null
If an id is given, and all creates, updates and destroys (if any) *onSuccessSetIsDefault*: Id|null
If an id is given, and all creates, updates, and destroys (if any)
succeed without error, the server will try to set this AddressBook succeed without error, the server will try to set this AddressBook
as the default. (For references to AddressBook creations, this is as the default. (For references to AddressBook creations, this is
equivalent to a creation-reference, so the id will be the creation equivalent to a creation-reference, so the id will be the creation
id prefixed with a "#".) id prefixed with a "#".)
If the id is not found, or the change is not permitted by the server If the id is not found or if the change is not permitted by the
for policy reasons, it MUST be ignored and the currently default server for policy reasons, it MUST be ignored and the current default
AddressBook (if any) will remain as such. No error is returned to AddressBook (if any) will remain as such. No error is returned to
the client in this case. the client in this case.
As per [RFC8620], Section 5.3, if the default is successfully As per Section 5.3 of [RFC8620], if the default AddressBook is
changed, any changed objects MUST be reported in either the "created" successfully changed, any changed objects MUST be reported in either
or "updated" argument in the response as appropriate, with the the "created" or "updated" argument in the response as appropriate,
server-set value included. with the server-set value included.
The "shareWith" property may only be set by users that have the The "shareWith" property may only be set by users that have the
mayShare right. When modifying the shareWith property, the user "mayShare" right. When modifying the "shareWith" property, the user
cannot give a right to a principal if the principal did not already cannot give a right to a Principal if the Principal did not already
have that right and the user making the change also does not have have that right and the user making the change also does not have
that right. Any attempt to do so MUST be rejected with a forbidden that right. Any attempt to do so MUST be rejected with a "forbidden"
SetError. SetError.
Users can subscribe or unsubscribe to an AddressBook by setting the Users can subscribe or unsubscribe to an AddressBook by setting the
"isSubscribed" property. The server MAY forbid users from "isSubscribed" property. The server MAY forbid users from
subscribing to certain AddressBooks even though they have permission subscribing to certain AddressBooks even though they have permission
to see them, rejecting the update with a forbidden SetError. to see them, rejecting the update with a "forbidden" SetError.
The following extra SetError type is defined:
For "destroy": The following extra SetError type is defined for "destroy":
* *addressBookHasContents*: The AddressBook has at least one *addressBookHasContents*: The AddressBook has at least one
ContactCard assigned to it, and the "onDestroyRemoveContents" ContactCard assigned to it and the "onDestroyRemoveContents"
argument was false. argument was false.
3. ContactCards 3. ContactCards
A *ContactCard* object contains information about a person, company, A *ContactCard* object contains information about a person, company,
or other entity, or represents a group of such entities. It is a or other entity, or represents a group of such entities. It is a
JSContact Card object, as defined in Section 2 of [RFC9553], with the JSContact Card object as defined in Section 2 of [RFC9553] with the
following additional properties: following additional properties:
* *id*: Id (immutable; server-set) *id*: Id (immutable; server-set)
The id of the ContactCard. The id property MAY be different to The id of the ContactCard. The "id" property MAY be different to
the ContactCard's "uid" property (as defined in Section 2.1.9 of the ContactCard's "uid" property (as defined in Section 2.1.9 of
[RFC9553]). However there MUST NOT be more than one ContactCard [RFC9553]). However, there MUST NOT be more than one ContactCard
with the same "uid" in an Account. with the same uid in an Account.
* *addressBookIds*: Id[Boolean]
The set of AddressBook ids this ContactCard belongs to. A card *addressBookIds*: Id[Boolean]
MUST belong to at least one AddressBook at all times (until it is The set of AddressBook ids that this ContactCard belongs to. A
destroyed). The set is represented as an object, with each key card MUST belong to at least one AddressBook at all times (until
being an AddressBook id. The value for each key in the object it is destroyed). The set is represented as an object, with each
key being an AddressBook id. The value for each key in the object
MUST be true. MUST be true.
For any Media object in the card (see Section 2.6.4 of [RFC9553]), a For any Media object in the card (see Section 2.6.4 of [RFC9553]), a
new property is defined: new property is defined:
* *blobId*: Id *blobId*: Id
An id for the Blob representing the binary contents of the An id for the Blob representing the binary contents of the
resource. resource.
When returning ContactCards, any Media with a URI that uses the data When returning ContactCards, any Media with a URI that uses the
URL scheme ([RFC2397]) SHOULD return a blobId property and omit the "data:" URL scheme [RFC2397] SHOULD return a "blobId" property and
uri property, as this lets clients load the (potentially large) image omit the "uri" property, as this lets clients load the (potentially
file only when needed, and avoids the overhead of Base64 encoding. large) image file only when needed and avoids the overhead of Base64
The "mediaType" property MUST also be set. Similarly, when creating encoding. The "mediaType" property MUST also be set. Similarly,
or updating a ContactCard, clients MAY send a blobId instead of the when creating or updating a ContactCard, clients MAY send a "blobId"
uri property for a Media object. instead of the "uri" property for a Media object.
A contact card with a "kind" property equal to "group" represents a A contact card with a "kind" property equal to "group" represents a
group of contacts. Clients often present these separately from other group of contacts. Clients often present these separately from other
contact cards. The "members" property, as defined in Section 2.1.6 contact cards. The "members" property, as defined in Section 2.1.6
of [RFC9553], contains a set of UIDs (as defined in Section 2.1.9 of of [RFC9553], contains a set of uids (as defined in Section 2.1.9 of
[RFC9553]) for other contacts that are the members of this group. [RFC9553]) for other contacts that are the members of this group.
Clients should consider the group to contain any ContactCard with a Clients should consider the group to contain any ContactCard with a
matching UID, from any account they have access to with support for matching uid from any account they have access to that has support
the urn:ietf:params:jmap:contacts capability. UIDs that cannot be for the urn:ietf:params:jmap:contacts capability. Any uid that
found SHOULD be ignored but preserved. For example, suppose a user cannot be found SHOULD be ignored but preserved. For example,
adds contacts from a shared address book to their private group, then suppose a user adds contacts from a shared address book to their
temporarily loses access to this address book. The UIDs cannot be private group, then temporarily loses access to this address book.
resolved so the contacts will disappear from the group. However, if The uids cannot be resolved, so the contacts will disappear from the
they are given permission to access the data again the UIDs will be group. However, if they are given permission to access the data
found and the contacts will reappear. again, the uids will be found and the contacts will reappear.
3.1. ContactCard/get 3.1. ContactCard/get
This is a standard "/get" method as described in [RFC8620], This is a standard "/get" method as described in Section 5.1 of
Section 5.1. [RFC8620].
3.2. ContactCard/changes 3.2. ContactCard/changes
This is a standard "/changes" method as described in [RFC8620], This is a standard "/changes" method as described in Section 5.2 of
Section 5.2. [RFC8620].
3.3. ContactCard/query 3.3. ContactCard/query
This is a standard "/query" method as described in [RFC8620], This is a standard "/query" method as described in Section 5.5 of
Section 5.5. [RFC8620].
3.3.1. Filtering 3.3.1. Filtering
A *FilterCondition* object has the following properties, any of which A *FilterCondition* object has the following properties, any of which
may be omitted: may be omitted:
* *inAddressBook*: Id *inAddressBook*: Id
An AddressBook id. A card must be in this address book to match An AddressBook id. A card must be in this address book to match
the condition. the condition.
* *uid*: String
*uid*: String
A card must have this string exactly as its uid (as defined in A card must have this string exactly as its uid (as defined in
Section 2.1.9 of [RFC9553]) to match. Section 2.1.9 of [RFC9553]) to match.
* *hasMember*: String
*hasMember*: String
A card must have a "members" property (as defined in Section 2.1.6 A card must have a "members" property (as defined in Section 2.1.6
of [RFC9553]) that contains this string as one of the uids in the of [RFC9553]) that contains this string as one of the uids in the
set to match. set to match.
* *kind*: String
A card must have a kind property (as defined in Section 2.1.4 of *kind*: String
A card must have a "kind" property (as defined in Section 2.1.4 of
[RFC9553]) that equals this string exactly to match. [RFC9553]) that equals this string exactly to match.
* *createdBefore*: UTCDate
*createdBefore*: UTCDate
The "created" date-time of the ContactCard (as defined in The "created" date-time of the ContactCard (as defined in
Section 2.1.3 of [RFC9553]) must be before this date-time to match Section 2.1.3 of [RFC9553]) must be before this date-time to match
the condition. the condition.
* *createdAfter*: UTCDate
*createdAfter*: UTCDate
The "created" date-time of the ContactCard (as defined in The "created" date-time of the ContactCard (as defined in
Section 2.1.3 of [RFC9553]) must be the same or after this date- Section 2.1.3 of [RFC9553]) must be the same or after this date-
time to match the condition. time to match the condition.
* *updatedBefore*: UTCDate
*updatedBefore*: UTCDate
The "updated" date-time of the ContactCard (as defined in The "updated" date-time of the ContactCard (as defined in
Section 2.1.10 of [RFC9553]) must be before this date-time to Section 2.1.10 of [RFC9553]) must be before this date-time to
match the condition. match the condition.
* *updatedAfter*: UTCDate
*updatedAfter*: UTCDate
The "updated" date-time of the ContactCard (as defined in The "updated" date-time of the ContactCard (as defined in
Section 2.1.10 of [RFC9553]) must be the same or after this date- Section 2.1.10 of [RFC9553]) must be the same or after this date-
time to match the condition. time to match the condition.
* *text*: String
*text*: String
A card matches this condition if the text matches with text in the A card matches this condition if the text matches with text in the
card. card.
* *name*: String
*name*: String
A card matches this condition if the value of any NameComponent in A card matches this condition if the value of any NameComponent in
the "name" property, or the "full" property in the "name" property the "name" property or the "full" property in the "name" property
of the card, (as defined in Section 2.2.1.2 of [RFC9553]) matches of the card (as defined in Section 2.2.1.2 of [RFC9553]) matches
the value. the value.
* *name/given*: String
*name/given*: String
A card matches this condition if the value of a NameComponent with A card matches this condition if the value of a NameComponent with
kind "given" inside the "name" property of the card (as defined in kind "given" inside the "name" property of the card (as defined in
Section 2.2.1.2 of [RFC9553]) matches the value. Section 2.2.1.2 of [RFC9553]) matches the value.
* *name/surname*: String
*name/surname*: String
A card matches this condition if the value of a NameComponent with A card matches this condition if the value of a NameComponent with
kind "surname" inside the "name" property of the card (as defined kind "surname" inside the "name" property of the card (as defined
in Section 2.2.1.2 of [RFC9553]) matches the value. in Section 2.2.1.2 of [RFC9553]) matches the value.
* *name/surname2*: String
*name/surname2*: String
A card matches this condition if the value of a NameComponent with A card matches this condition if the value of a NameComponent with
kind "surname2" inside the "name" property of the card (as defined kind "surname2" inside the "name" property of the card (as defined
in Section 2.2.1.2 of [RFC9553]) matches the value. in Section 2.2.1.2 of [RFC9553]) matches the value.
* *nickname*: String
*nickname*: String
A card matches this condition if the "name" of any Nickname in the A card matches this condition if the "name" of any Nickname in the
"nicknames" property of the card (as defined in Section 2.2.2 of "nicknames" property of the card (as defined in Section 2.2.2 of
[RFC9553]) matches the value. [RFC9553]) matches the value.
* *organization*: String
*organization*: String
A card matches this condition if the "name" of any Organization in A card matches this condition if the "name" of any Organization in
the "organizations" property of the card (as defined in the "organizations" property of the card (as defined in
Section 2.2.3 of [RFC9553]) matches the value. Section 2.2.3 of [RFC9553]) matches the value.
* *email*: String
*email*: String
A card matches this condition if the "address" or "label" of any A card matches this condition if the "address" or "label" of any
EmailAddress in the "emails" property of the card (as defined in EmailAddress in the "emails" property of the card (as defined in
Section 2.3.1 of [RFC9553]) matches the value. Section 2.3.1 of [RFC9553]) matches the value.
* *phone*: String
*phone*: String
A card matches this condition if the "number" or "label" of any A card matches this condition if the "number" or "label" of any
Phone in the "phones" property of the card (as defined in Phone in the "phones" property of the card (as defined in
Section 2.3.3 of [RFC9553]) matches the value. Section 2.3.3 of [RFC9553]) matches the value.
* *onlineService*: String
*onlineService*: String
A card matches this condition if the "service", "uri", "user", or A card matches this condition if the "service", "uri", "user", or
"label" of any OnlineService in the "onlineServices" property of "label" of any OnlineService in the "onlineServices" property of
the card (as defined in Section 2.3.2 of [RFC9553]) matches the the card (as defined in Section 2.3.2 of [RFC9553]) matches the
value. value.
* *address*: String
*address*: String
A card matches this condition if the value of any AddressComponent A card matches this condition if the value of any AddressComponent
in the "addresses" property, or the "full" property in the in the "addresses" property or the "full" property in the
"addresses" property of the card, (as defined in Section 2.5.1 of "addresses" property of the card (as defined in Section 2.5.1 of
[RFC9553]) matches the value. [RFC9553]) matches the value.
* *note*: String
*note*: String
A card matches this condition if the "note" of any Note in the A card matches this condition if the "note" of any Note in the
"notes" property of the card (as defined in Section 2.8.3 of "notes" property of the card (as defined in Section 2.8.3 of
[RFC9553]) matches the value. [RFC9553]) matches the value.
If zero properties are specified on the FilterCondition, the If zero properties are specified on the FilterCondition, the
condition MUST always evaluate to true. If multiple properties are condition MUST always evaluate to true. If multiple properties are
specified, ALL must apply for the condition to be true (it is specified, ALL must apply for the condition to be true (it is
equivalent to splitting the object into one-property conditions and equivalent to splitting the object into one-property conditions and
making them all the child of an AND filter operator). making them all the child of an AND filter operator).
The exact semantics for matching String fields is *deliberately not The exact semantics for matching String fields is deliberately not
defined* to allow for flexibility in indexing implementation, subject defined to allow for flexibility in indexing implementation, subject
to the following: to the following:
* Text SHOULD be matched in a case-insensitive manner. * Text SHOULD be matched in a case-insensitive manner.
* Text contained in either (but matched) single or double quotes * Text contained in either (but matched) single or double quotes
SHOULD be treated as a *phrase search*, that is a match is SHOULD be treated as a phrase search. That is, a match is
required for that exact sequence of words, excluding the required for that exact sequence of words, excluding the
surrounding quotation marks. Use \", \' and \\ to match a literal surrounding quotation marks. Use \", \', and \\ to match a
", ' and \ respectively in a phrase. literal ", ', and \ respectively in a phrase.
* Outside of a phrase, white-space SHOULD be treated as dividing * Outside of a phrase, whitespace SHOULD be treated as dividing
separate tokens that may be searched for separately in the separate tokens that may be searched for separately in the
contact, but MUST all be present for the contact to match the contact, but MUST all be present for the contact to match the
filter. filter.
* Tokens MAY be matched on a whole-word basis using stemming (so for
example a text search for bus would match "buses" but not * Tokens MAY be matched on a whole-word basis using stemming (e.g.,
"business"). a text search for bus would match "buses", but not "business").
3.3.2. Sorting 3.3.2. Sorting
The following value for the "property" field on the Comparator object The following values for the "property" field on the Comparator
MUST be supported for sorting: object MUST be supported for sorting:
* "created" - The "created" date on the ContactCard. * "created" - The "created" date on the ContactCard.
* "updated" - The "updated" date on the ContactCard. * "updated" - The "updated" date on the ContactCard.
The following values for the "property" field on the Comparator The following values for the "property" field on the Comparator
object SHOULD be supported for sorting: object SHOULD be supported for sorting:
* "name/given" - The value of the first NameComponent in the "name" * "name/given" - The value of the first NameComponent in the "name"
property whose "kind" is "given". property whose "kind" is "given".
* "name/surname" - The value of the first NameComponent in the * "name/surname" - The value of the first NameComponent in the
"name" property whose "kind" is "surname". "name" property whose "kind" is "surname".
* "name/surname2" - The value of the first NameComponent in the * "name/surname2" - The value of the first NameComponent in the
"name" property whose "kind" is "surname2". "name" property whose "kind" is "surname2".
3.4. ContactCard/queryChanges 3.4. ContactCard/queryChanges
This is a standard "/queryChanges" method as described in [RFC8620], This is a standard "/queryChanges" method as described in Section 5.6
Section 5.6. of [RFC8620].
3.5. ContactCard/set 3.5. ContactCard/set
This is a standard "/set" method as described in [RFC8620], This is a standard "/set" method as described in Section 5.3 of
Section 5.3. [RFC8620].
To set a new photo, the file must first be uploaded using the upload To set a new photo, the file must first be uploaded using the upload
mechanism as described in [RFC8620], Section 6.1. This will give the mechanism as described in Section 6.1 of [RFC8620]. This will give
client a valid blobId/size/type to use. The server MUST reject the client a valid blobId, size, and type to use. The server MUST
attempts to set a file that is not a recognised image type as the reject attempts to set a file that is not a recognised image type as
photo for a card. the photo for a card.
3.6. ContactCard/copy 3.6. ContactCard/copy
This is a standard "/copy" method as described in [RFC8620], This is a standard "/copy" method as described in Section 5.4 of
Section 5.4. [RFC8620].
4. Examples 4. Examples
For brevity, in the following examples only the "methodCalls" For brevity, only the "methodCalls" property of the Request object
property of the Request object, and the "methodResponses" property of and the "methodResponses" property of the Response object is shown in
the Response object is shown. the following examples.
4.1. Fetching initial data 4.1. Fetching Initial Data
A user has authenticated and the client has fetched the JMAP Session A user has authenticated and the client has fetched the JMAP Session
object. It finds a single Account with the object. It finds a single Account with the
"urn:ietf:params:jmap:contacts" capability, with id "a0x9", and wants "urn:ietf:params:jmap:contacts" capability with id "a0x9" and wants
to fetch all the address books and contacts. It might make the to fetch all the address books and contacts. It might make the
following request: following request:
[ [
["AddressBook/get", { ["AddressBook/get", {
"accountId": "a0x9" "accountId": "a0x9"
}, "0"], }, "0"],
["ContactCard/get", { ["ContactCard/get", {
"accountId": "a0x9" "accountId": "a0x9"
}, "1"] }, "1"]
] ]
Figure 1: "methodCalls" Property of a JMAP Request
The server might respond with something like: The server might respond with something like:
[ [
["AddressBook/get", { ["AddressBook/get", {
"accountId": "a0x9", "accountId": "a0x9",
"list": [{ "list": [{
"id": "062adcfa-105d-455c-bc60-6db68b69c3f3", "id": "062adcfa-105d-455c-bc60-6db68b69c3f3",
"name": "Personal", "name": "Personal",
"description": null, "description": null,
"sortOrder": 0, "sortOrder": 0,
"isDefault": true, "isDefault": true,
"isSubscribed": true, "isSubscribed": true,
"shareWith": { "shareWith": {
"3f1502e0-63fe-4335-9ff3-e739c188f5dd": { "3f1502e0-63fe-4335-9ff3-e739c188f5dd": {
"mayRead": true,
"mayWrite": false,
"mayShare": false,
"mayDelete": false
}
},
"myRights": {
"mayRead": true,
"mayWrite": true,
"mayShare": true,
"mayDelete": false
}
}, {
"id": "cd40089d-35f9-4fd7-980b-ba3a9f1d74fe",
"name": "Autosaved",
"description": null,
"sortOrder": 1,
"isDefault": false,
"isSubscribed": true,
"shareWith": null,
"myRights": {
"mayRead": true, "mayRead": true,
"mayWrite": true, "mayWrite": false,
"mayShare": true, "mayShare": false,
"mayDelete": false "mayDelete": false
} }
}], },
"notFound": [], "myRights": {
"state": "~4144" "mayRead": true,
"mayWrite": true,
"mayShare": true,
"mayDelete": false
}
}, {
"id": "cd40089d-35f9-4fd7-980b-ba3a9f1d74fe",
"name": "Autosaved",
"description": null,
"sortOrder": 1,
"isDefault": false,
"isSubscribed": true,
"shareWith": null,
"myRights": {
"mayRead": true,
"mayWrite": true,
"mayShare": true,
"mayDelete": false
}
}],
"notFound": [],
"state": "~4144"
}, "0"], }, "0"],
["Contact/get", { ["ContactCard/get", {
"accountId": "a0x9", "accountId": "a0x9",
"list": [{ "list": [{
"id": "3", "id": "3",
"addressBookIds": { "addressBookIds": {
"062adcfa-105d-455c-bc60-6db68b69c3f3": true "062adcfa-105d-455c-bc60-6db68b69c3f3": true
}, },
"name": { "name": {
"components": [ "components": [
{ "kind": "given", "value": "Joe" }, { "kind": "given", "value": "Joe" },
{ "kind": "surname", "value": "Bloggs" } { "kind": "surname", "value": "Bloggs" }
], ],
"isOrdered": true "isOrdered": true
}, },
"emails": { "emails": {
"0": { "0": {
"contexts": { "contexts": {
"private": true "private": true
}, },
"address": "joe.bloggs@example.com" "address": "joe.bloggs@example.com"
}
} }
}], }
"notFound": [], }],
"state": "ewarbckaqJ::112" "notFound": [],
"state": "ewarbckaqJ::112"
}, "1"] }, "1"]
] ]
4.2. Changing the default address book Figure 2: "methodResponses" Property of a JMAP Response
4.2. Changing the Default Address Book
The client tries to change the default address book from "Personal" The client tries to change the default address book from "Personal"
to "Autosaved" (and makes no other change): to "Autosaved" (and makes no other change):
[ [
["AddressBook/set", { ["AddressBook/set", {
"accountId": "a0x9", "accountId": "a0x9",
"onSuccessSetIsDefault": "cd40089d-35f9-4fd7-980b-ba3a9f1d74fe" "onSuccessSetIsDefault": "cd40089d-35f9-4fd7-980b-ba3a9f1d74fe"
}, "0"] }, "0"]
] ]
Figure 3: "methodCalls" Property of a JMAP Request
The server allows the change, returning the following response: The server allows the change, returning the following response:
[ [
["AddressBook/set", { ["AddressBook/set", {
"accountId": "a0x9", "accountId": "a0x9",
"updated": { "updated": {
"cd40089d-35f9-4fd7-980b-ba3a9f1d74fe": { "cd40089d-35f9-4fd7-980b-ba3a9f1d74fe": {
"isDefault": true "isDefault": true
}, },
"062adcfa-105d-455c-bc60-6db68b69c3f3": { "062adcfa-105d-455c-bc60-6db68b69c3f3": {
"isDefault": false "isDefault": false
} },
"oldState": "~4144",
"newState": "~4148"
} }
}, "0"] }, "0"]
] ]
Figure 4: "methodResponses" Property of a JMAP Response
5. Internationalisation Considerations 5. Internationalisation Considerations
Experience has shown that unrestricted use of Unicode can lead to Experience has shown that unrestricted use of Unicode can lead to
problems such as inconsistent rendering, users reading text and problems such as inconsistent rendering, users reading text and
interpreting it differently than intended, and unexpected results interpreting it differently than intended, and unexpected results
when copying text from one location to another. Servers MAY choose when copying text from one location to another. Servers MAY choose
to mitigate this by restricting the set of characters allowed in to mitigate this by restricting the set of characters allowed in
otherwise unconstrained String fields. The FreeformClass, as otherwise unconstrained String fields. The FreeformClass, as
documented in [RFC8264], Section 4.3 might be a good starting point documented in Section 4.3 of [RFC8264], might be a good starting
for this. point for this.
Attempts to set a value containing code points outside of the Attempts to set a value containing code points outside of the
permissible set can be handled in a few ways by the server. The permissible set can be handled in a few ways by the server. The
server could choose to strip the forbidden characters, or replace server could choose to strip the forbidden characters or replace them
them with U+FFFD (the Unicode replacement character), and store the with U+FFFD (the Unicode replacement character) and store the
resulting string. This is likely to be appropriate for non-printable resulting string. This is likely to be appropriate for non-printable
characters such as the "Control Codes" defined in [UNICODE] characters -- such as the "Control Codes" defined in Section 23.1
Section 23.1, excluding newline (U+000A), carriage return (U+000D), (https://www.unicode.org/versions/latest/core-spec/chapter-
and tab (U+0009) — which can end up in data accidentally due to copy- 23/#G20365) of [UNICODE], excluding newline (U+000A), carriage return
and-paste issues, but are invisible to the end user. JMAP allows the (U+000D), and tab (U+0009) -- that can end up in data accidentally
server to transform data on create/update, as long as any changed due to copy-and-paste issues but are invisible to the end user. JMAP
properties are returned to the client in the /set response, so it allows the server to transform data on create/update as long as any
knows what has changed, as per [RFC8620], Section 5.3. changed properties are returned to the client in the "/set" response
so it knows what has changed, as per Section 5.3 of [RFC8620].
Alternatively, the server MAY just reject the create/update with an Alternatively, the server MAY just reject the create/update with an
invalidProperties SetError. "invalidProperties" SetError.
6. Security Considerations 6. Security Considerations
All security considerations of JMAP ([RFC8620]) apply to this All security considerations of JMAP [RFC8620] apply to this
specification. Additional considerations specific to the data types specification. Additional considerations specific to the data types
and functionality introduced by this document are described in the and functionality introduced by this document are described in the
following subsection. following subsection.
Contacts consist almost entirely of private, personally identifiable Contacts consist almost entirely of private, personally identifiable
information, and represent the social connections of users. Privacy information, and represent the social connections of users. Privacy
leaks can have real world consequences, and contacts servers and leaks can have real world consequences, and contact servers and
clients MUST be mindful of the need to keep all data secure. clients MUST be mindful of the need to keep all data secure.
Servers MUST enforce the ACLs set on address books to ensure only Servers MUST enforce the Access Control Lists (ACLs) set on address
authorised data is shared. books to ensure only authorised data is shared.
7. IANA Considerations 7. IANA Considerations
7.1. JMAP capability registration for "contacts" 7.1. JMAP Capability Registration for "contacts"
IANA will register "contacts" in the "JMAP Capabilities" registry as IANA has registered "contacts" in the "JMAP Capabilities" registry as
follows: follows:
Capability Name: urn:ietf:params:jmap:contacts Capability Name: urn:ietf:params:jmap:contacts
Intended Use: common
Specification document: this document Change Controller: IETF
Security and Privacy Considerations: this document, Section 6
Intended use: common Reference: this document
Change Controller: IETF
Security and privacy considerations: this document, Section 6
7.2. JMAP Data Type Registration for "AddressBook" 7.2. JMAP Data Type Registration for "AddressBook"
IANA will register "AddressBook" in the "JMAP Data Types" registry as IANA has registered "AddressBook" in the "JMAP Data Types" registry
follows: as follows:
Type Name: AddressBook
Can reference blobs: no
Can Use for State Change: yes
Capability: urn:ietf:params:jmap:contacts
Specification document: this document Type Name: AddressBook
Can Reference Blobs: No
Can Use for State Change: Yes
Capability: urn:ietf:params:jmap:contacts
Reference: this document
7.3. JMAP Data Type Registration for "ContactCard" 7.3. JMAP Data Type Registration for "ContactCard"
IANA will register "ContactCard" in the "JMAP Data Types" registry as IANA has registered "ContactCard" in the "JMAP Data Types" registry
follows: as follows:
Type Name: ContactCard
Can reference blobs: yes
Can Use for State Change: yes
Capability: urn:ietf:params:jmap:contacts
Specification document: this document Type Name: ContactCard
Can Reference Blobs: Yes
Can Use for State Change: Yes
Capability: urn:ietf:params:jmap:contacts
Reference: this document
7.4. JMAP Error Codes Registry 7.4. JMAP Error Codes Registry
The following subsection registers a new error code in the "JMAP The following subsection has registered a new error code in the "JMAP
Error Codes" registry, as defined in Section 9 of [RFC8620]. Error Codes" registry, as defined in Section 9 of [RFC8620].
7.4.1. addressBookHasContents 7.4.1. addressBookHasContents
JMAP Error Code: addressBookHasContents JMAP Error Code: addressBookHasContents
Intended Use: common
Intended use: common Change Controller: IETF
Description: The AddressBook has at least one ContactCard assigned
Change controller: IETF to it, and the "onDestroyRemoveContents" argument was false.
Reference: This document, Section 2.3
Reference: This document, Section 2.3
Description: The AddressBook has at least one ContactCard assigned to
it, and the "onDestroyRemoveContents" argument was false.
7.5. JSContact Property Registrations 7.5. JSContact Property Registrations
IANA will register the following additional properties in the IANA has registered the following additional properties in the
JSContact Properties Registry, as defined in Section 3 of [RFC9553]. "JSContact Properties" registry, as defined in Section 3 of
[RFC9553].
7.5.1. id 7.5.1. id
Property Name: id Property Name: id
Property Type: not applicable
Property Type: Not applicable Property Context: Card
Property Context: Card Intended Usage: reserved
Since Version: 1.0
Intended Use: Reserved Change Controller: IETF
Reference: this document
Since Version: 1.0
Change Controller: IETF
7.5.2. addressBookIds 7.5.2. addressBookIds
Property Name: addressBookIds Property Name: addressBookIds
Property Type: not applicable
Property Type: Not applicable Property Context: Card
Intended Usage: reserved
Property Context: Card Since Version: 1.0
Change Controller: IETF
Intended Use: Reserved Reference: this document
Since Version: 1.0
Change Controller: IETF
7.5.3. blobId 7.5.3. blobId
Property Name: blobId Property Name: blobId
Property Type: not applicable
Property Type: Not applicable Property Context: Media
Intended Usage: reserved
Property Context: Media Since Version: 1.0
Change Controller: IETF
Intended Use: Reserved Reference: this document
Since Version: 1.0
Change Controller: IETF 8. References
8. Normative References 8.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997, DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>. <https://www.rfc-editor.org/info/rfc2119>.
[RFC2397] Masinter, L., "The "data" URL scheme", RFC 2397, [RFC2397] Masinter, L., "The "data" URL scheme", RFC 2397,
DOI 10.17487/RFC2397, August 1998, DOI 10.17487/RFC2397, August 1998,
<https://www.rfc-editor.org/info/rfc2397>. <https://www.rfc-editor.org/info/rfc2397>.
skipping to change at page 18, line 18 skipping to change at line 817
[RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application [RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application
Protocol (JMAP)", RFC 8620, DOI 10.17487/RFC8620, July Protocol (JMAP)", RFC 8620, DOI 10.17487/RFC8620, July
2019, <https://www.rfc-editor.org/info/rfc8620>. 2019, <https://www.rfc-editor.org/info/rfc8620>.
[RFC9553] Stepanek, R. and M. Loffredo, "JSContact: A JSON [RFC9553] Stepanek, R. and M. Loffredo, "JSContact: A JSON
Representation of Contact Data", RFC 9553, Representation of Contact Data", RFC 9553,
DOI 10.17487/RFC9553, May 2024, DOI 10.17487/RFC9553, May 2024,
<https://www.rfc-editor.org/info/rfc9553>. <https://www.rfc-editor.org/info/rfc9553>.
[I-D.ietf-jmap-sharing] [RFC9670] Jenkins, N., Ed., "JSON Meta Application Protocol (JMAP)
Jenkins, N., "JMAP Sharing", Work in Progress, Internet- Sharing", RFC 9670, DOI 10.17487/RFC9670, November 2024,
Draft, draft-ietf-jmap-sharing-09, 17 April 2024, <https://www.rfc-editor.org/info/rfc9670>.
<https://datatracker.ietf.org/doc/html/draft-ietf-jmap-
sharing-09>.
9. Informative References 8.2. Informative References
[RFC8264] Saint-Andre, P. and M. Blanchet, "PRECIS Framework: [RFC8264] Saint-Andre, P. and M. Blanchet, "PRECIS Framework:
Preparation, Enforcement, and Comparison of Preparation, Enforcement, and Comparison of
Internationalized Strings in Application Protocols", Internationalized Strings in Application Protocols",
RFC 8264, DOI 10.17487/RFC8264, October 2017, RFC 8264, DOI 10.17487/RFC8264, October 2017,
<https://www.rfc-editor.org/info/rfc8264>. <https://www.rfc-editor.org/info/rfc8264>.
[UNICODE] The Unicode Consortium, "The Unicode Standard", [UNICODE] The Unicode Consortium, "The Unicode Standard",
<http://www.unicode.org/versions/latest/>. Note that this <https://www.unicode.org/versions/latest/>.
reference is to the latest version of Unicode, rather than
to a specific release. It is not expected that future
changes in the Unicode Standard will affect the referenced
definitions.
Author's Address Author's Address
Neil Jenkins (editor) Neil Jenkins (editor)
Fastmail Fastmail
PO Box 234, Collins St West PO Box 234, Collins St West
Melbourne VIC 8007 Melbourne VIC 8007
Australia Australia
Email: neilj@fastmailteam.com Email: neilj@fastmailteam.com
URI: https://www.fastmail.com URI: https://www.fastmail.com
 End of changes. 136 change blocks. 
405 lines changed or deleted 399 lines changed or added

This html diff was produced by rfcdiff 1.48.