<?xml version="1.0" encoding="utf-8"?>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc version="3" ipr="trust200902" docName="draft-baum-jmap-portability-00" submissionType="IETF" category="info" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude" indexInclude="true" consensus="true">

<front>
<title abbrev="JMAP Portability">JMAP for Migration and Data Portability</title><seriesInfo value="draft-baum-jmap-portability-00" stream="IETF" status="informational" name="Internet-Draft"></seriesInfo>
<author role="editor" initials="J.M." surname="Baum" fullname="Joris Baum"><organization>audriga</organization><address><postal><street>Alter Schlachthof 57</street>
<city>Karlsruhe </city>
<code>76137</code>
<country>Germany</country>
</postal><email>joris@audriga.com</email>
<uri>https://www.audriga.com</uri>
</address></author><author role="editor" initials="H.J." surname="Happel" fullname="Hans-Joerg"><organization>audriga</organization><address><postal><street>Alter Schlachthof 57</street>
<city>Karlsruhe </city>
<code>76137</code>
<country>Germany</country>
</postal><email>hans-joerg@audriga.com</email>
<uri>https://www.audriga.com</uri>
</address></author><date year="2023" month="March" day="7"></date>
<area>Applications</area>
<workgroup>JMAP</workgroup>
<keyword>jmap</keyword>
<keyword>data portability</keyword>
<keyword>migration</keyword>

<abstract>
<t>The JMAP base protocol (RFC8620) is a generic, efficient, mobile friendly and scalable protocol that can be used for data of any type. This makes it a good fit for migrations or data portability use cases. However, due to its large set of features, it is also quite complex, which makes it difficult to explore new application domains in practice. The goal of this document is to provide a simplified version of JMAP for more rapid development.</t>
</abstract>

</front>

<middle>

<section anchor="introduction"><name>Introduction</name>
<t>JMAP <xref target="RFC8620"></xref> is designed to be a generic, efficient, mobile friendly and scalable protocol. This comes with the cost of high complexity, even though this is necessary to meet JMAP's design goals.</t>
<t>Migration and data portability is about moving arbitrary user data between services. JMAP is a particularly good fit for meeting basic data portability requirements. It can be used as an open protocol in front of an application service, exposing data of any kind. However, implementing JMAP correctly can be complicated, which makes it difficult to explore new application domains in practice.</t>
<t>For basic data portability requirements, users need to be able to export their data from a product or import it into a product in real time. Providers that want to support JMAP for their service to meet data portability requirements are likely to not want to implement the full feature set that JMAP Core currently defines. Currently, there is no clear guidance on which parts of the JMAP specification are essential to migration and data portablity use cases.</t>
<t>This specification aims to provide guidance to identify essential parts of the JMAP spec for more rapid development. For the sole purpose of providing very basic data portability, there is no need to implement all parts of the JMAP protocol. In a second iteration developers could then extend upon this basic version of JMAP. It also defines a simplified version of the JMAP Request that has even less requirements.</t>
</section>

<section anchor="conventions-used-in-this-document"><name>Conventions Used In This Document</name>
<t>The key words &quot;MUST&quot;, &quot;MUST NOT&quot;, &quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL
NOT&quot;, &quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;, &quot;NOT RECOMMENDED&quot;,
&quot;MAY&quot;, and &quot;OPTIONAL&quot; in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"></xref> <xref target="RFC8174"></xref> when, and only when,
they appear in all capitals, as shown here.</t>
<t>The definitions of JSON keys and datatypes in the document follow
the conventions described in the core JMAP specification <xref target="RFC8620"></xref>.</t>
</section>

<section anchor="session-resource"><name>Session Resource</name>
<t>For a lot of basic portability use of cases for existing application services
the following constraints are typically acceptable:</t>

<ul spacing="compact">
<li>A single user login is tied to a single user account (this is then also the primary account).</li>
<li>This implies that shared data shall not be exposed over the API. The API will only provide access to data owned by the current user.</li>
<li>Each user has the same set of capabilities and restrictions (e.g.  <tt>maxMailboxesPerEmail</tt>).</li>
<li><tt>apiUrl</tt>, <tt>downloadUrl</tt>, <tt>uploadUrl</tt> and <tt>eventSourceUrl</tt> are the same for ever user.</li>
</ul>
<t>For use cases adhering to those restrictions, the session resource can be modeled as a simple static JSON file without the username property. The <tt>accountId</tt> is then the same as the <tt>username</tt>.</t>
</section>

<section anchor="structured-data-exchange"><name>Structured Data exchange</name>
<t>While batching improves performance considerably, it imposes additional
implementation effort on developers. It is not essential for portability and can
be left out.</t>
</section>

<section anchor="standard-methods-and-naming-convention"><name>Standard Methods and Naming Convention</name>
<t>JMAP core defines 6 standard methods, which are then reused in most JMAP
extensions. Not all JMAP Methods are required to provide essential portability.
For some use-cases where the data is expected to be small, <strong>/set</strong> and <strong>/get</strong>
should be enough. In case a large amount of
data shall be supported, paging can be achieved via the <strong>/query</strong> method. Note
that some specifications require specific IDs for /set .</t>
<t><strong>/changes</strong>, <strong>/copy</strong> as well as <strong>/queryChanges</strong> are not required as all
data can already be retrieved and set with above's three methods.</t>
</section>

<section anchor="binary-data"><name>Binary Data</name>
<t>The advanced Blob/copy method call is not essential.</t>
</section>

<section anchor="simplified-rest-like-jmap-api"><name>Simplified REST-like JMAP API</name>
<t>Structured data exchange over JMAP usually involves processing JMAP Request JSON payloads. This might impose unnecessary requirements for certain use cases of JMAP. Likely scenarios in which this is beneficiary are situations in which portability needs to be provided due to regulatory requirements or when migrating user data away from legacy platforms.</t>
<t>For rapid development of a JMAP API without
support for batching, the essential properties of the Request object can instead
be implemented as URI with query parameters.</t>

<ul spacing="compact">
<li><strong>apiUrlSimple</strong>: <tt>String</tt> The URL to use for JMAP API requests. THE URL MUST
contain <tt>accountId</tt> and <tt>methodCall</tt>. One MAY use <tt>ids</tt>.</li>
</ul>

<section anchor="addition-to-the-capabilities-object"><name>Addition to the capabilities object</name>
<t>The capabilities object is returned as part of the JMAP Session object;
see <xref target="RFC8620"></xref>, Section 2. This document defines one additional capability URI.</t>

<section anchor="urn-ietf-params-jmap-core-simple"><name>urn:ietf:params:jmap:core-simple</name>
<t>The capability <tt>urn:ietf:params:jmap:core-simple</tt> being present in the &quot;capabilities&quot; property represents support for the simplified JMAP API.</t>
<t>The value of this property in the JMAP Session capabilities property and the
account’s accountCapabilities property is an empty object.</t>
</section>

<section anchor="capability-example"><name>Capability Example</name>

<artwork>{
  ...
  &quot;capabilities&quot;: {
    ...,
    &quot;urn:ietf:params:jmap:core-simple&quot;: {}
  },
  &quot;apiUrlSimple&quot;: &quot;https://jmap.me/api
    /?accountId=&lt;account-id&gt;&amp;methodCall=&lt;methodCall&gt;&amp;ids=&lt;ids&gt;&quot;
}
</artwork>
</section>
</section>
</section>

<section anchor="security-considerations"><name>Security considerations</name>
<t>All security considerations of JMAP <xref target="RFC8620"></xref> apply to this specification.</t>
</section>

<section anchor="iana-considerations"><name>IANA considerations</name>

<section anchor="jmap-capability-registration-for-core-simple"><name>JMAP Capability registration for &quot;core-simple&quot;</name>
<t>IANA is requested to register the &quot;core-simple&quot; JMAP Capability as follows:</t>
<t>Capability Name: urn:ietf:params:jmap:core-simple</t>
<t>Specification document: this document</t>
<t>Intended use: common</t>
<t>Change Controller: IETF</t>
<t>Security and privacy considerations: this document, Section XXX</t>
</section>
</section>

<section anchor="acknowledgements"><name>Acknowledgements</name>
<t>Bron Gondwana, Neil Jenkins, Alexey Melnikov, Ken Murchison, Robert Stepanek and
the JMAP working group at the IETF.</t>
</section>

</middle>

<back>
<references><name>Normative References</name>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8620.xml"/>
</references>

<section anchor="required-features-for-jmap-portability"><name>Required features for JMAP Portability</name>
<t>Not all features of JMAP Core are required for basic data portability use cases. Tables 1-4 list the required features for a minimal implementation of JMAP for Migration and Portability in more detail. It distinguishes between two common scenarios:</t>

<ul spacing="compact">
<li>Export use cases: Minimal implementation for exporting data from an application server</li>
<li>Import use cases: Minimal implementation for importing data into an application server</li>
</ul>
<t>The last column lists more advanced features of JMAP Core recommended for data portability use cases.</t>
<table><name>Session Object features essential for Migration and Portability use cases
</name>
<thead>
<tr>
<th>JMAP Core Feature</th>
<th>JMAP Portability export use cases</th>
<th>JMAP Portability import use cases</th>
<th>JMAP Portability advanced features</th>
</tr>
</thead>

<tbody>
<tr>
<td>Session Object (static file)</td>
<td>(yes)<sup>1</sup></td>
<td>(yes)<sup>1</sup></td>
<td></td>
</tr>

<tr>
<td>Session Object (full)</td>
<td>some use cases<sup>1</sup></td>
<td>some use cases<sup>1</sup></td>
<td></td>
</tr>

<tr>
<td>Service Autodiscovery</td>
<td>-</td>
<td>-</td>
<td>good for simple connection</td>
</tr>
</tbody>
</table><table><name>Structured Data Exchange features essential for Migration and Portability use cases
</name>
<thead>
<tr>
<th>JMAP Core Feature</th>
<th>JMAP Portability export use cases</th>
<th>JMAP Portability import use cases</th>
<th>JMAP Portability advanced features</th>
</tr>
</thead>

<tbody>
<tr>
<td>Invocation (all properties)</td>
<td>yes</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>Request (using)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Request (methodCalls, no batching)</td>
<td>yes</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>Request (methodCalls, with batching)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Request (createdIds)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Response (methodResponses)</td>
<td>yes</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>Response (createdIds)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Response (sessionState)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Errors</td>
<td>-</td>
<td>-</td>
<td>good for debugging</td>
</tr>

<tr>
<td>References to Previous Method Results</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Localisation of User-Visible String</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>
</tbody>
</table><table><name>Method features essential for Migration and Portability
</name>
<thead>
<tr>
<th>JMAP Core Feature</th>
<th>JMAP Portability export use cases</th>
<th>JMAP Portability import use cases</th>
<th>JMAP Portability advanced features</th>
</tr>
</thead>

<tbody>
<tr>
<td>Core/echo</td>
<td>-</td>
<td>-</td>
<td>good for connection testing</td>
</tr>

<tr>
<td>/get method Request</td>
<td>yes</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Request (accountId)</td>
<td>some use cases<sup>1</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Request (ids, only single id)</td>
<td>for listing or paging<sup>2,3</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Request (ids)</td>
<td>for listing or paging<sup>2,3</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Request (properties)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Response</td>
<td>yes</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Response (accountId)</td>
<td>some use cases<sup>1</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Response (state)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Response (list)</td>
<td>yes</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/get method Response (notFound)</td>
<td>yes</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/changes method (full)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Request</td>
<td>-</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>/set method Request (accountId)</td>
<td>-</td>
<td>some use cases<sup>1</sup></td>
<td></td>
</tr>

<tr>
<td>/set method Request (ifInState)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Request (create, only single id)</td>
<td>-</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>/set method Request (create, multiple ids)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Request (update)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Request (destroy)</td>
<td>-</td>
<td>-</td>
<td>good for testing</td>
</tr>

<tr>
<td>/set method Response</td>
<td>-</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>/set method Response (accountId)</td>
<td>-</td>
<td>some use cases<sup>1</sup></td>
<td></td>
</tr>

<tr>
<td>/set method Response (oldState)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Response (newState)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Response (created)</td>
<td>-</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>/set method Response (updated)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Response (destroyed)</td>
<td>-</td>
<td>-</td>
<td>good for testing</td>
</tr>

<tr>
<td>/set method Response (notCreated)</td>
<td>-</td>
<td>yes</td>
<td></td>
</tr>

<tr>
<td>/set method Response (notUpdated)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/set method Response (notDestroyed)</td>
<td>-</td>
<td>-</td>
<td>good for testing</td>
</tr>

<tr>
<td>/set method SetError</td>
<td>-</td>
<td>-</td>
<td>good for debugging</td>
</tr>

<tr>
<td>/copy method (full)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request</td>
<td>for listing or paging<sup>2,3</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (accountId)</td>
<td>some use cases<sup>1</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (filter)</td>
<td>-</td>
<td>-</td>
<td>good for listing objects of a specific kind</td>
</tr>

<tr>
<td>/query method Request (sort)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (position)</td>
<td>for paging<sup>3</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (anchor)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (anchorOffset)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (limit)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Request (calculateTotal)</td>
<td>for paging<sup>3</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Response</td>
<td>for listing or paging<sup>2,3</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Response (accountId)</td>
<td>some use cases<sup>1</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>/query method Response (queryState)</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method Response (canCalculateChanges)</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method Response (position)</td>
<td>for paging<sup>3</sup></td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method Response (ids)</td>
<td>for listing or paging<sup>2,3</sup></td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method Response (total)</td>
<td>for paging<sup>2,3</sup></td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method Response (limit)</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method FilterCondition</td>
<td>-</td>
<td>-</td>
<td>good for listing objects of a specific kind</td>
</tr>

<tr>
<td>/query method FilterOperator</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/query method Comparator</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>

<tr>
<td>/queryChanges method (full)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>
</tbody>
</table><table><name>Blob and Push features essential for Migration and Portability
</name>
<thead>
<tr>
<th>JMAP Core Feature</th>
<th>JMAP Portability export use cases</th>
<th>JMAP Portability import use cases</th>
<th>JMAP Portability advanced features</th>
</tr>
</thead>

<tbody>
<tr>
<td>Uploading Binary Data</td>
<td>-</td>
<td>for importing attachments<sup>4</sup></td>
<td></td>
</tr>

<tr>
<td>Downloading Binary Data</td>
<td>for exporting attachments<sup>4</sup></td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Blob/copy (full)</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>

<tr>
<td>Push</td>
<td>-</td>
<td>-</td>
<td></td>
</tr>
</tbody>
</table>
<ul spacing="compact">
<li>1: Can be modeled as a static JSON file for a lot of scenarios. Section 3 details for which use cases a static JSON file should be sufficient.</li>
<li>2: Some data types require using ids in /get .</li>
<li>3: maxObjectsInGet might not be sufficiently high in some products. Then /query and paging is required.</li>
<li>4: Some data types allow having attachments as base64 enconded strings inside a JMAP object. In those cases it is not necessary to implement a download or upload endpoint.</li>
</ul>
</section>

<section anchor="jmap-debug-extension"><name>JMAP Debug extension</name>

<section anchor="introduction-1"><name>Introduction</name>
<t>Data exchanges between JMAP clients and server typically produces log lines from
both the client and the server. Usually, logs are either stored locally on the
instances or sent to a dedicated logging server. However, JMAP can also be used
to supply log messages along-side the usual data exchange. This also removes the
need to operate a separate logging infrastructure or have dedicated channels for
log messages.</t>
<t>This extension adds a <tt>logs</tt> property to the JMAP
method response (defined in
<eref target="https://www.rfc-editor.org/rfc/rfc8620.html#section-3.4">RFC8620 Section 3.4</eref>)
which contains the log lines of the JMAP server.</t>
<t>An example use case would be a JMAP API software running on a third-party
infrastructure in which log messages from the API cannot be sent to a dedicated logging service. Access to the third-party infrastructure is restrictive in the sense that there is only access to the JMAP API endpoint.</t>
</section>

<section anchor="addition-to-the-capabilities-object-1"><name>Addition to the Capabilities Object</name>
<t>The capabilities object is returned as part of the JMAP Session object; see
<xref target="RFC8620"></xref>, Section 2. This document defines one additional capability URI.</t>

<section anchor="urn-ietf-params-jmap-debug"><name>urn:ietf:params:jmap:debug</name>
<t>Represents support for the <strong>logs</strong> property in the JMAP method response
(defined in
<eref target="https://www.rfc-editor.org/rfc/rfc8620.html#section-3.4">RFC8620 Section 3.4</eref>)
and the <strong>LogLine</strong> data type.</t>
<t>The value of this property in the JMAP Session and account's capabilities
property is an empty object.</t>
</section>
</section>

<section anchor="response-extension"><name>Response extension</name>
<t>The <strong>Response</strong> object will be extended via:</t>

<ul spacing="compact">
<li><strong>logs</strong>: <tt>LogLine[]</tt> (optional)
An array of log lines for the sent request.</li>
</ul>
<t>A <strong>LogLine</strong> object has the following properties:</t>

<ul spacing="compact">
<li><strong>level</strong>: <tt>String</tt>
The log level of the log message. Must be one of the eight levels defined in
<eref target="https://datatracker.ietf.org/doc/html/rfc5424">RFC5424</eref>: debug, info, notice,
warning, error, critical, alert or emergency.</li>
<li><strong>message</strong>: <tt>String</tt>
The log message</li>
<li><strong>timestamp</strong>: <tt>UTCDate</tt>
The date the log message was logged.</li>
<li><strong>class</strong>: <tt>String|null</tt>
The name of the class that is currently logging.</li>
<li><strong>file</strong>: <tt>String|null</tt>
The file that initiated the log line.</li>
<li><strong>line</strong>: <tt>String|null</tt>
The exact line in the file where the log function is being called.</li>
</ul>
<t>An example list of logs sent alongside a response to Core/echo would look like:</t>

<sourcecode type="json">{
  &quot;logs&quot; : [
    {
      &quot;file&quot; : &quot;Logger.php&quot;,
      &quot;level&quot; : &quot;info&quot;,
      &quot;line&quot; : 32,
      &quot;message&quot; : &quot;Array Logger has been successfully initialized&quot;,
      &quot;timestamp&quot; : &quot;2022-01-18T10:26:56+01:00&quot;
    },
    {
      &quot;file&quot; : &quot;ErrorHandler.php&quot;,
      &quot;level&quot; : &quot;warning&quot;,
      &quot;line&quot; : 52,
      &quot;message&quot; : &quot;fopen(bridge.php):
        failed to open stream: No such file or directory&quot;,
      &quot;timestamp&quot; : &quot;2022-01-18T10:26:56+01:00&quot;
    },
    ...
  ],
  &quot;methodResponses&quot; : [
    [
      &quot;Core/echo&quot;,
      ...
</sourcecode>
</section>

<section anchor="security-considerations-1"><name>Security Considerations</name>
<t>Log messages might contain sensitive user data as well as detailed information
about the system on which an API server has been installed. Appropriate measures
must be taken to restrict access to JMAP Debug to privileged parties only.</t>
</section>
</section>

<section anchor="backend-info"><name>Backend Info</name>

<section anchor="introduction-2"><name>Introduction</name>
<t>Every server-side software has its own quirks. For example, the JMAP standard
might only have been partially implemented by a server or design decisions might
have been taken that let the server deviate from what is actually required by
the standard. Servers might also have unintended bugs or have certain
restrictions that are not advertised by their list of supported
server capabilities.</t>
<t>Interoperable clients that still want to have a successful structured data
exchange with such &quot;unique&quot; servers need to handle these quirks with workarounds
on the client-side. These clients only want to apply special workarounds in
situations where they are truly necessary. This is typically done by identifying
which server-side software they are communicating with.</t>
<t>JMAP does not provide a standardized way to retrieve an identifier of the
product that is residing on the server side. Due to the lack of standardization
clients are left to identify misbehaving servers by error prone means. Examples
are checking against a list of known URLs or checking known unique responses
typically only sent by certain products. This makes identifying products
time-consuming and brittle.</t>
<t>iCalendar and vCard already define a PRODID which property which allows
identifying the product that produced the files.</t>
</section>

<section anchor="addition-to-the-capabilities-object-2"><name>Addition to the capabilities object</name>
<t>The capabilities object is returned as part of the JMAP Session object;
see <xref target="RFC8620"></xref>, Section 2. This document defines one additional capability URI.</t>

<section anchor="urn-ietf-params-jmap-core-backendinfo"><name>urn:ietf:params:jmap:core:backendinfo</name>
<t>This extension defines
one additional <tt>urn:ietf:params:jmap:core:backendinfo</tt> capability that provides
details about the product, backend and environment.</t>

<ul spacing="compact">
<li><strong>backend</strong> <tt>String</tt></li>
<li><strong>product</strong> <tt>String</tt></li>
<li><strong>environment</strong> <tt>String</tt></li>
<li><strong>cababilityInfo</strong> <tt>String[CapabilityInfo]</tt> For
example, the capability <tt>urn:ietf:params:jmap:sieve:backendinfo</tt> would provide
additional meta data for the JMAP Sieve extension.</li>
</ul>
<t>JSON snippet:</t>

<sourcecode type="json">{
  &quot;capabilities&quot;: {
    &quot;urn:ietf:params:jmap:core:backendinfo&quot;: {
      &quot;backend&quot;: &quot;OpenXPort/Horde v1.0.0&quot;,
      &quot;product&quot;: &quot;Horde Webmailer v1.0.0&quot;,
      &quot;environment&quot;: &quot;PHP v5.5&quot;,
      &quot;capabilityInfo&quot;: {
        &quot;urn:ietf:params:jmap:sieve&quot;: {
          &quot;backend&quot;: &quot;Cyrus timsieved&quot;,
          &quot;product&quot;: &quot;Horde Ingo v1.0.0&quot;,
          &quot;fileType&quot;: &quot;SIEVE/HORDE&quot;
        }
      }
    }
  },
    ...
  }
}
</sourcecode>
</section>
</section>
</section>

<section anchor="turning-jmap-portability-into-a-different-version-of-jmap-core"><name>Turning JMAP Portability into a different version of JMAP Core</name>
<t>Because this document contradicts in parts what was stated in JMAP Core (e.g., leave out certain required properties), one might also realize this as a separate protocol that is basically just a subset of JMAP Core. Then we would need to advertise this as a new capability.</t>

<section anchor="addition-to-the-capabilities-object-3"><name>Addition to the capabilities object</name>
<t>This document would then define one more additional capability URI.</t>

<section anchor="urn-ietf-params-jmap-core-essential-portability"><name>urn:ietf:params:jmap:core-essential-portability</name>
<t>The capability <tt>urn:ietf:params:jmap:core-essential-portability</tt> being present in the &quot;capabilities&quot; property represents support for the essential parts of Core JMAP data types and associated API methods as defined in this document.</t>
<t>The value of this property in the JMAP Session capabilities property and the account’s accountCapabilities property is an empty object.</t>
</section>

<section anchor="capability-example-1"><name>Capability Example</name>

<artwork>{
  &quot;capabilities&quot;: {
    ...,
    &quot;urn:ietf:params:jmap:core-essential-portability&quot;: {}
  },
  &quot;apiUrl&quot;: &quot;https://jmap.example.com/api/&quot;,
  &quot;downloadUrl&quot;: &quot;https://jmap.example.com
    /download/{accountId}/{blobId}/{name}?accept={type}&quot;,
  &quot;uploadUrl&quot;: &quot;https://jmap.example.com/upload/{accountId}/&quot;
}
</artwork>
</section>
</section>

<section anchor="iana-considerations-1"><name>IANA Considerations</name>

<section anchor="jmap-capability-registration-for-core-essential-portability"><name>JMAP Capability registration for &quot;core-essential-portability&quot;</name>
<t>IANA is requested to register the &quot;core-essential-portability&quot; JMAP Capability as follows:</t>
<t>Capability Name: urn:ietf:params:jmap:core-essential-portability</t>
<t>Specification document: this document</t>
<t>Intended use: common</t>
<t>Change Controller: IETF</t>
<t>Security and privacy considerations: this document, Section XXX</t>
</section>
</section>
</section>

</back>

</rfc>
