<?xml version='1.0'encoding='utf-8'?>encoding='UTF-8'?> <!-- draft submitted in xml v3 --> <!DOCTYPE rfc [ <!ENTITY nbsp " "> <!ENTITY zwsp "​"> <!ENTITY nbhy "‑"> <!ENTITY wj "⁠"> ]> <rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" category="std" docName="draft-ietf-jmap-sieve-22" number="9661" obsoletes="" updates="" submissionType="IETF" consensus="true" xml:lang="en" tocInclude="true" symRefs="true" sortRefs="true" version="3"><!-- xml2rfc v2v3 conversion 3.10.0 --><front> <title abbrev="JMAPSieve">JMAPSieve">The JSON Meta Application Protocol (JMAP) for Sieve Scripts</title> <seriesInfoname="Internet-Draft" value="draft-ietf-jmap-sieve-22"/>name="RFC" value="9661"/> <author initials="K." surname="Murchison" fullname="Kenneth Murchison"> <organization abbrev="Fastmail">Fastmail US LLC</organization> <address> <postal> <street>1429 WalnutStreet -Street, Suite 1201</street> <city>Philadelphia</city> <region>PA</region> <code>19102</code><country>USA</country><country>United States of America</country> </postal> <email>murch@fastmailteam.com</email> </address> </author><date/><date month="September" year="2024"/> <area>ART</area><!-- <workgroup>Independent Submission</workgroup>--> <workgroup>JMAP</workgroup><workgroup>jmap</workgroup> <keyword>JMAP</keyword> <keyword>JSON</keyword> <keyword>Sieve</keyword> <abstract> <t>This document specifies a data model for managing Sieve scripts on a server using the JSON Meta Application Protocol (JMAP). Clients can use this protocol to efficiently search, access, organize, and validate Sieve scripts. </t> </abstract><!-- <note title="Open Issues"> <ul spacing="normal"> <li> </li> </ul> </note> --></front> <middle> <section numbered="true" toc="default"> <name>Introduction</name> <t><xreftarget="RFC8620">JMAP</xref> (JSONtarget="RFC8620">The JSON Meta ApplicationProtocol)Protocol (JMAP)</xref> is a generic protocol for synchronizing data, such as mail,calendarscalendars, or contacts, between a client and a server. It is optimized for mobile and web environments, and it aims to provide a consistent interface to different data types. </t> <t>This specification defines a data model for managing <xreftarget="RFC5228">Sieve</xref> scriptstarget="RFC5228">Sieve scripts</xref> on a server using JMAP. The data model is designed to allow a server to provide consistent access to the same scripts via <xref target="RFC5804">ManageSieve</xref> as well as JMAP. </t> <section numbered="true" toc="default"> <name>Notational Conventions</name> <t>The key words"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY","<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and"OPTIONAL""<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as described inBCP 14BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shownhere. </t>here.</t> <t>Type signatures, examples, and property descriptions in this document follow the conventions established in <xref target="RFC8620" section="1.1"/>. This document also uses data types and terminology established inSections <xrefSections <xref target="RFC8620" section="1.2"sectionFormat="bare"/>-<xrefsectionFormat="bare"/> through <xref target="RFC8620" section="1.6" sectionFormat="bare"/> of <xref target="RFC8620"/>.</t> <t>The termSieveScript"SieveScript" (with this specific capitalization) is used to refer to the data type defined inthis document<xref target="object"/> and instances ofthosethis datatypes.type used throughout this document. ServersMUST<bcp14>MUST</bcp14> support all properties specified for the data type defined in this document.</t> <t>For brevity, JMAP API examples (see <xref target="RFC8620" section="3"/>)examplesonly show the "methodCalls" property of theRequest object,"Request" object and the "methodResponses" property of theResponse"Response" object. All other examples are shown using the <xreftarget="RFC9112">HTTP 1.1</xref> protocol.</t>target="RFC9112">HTTP/1.1 protocol</xref>.</t> </section> <section numbered="true" toc="default"> <name>Addition to the Capabilities Object</name> <t>Thecapabilities"capabilities" object is returned as part of the JMAP Session object; see <xref target="RFC8620" section="2" sectionFormat="comma"/>. This document defines one additional capability URI. </t> <section anchor="capa" numbered="true" toc="default"> <name>urn:ietf:params:jmap:sieve</name> <t>The urn:ietf:params:jmap:sieve URI represents support for the SieveScript data type and associated API methods. The value of this property in the JMAP Sessioncapabilities"capabilities" property is an object thatMUST<bcp14>MUST</bcp14> contain the following information on server capabilities: </t><ul<dl spacing="normal"><li> <t><strong>implementation</strong>:<dt><strong>implementation</strong>:</dt><dd><t> <tt>String</tt> </t> <t> The name and version of the Sieve implementation. </t><t/> </li> </ul></dd> </dl> <t>The value of this property in an account'saccountCapabilities"accountCapabilities" property is an object thatMUST<bcp14>MUST</bcp14> contain the following information on per-account server capabilities: </t><ul<dl spacing="normal"><li> <t><strong>maxSizeScriptName</strong>: <tt>UnsignedInt</tt><dt><strong>maxSizeScriptName</strong>:</dt> <dd><t><tt>UnsignedInt</tt> </t> <t> The maximum length, in octets, allowed for the name of a SieveScript. For compatibility with ManageSieve, thisMUST<bcp14>MUST</bcp14> be at least 512 (up to 128 Unicode characters).</t> <t/> </li> <li> <t><strong>maxSizeScript</strong>: <tt>UnsignedInt|null</tt></t></dd> <dt><strong>maxSizeScript</strong>:</dt><dd> <t><tt>UnsignedInt|null</tt> </t> <t> The maximum size (in octets) of a Sieve script the server is willing to store for the user, or <tt>null</tt> for no limit. </t><t/> </li> <li> <t><strong>maxNumberScripts</strong>: <tt>UnsignedInt|null</tt></dd> <dt><strong>maxNumberScripts</strong>:</dt> <dd><t><tt>UnsignedInt|null</tt> </t> <t> The maximum number of Sieve scripts the server is willing to store for the user, or <tt>null</tt> for no limit. </t><t/> </li> <li> <t><strong>maxNumberRedirects</strong>: <tt>UnsignedInt|null</tt></dd> <dt><strong>maxNumberRedirects</strong>:</dt> <dd><t><tt>UnsignedInt|null</tt> </t> <t> The maximum number of Sieve "redirect" actions a script can perform during a singleevaluationevaluation, or <tt>null</tt> for no limit. Note that this is different from the total number of "redirect" actions a script can contain. </t><t/> </li> <li> <t><strong>sieveExtensions</strong>: <tt>String[]</tt></dd> <dt><strong>sieveExtensions</strong>:</dt> <dd><t><tt>String[]</tt> </t> <t> A list of case-sensitive Sieve capability strings (as listed in the Sieve "require" action; see <xref target="RFC5228" section="3.2" sectionFormat="comma"/>) indicating the extensions supported by the Sieve engine.</t> <t/> </li> <li> <t><strong>notificationMethods</strong>: <tt>String[]|null</tt></t></dd> <dt><strong>notificationMethods</strong>:</dt> <dd><t><tt>String[]|null</tt> </t> <t> A list of <xref target="RFC3986">URIschemascheme parts</xref> for notification methods supported by the Sieve <xreftarget="RFC5435">"enotify"</xref> extension,target="RFC5435">"enotify" extension</xref>, or <tt>null</tt> if the extension is not supported by the Sieve engine. </t><t/> </li> <li> <t><strong>externalLists</strong>: <tt>String[]|null</tt></dd> <dt><strong>externalLists</strong>:</dt> <dd><t><tt>String[]|null</tt> </t> <t> A list of <xref target="RFC3986">URIschemascheme parts</xref> for externally stored list types supported by the Sieve <xreftarget="RFC6134">"extlists"</xref> extension,target="RFC6134">"extlists" extension</xref>, or <tt>null</tt> if the extension is not supported by the Sieve engine. </t></li> </ul></dd> </dl> </section> <section anchor="session" numbered="true" toc="default"> <name>Example</name> <t keepWithNext="true">AThis example JMAP Session objectshowingshows a user that has access to their own Sieve scripts with support for a few Sieve extensions: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ { "capabilities": { "urn:ietf:params:jmap:core": { ... }, "urn:ietf:params:jmap:mail": {}, "urn:ietf:params:jmap:quota": {}, "urn:ietf:params:jmap:blob": {}, "urn:ietf:params:jmap:sieve": { "implementation": "ACME Email Filtering" }, "urn:ietf:params:jmap:vacationresponse": {}, ... }, "accounts": { "ken": { "name": "ken@example.com", "isPersonal": true, "isReadOnly": false, "accountCapabilities": { "urn:ietf:params:jmap:core": {}, "urn:ietf:params:jmap:quota": {}, "urn:ietf:params:jmap:mail": { ... }, "urn:ietf:params:jmap:blob": { "supportedTypeNames": [ "Email" "SieveScript", ... ], ... }, "urn:ietf:params:jmap:sieve": { "maxSizeScriptName": 512, "maxSizeScript": 65536, "maxNumberScripts": 5, "maxNumberRedirects": null, "sieveExtensions": [ "fileinto", "imap4flags", "enotify", ... ], "notificationMethods": [ "mailto" ], "externalLists": null, }, "urn:ietf:params:jmap:vacationresponse": {}, ... }, ... } }, "primaryAccounts": { "urn:ietf:params:jmap:mail": "ken", "urn:ietf:params:jmap:sieve": "ken", "urn:ietf:params:jmap:vacationresponse": "ken", ... }, "username": "ken@example.com", "apiUrl": "/jmap/", "downloadUrl": "/jmap/download/{accountId}/{blobId}/{name}?accept={type}", "uploadUrl": "/jmap/upload/{accountId}/", ... }]]></artwork>]]></sourcecode> </section> </section> </section> <section anchor="object" numbered="true" toc="default"> <name>Sieve Scripts</name> <t>A<strong>SieveScript</strong>"SieveScript" object represents a single <xreftarget="RFC5228">Sieve</xref> scripttarget="RFC5228">Sieve script</xref> for filtering email messages at the time of final delivery. </t> <section anchor="props" numbered="true" toc="default"> <name>Sieve Script Properties</name> <t>A<strong>SieveScript</strong>"SieveScript" object has the following properties: </t><ul<dl spacing="normal"><li> <t><strong>id</strong>: <tt>Id</tt><dt><strong>id</strong>:</dt> <dd><t><tt>Id</tt> (immutable; server-set) </t> <t> The id of the script. </t><t/> </li> <li> <t><strong>name</strong>: <tt>String|null</tt></dd> <dt><strong>name</strong>:</dt> <dd><t><tt>String|null</tt> (optional; default isserver-dependent)server dependent) </t> <t> User-visible name for the SieveScript. If non-null, thisMUST<bcp14>MUST</bcp14> be a <xreftarget="RFC5198">Net-Unicode</xref> stringtarget="RFC5198">Net-Unicode string</xref> of at least 1 character in length, subject to the maximum size given in thecapability"capability" object. </t> <t> For compatibility with ManageSieve, serversMUST<bcp14>MUST</bcp14> reject names that contain any of the following Unicode characters:U+0000 - U+001F, U+007F - U+009F,U+0000-U+001F, U+007F-U+009F, U+2028, or U+2029. </t> <t> ServersMAY<bcp14>MAY</bcp14> reject names that violate server policy (e.g., names containing a slash (/)). </t> <t> The nameMUST<bcp14>MUST</bcp14> be unique among all SieveScripts within an account. </t><t/> </li> <li> <t><strong>blobId</strong>: <tt>Id</tt></dd> <dt><strong>blobId</strong>:</dt> <dd><t><tt>Id</tt> </t> <t> The id of the blob containing the raw octets of the script. </t><t/> </li> <li> <t><strong>isActive</strong>: <tt>Boolean</tt></dd> <dt><strong>isActive</strong>:</dt> <dd><t><tt>Boolean</tt> (server-set; default: false) </t> <t> Indicator that the SieveScript is actively filtering incoming messages. </t> <t> A user may have at most one active script. The <xreftarget="set">SieveScript/set</xref> methodtarget="set">SieveScript/set method</xref> is used for changing the active script or disabling Sieve processing. </t><t/> </li> </ul></dd> </dl> </section> <section anchor="content" numbered="true" toc="default"> <name>Sieve Script Content</name> <t>A scriptMUST<bcp14>MUST</bcp14> be <xreftarget="RFC3629">UTF-8</xref> contenttarget="RFC3629">UTF-8 content</xref> of at least 1 character in length, subject to the syntax of <xref target="RFC5228">Sieve</xref>. A scriptMUST NOT<bcp14>MUST NOT</bcp14> contain any "require" statement(s) mentioning Sieve capability strings not present in the <xreftarget="capa">capability</xref> object.target="capa">"capability" object</xref>. Note that if the Sieve <xreftarget="RFC5463">"ihave"</xref>target="RFC5463">"ihave" capability string </xref> is present in thecapability"capability" object, the scriptMAY<bcp14>MAY</bcp14> mention unrecognized/unsupported extensions in the "ihave" test. </t> <t>Script content is treated as a binary blob and uploaded/downloaded via the mechanisms provided in<xref target="RFC8620"/> Sections <xrefSections <xref target="RFC8620" section="6.1"sectionFormat="bare"/>/<xrefsectionFormat="bare"/> and <xref target="RFC8620" section="6.2" sectionFormat="bare"/>respectivelyof <xref target="RFC8620"/>, respectively, and/or via the JMAP Blob management methods provided in<xref target="RFC9404"/> Sections <xrefSections <xref target="RFC9404" section="4.1"sectionFormat="bare"/>/<xrefsectionFormat="bare"/> and <xref target="RFC9404" section="4.2" sectionFormat="bare"/> of <xref target="RFC9404"/>, respectively. </t> <t>Downloading script content via the JMAP downloadUrl or the Blob/get method providesequivalentfunctionality equivalent to that of the GETSCRIPT command defined in <xref target="RFC5804"/>. </t> </section> <section anchor="get" numbered="true" toc="default"> <name>SieveScript/get</name> <t>This is a standard "/get" method as described in <xref target="RFC8620" section="5.1" sectionFormat="comma"/>. The<em>ids</em>"ids" argument may be <tt>null</tt> to fetch all scripts at once. </t> <t>This method providesequivalentfunctionality equivalent to that of the LISTSCRIPTS command defined in <xref target="RFC5804"/>. </t> <section numbered="true" toc="default"> <name>Examples</name> <t keepWithNext="true"> List all scripts: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ [ ["SieveScript/get", { "accountId": "ken" }, "0"] ] [ [ "SieveScript/get", { "state": "1634915373.240633104-120", "list": [ { "id": "2d647053-dded-418d-917a-63eda3ac8f7b", "name": "test1", "isActive": true, "blobId": "S7" } ], "notFound": [], "accountId": "ken" }, "0" ] ]]]></artwork>]]></sourcecode> <t keepWithNext="true"> Download the script content via the JMAP downloadUrl as advertised in the example in <xref target="session"/>: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="http-message"><![CDATA[ GET /jmap/download/ken/S7/test1.siv?accept=application/sieve HTTP/1.1 Host: jmap.example.com Authorization: Basic a2VuOnBhc3N3b3Jk HTTP/1.1 200 OK Date: Fri, 22 Oct 2021 15:27:38 GMT Content-Type: application/sieve; charset=utf-8 Content-Disposition: attachment; filename="test1.siv" Content-Length: 49 require ["fileinto"]; fileinto "INBOX.target";]]></artwork>]]></sourcecode> <t keepWithNext="true"> Fetch script properties and content in a single JMAP API request using the <xref target="RFC9404"> JMAP Blob management extension</xref>: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ [ ["SieveScript/get", { "accountId": "ken", "ids": [ "2d647053-dded-418d-917a-63eda3ac8f7b" ] }, "0"], ["Blob/get", { "accountId": "ken", "#ids": { "resultOf": "0", "name": "SieveScript/get", "path": "/list/*/blobId" } }, "1"] ] [ [ "SieveScript/get", { "state": "1634915373.240633104-120", "list": [ { "id": "2d647053-dded-418d-917a-63eda3ac8f7b", "name": "test1", "isActive": true, "blobId": "S7" } ], "notFound": [], "accountId": "ken" }, "0" ], [ "Blob/get", { "list": [ { "id": "S7", "data:asText": "require [\"fileinto\"];\\r\\nfileinto \"INBOX.target\";\\r\\n", "size": 49 } ], "notFound": [], "accountId": "ken" }, "1" ] ]]]></artwork>]]></sourcecode> </section> </section><!-- /get --><section anchor="set" numbered="true" toc="default"> <name>SieveScript/set</name> <t>This is a standard "/set" method as described in <xref target="RFC8620" section="5.3"sectionFormat="comma"/>sectionFormat="comma"/>, but with the following additional optional request arguments: </t><ul<dl spacing="normal"><li> <t><strong>onSuccessActivateScript</strong>: <tt>Id</tt><dt><strong>onSuccessActivateScript</strong>:</dt> <dd><t><tt>Id</tt> </t> <t> The id of the SieveScript to activate if and only if all of the creations, modifications, and destructions (if any) succeed. (For references to SieveScript creations, this is equivalent to a creation-reference, so the id will be the creation id prefixed with a "#".) The currently active SieveScript (if any) will be deactivated before activating the specified SieveScript. </t> <t> If omitted, or if the id is either invalid or nonexistent, itMUST<bcp14>MUST</bcp14> beignoredignored, and the currently active SieveScript (if any) will remain as such. </t> <t> The id of any activated SieveScriptMUST<bcp14>MUST</bcp14> be reported in either the "created" or "updated" argument in the response as appropriate, including a value of "true" for the "isActive" property. The id of any deactivated SieveScriptMUST<bcp14>MUST</bcp14> be reported in the "updated" argument in the response, including a value of "false" for the "isActive" property. </t><t/> </li> <li> <t><strong>onSuccessDeactivateScript</strong>: <tt>Boolean</tt></dd> <dt><strong>onSuccessDeactivateScript</strong>:</dt> <dd><t><tt>Boolean</tt> </t> <t> If<tt>true</tt>,"true", the currently active SieveScript (if any) will be deactivated if and only if all of the creations, modifications, and destructions (if any) succeed. If<tt>false</tt>"false" or omitted, the currently active SieveScript (if any) will remain as such. </t> <t> The id of any deactivated SieveScriptMUST<bcp14>MUST</bcp14> be reported in the "updated" argument in the response, including a value of "false" for the "isActive" property. </t><t/> </li> </ul></dd> </dl> <t>If both the<strong>onSuccessActivateScript</strong>"onSuccessActivateScript" and<strong>onSuccessDeactivateScript</strong>"onSuccessDeactivateScript" arguments are present in the request, then<strong>onSuccessDeactivateScript</strong> MUST"onSuccessDeactivateScript" <bcp14>MUST</bcp14> be processed first. If neither argument is present in the request, the currently active SieveScript (if any) will remain as such. </t> <t>This method providesequivalentfunctionality equivalent to that of the PUTSCRIPT, DELETESCRIPT, RENAMESCRIPT, and SETACTIVE commands defined in <xref target="RFC5804"/>. </t> <t>Script content must first be uploaded as per <xref target="content"/> prior to referencing it in a SieveScript/set call.</t> <t>If the SieveScriptcan notcannot be created or updated because it would result in two SieveScripts with the same name, the serverMUST<bcp14>MUST</bcp14> reject the request with an "alreadyExists" SetError. An "existingId" property of type "Id"MUST<bcp14>MUST</bcp14> be included on the SetError object with the id of the existing SieveScript.</t> <t>If the SieveScriptcan notcannot be created or updated because its size exceeds the "maxSizeScript" limit, the serverMUST<bcp14>MUST</bcp14> reject the request with a "tooLarge" SetError.</t> <t>If the SieveScriptcan notcannot be created because it would exceed the "maxNumberScripts" limit or would exceed a server-imposed storage limit, the serverMUST<bcp14>MUST</bcp14> reject the request with an "overQuota" SetError.</t> <t>The active SieveScriptMUST NOT<bcp14>MUST NOT</bcp14> be destroyed unless it is first deactivated in a separate SieveScript/set method call.</t> <t>The following extra SetError types are defined: </t> <t>For "create" and "update": </t><ul<dl spacing="normal"><li> <t><strong>invalidSieve</strong>: </t> <t><dt><strong>invalidSieve</strong>:</dt> <dd><t> The SieveScript content violates the <xreftarget="RFC5228">Sieve</xref> grammartarget="RFC5228">Sieve grammar</xref>, and/or one or more extensions mentioned in the script's "require" statement(s) are not supported by the Sieve interpreter. The<em>description</em>"description" property on the SetError objectSHOULD<bcp14>SHOULD</bcp14> contain a specific error message giving at least the line number of the firsterror. </t> <t/> </li> </ul>error.</t> </dd> </dl> <t>For "destroy": </t><ul<dl spacing="normal"><li> <t><strong>sieveIsActive</strong>: </t> <t><dt><strong>sieveIsActive</strong>:</dt> <dd><t> The SieveScript is active. </t><t/> </li> </ul></dd> </dl> <section numbered="true" toc="default"> <name>Examples</name> <t keepWithNext="true"> Upload a script requiring the Imap4Flags Extension <xref target="RFC5232"/>Extensionusing the JMAP uploadUrl as advertised in the example in <xref target="session"/>: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="http-message"><![CDATA[ POST /jmap/upload/ken/ HTTP/1.1 Host: jmap.example.com Authorization: Basic a2VuOnBhc3N3b3Jk Content-Type: application/sieve Content-Length: 98 require "imapflags"; if address :is ["To", "Cc"] "jmap@ietf.org" { setflag "\\Flagged"; } HTTP/1.1 201 Created Date: Thu, 10 Dec 2020 17:14:31 GMT Content-Type: application/json; charset=utf-8 Content-Length: 171 { "accountId": "ken", "blobId": "Gabcc83e44a6e19991c4568d0b94e1767c83dd123", "type": "application/sieve" "size": 98 }]]></artwork>]]></sourcecode> <t keepWithNext="true"> Create and activate a script using the uploaded blob. Note that the response shows that an existing active script has been deactivated in lieu of the newly created script being activated. </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ [ ["SieveScript/set", { "accountId": "ken", "create": { "A": { "name": null, "blobId": "Gabcc83e44a6e19991c4568d0b94e1767c83dd123" } }, "onSuccessActivateScript": "#A" }, "0"] ] [ [ "SieveScript/set", { "oldState": "1603741717.50737918-4096", "newState": "1603741751.227268529-4096", "created": { "A": { "id": "dd1b164f-8cdc-448c-9f54", "name": "ken-20201210T171432-0", "blobId": "Sdd1b164f-8cdc-448c-9f54", "isActive": true } }, "updated": { "8abd6f4a-bcb4d-87650-3fcd": { "isActive": false } }, "destroyed": null, "notCreated": null, "notUpdated": null, "notDestroyed": null, "accountId": "ken" }, "0" ] ]]]></artwork>]]></sourcecode> <t keepWithNext="true"> Update the script content using the <xref target="RFC9404"> JMAP Blob management extension</xref>: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ { [ ["Blob/upload", { "accountId": "ken", "create": { "B": { "data": [ { "data:asText": "redirect \"ken@example.com\"\r\n;" } ], "type": "application/sieve" } } }, "1"], ["SieveScript/set", { "accountId": "ken", "update": { "dd1b164f-8cdc-448c-9f54": { "blobId": "#B" } } }, "2"] ] [ [ "Blob/upload", { "oldState": null, "newState": "1603741700.309607123-0128", "created": { "B": { "id": "G969c83e44a6e10871c4568d0b94e1767c83ddeae", "blobId": "G969c83e44a6e10871c4568d0b94e1767c83ddeae", "type": "application/sieve", "size": 29 } }, "notCreated": null, "accountId": "ken" }, "1" ], [ "SieveScript/set", { "oldState": "1603741751.227268529-4096", "newState": "1603742603.309607868-4096", "created": null, "updated": { "dd1b164f-8cdc-448c-9f54": null }, "destroyed": null, "notCreated": null, "notUpdated": null, "notDestroyed": null, "accountId": "ken" }, "2" ] ]]]></artwork>]]></sourcecode> <t keepWithNext="true"> Update the scriptnamename, and deactivate it: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ [ ["SieveScript/set", { "accountId": "ken", "update": { "dd1b164f-8cdc-448c-9f54": { "name": "myscript" } }, "onSuccessDeactivateScript": true }, "3"] ] [ [ "SieveScript/set", { "oldState": "1603742603.309607868-4096", "newState": "1603742967.852315428-4096", "created": null, "updated": { "dd1b164f-8cdc-448c-9f54": { "isActive": false } }, "destroyed": null, "notCreated": null, "notUpdated": null, "notDestroyed": null, "accountId": "ken" }, "3" ] ]]]></artwork>]]></sourcecode> <t keepWithNext="true"> Reactivate the script: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ [ ["SieveScript/set", { "accountId": "ken", "onSuccessActivateScript": "dd1b164f-8cdc-448c-9f54" }, "4"] ] [ [ "SieveScript/set", { "oldState": "1603742967.852315428-4096", "newState": "1603744460.316617118-4096", "created": null, "updated": { "dd1b164f-8cdc-448c-9f54": { "isActive": true } }, "destroyed": null, "notCreated": null, "notUpdated": null, "notDestroyed": null, "accountId": "ken" }, "4" ] ]]]></artwork>]]></sourcecode> <t keepWithNext="true"> Deactivate and destroy the active script: </t><artwork<sourcecode name=""type="" align="left" alt=""><![CDATA[type="json"><![CDATA[ [ ["SieveScript/set", { "accountId": "ken", "onSuccessDeactivateScript": true }, "5"], ["SieveScript/set", { "accountId": "ken", "destroy": [ "dd1b164f-8cdc-448c-9f54" ] }, "6"] ] [ [ "SieveScript/set", { "oldState": "1603744460.316617118-4096", "newState": "1603744637.575375572-4096", "created": null, "updated": { "dd1b164f-8cdc-448c-9f54": { "isActive": false } }, "destroyed": null, "notCreated": null, "notUpdated": null, "notDestroyed": null, "accountId": "ken" }, "5" ], [ "SieveScript/set", { "oldState": "1603744637.575375572-4096", "newState": "1603744637.854390875-4096", "created": null, "updated": null, "destroyed": [ "dd1b164f-8cdc-448c-9f54" ], "notCreated": null, "notUpdated": null, "notDestroyed": null, "accountId": "ken" }, "6" ] ]]]></artwork>]]></sourcecode> </section> </section><!-- /set --><section numbered="true" toc="default"> <name>SieveScript/query</name> <t>This is a standard "/query" method as described in <xref target="RFC8620" section="5.5" sectionFormat="comma"/>. A<em>FilterCondition</em>"FilterCondition" object has the following properties, either of which may be omitted: </t><ul<dl spacing="normal"><li> <t><strong>name</strong>: <tt>String</tt><dt><strong>name</strong>:</dt> <dd><t><tt>String</tt> </t> <t> The SieveScript "name" property contains the given string. </t><t/> </li> <li> <t><strong>isActive</strong>: <tt>Boolean</tt></dd> <dt><strong>isActive</strong>:</dt> <dd><t><tt>Boolean</tt> </t> <t> The "isActive" property of the SieveScript must be identical to the value given to match the condition. </t><t/> </li> <!-- <t> <spanx style="strong">isIncluded</spanx>: <spanx style="verb">Boolean</spanx> <vspace blankLines="1"/> If true, the SieveScript must be included (see <xref target="RFC6609" />) by the content of another SieveScript to match the condition. Otherwise, the SieveScript must not be included by the content of another SieveScript to match the condition. <vspace blankLines="1"/> </t> --> </ul></dd> </dl> <t>The following SieveScript propertiesMUST<bcp14>MUST</bcp14> be supported for sorting: </t> <ul spacing="normal"> <li> <t><strong>name</strong> </t><t/></li> <li> <strong>isActive</strong> </li> </ul> </section> <section numbered="true" toc="default"> <name>SieveScript/validate</name> <t>This method is used by the client to verify Sieve script validity without storing the script on the server. </t> <t>The method takes the following arguments: </t><ul<dl spacing="normal"><li> <t><strong>accountId</strong>: <tt>Id</tt><dt><strong>accountId</strong>:</dt> <dd><t><tt>Id</tt> </t> <t> The id of the account to use. </t><t/> </li> <li> <t><strong>blobId</strong>: <tt>Id</tt></dd> <dt><strong>blobId</strong>:</dt> <dd><t><tt>Id</tt> </t> <t> The id of the blob containing the raw octets of the script to validate, subject to the same requirements in <xreftarget="object"/>.target="content"/>. </t><t/> </li> </ul></dd> </dl> <t>The response has the following arguments: </t><ul<dl spacing="normal"><li> <t><strong>accountId</strong>: <tt>Id</tt><dt><strong>accountId</strong>:</dt> <dd><t><tt>Id</tt> </t> <t> The id of the account used for this call. </t><t/> </li> <li> <t><strong>error</strong>: <tt>SetError|null</tt></dd> <dt><strong>error</strong>:</dt> <dd><t><tt>SetError|null</tt> </t> <t> An "invalidSieve" SetError object if the script content is invalid (see <xref target="set"/>), or <tt>null</tt> if the script content is valid. </t><t/> </li> </ul></dd> </dl> <t>This method providesequivalentfunctionality equivalent to that of the CHECKSCRIPT command defined in <xref target="RFC5804"/>.</t> <t>Script content must first be uploaded as per <xref target="content"/> prior to referencing it in a SieveScript/validate call.</t> </section><!-- /validate --></section> <section anchor="quotas" numbered="true" toc="default"> <name>Quotas</name> <t>ServersSHOULD<bcp14>SHOULD</bcp14> impose quotas on Sieve scripts to prevent malicious users from exceeding available storage. Administration of such quotas is outside of the scope of thisspecification, howeverspecification; however, <xref target="RFC9425"/> defines a data model for users to obtain quota details over JMAP.</t> <t>The mechanism for handling SieveScript requests that would place a user over a quota setting is discussed in <xref target="set"/>. </t> </section> <section anchor="vacation" numbered="true" toc="default"> <name>Compatibility with JMAP Vacation Response</name> <t><xref target="RFC8621" section="8"/> defines aVacationResponse"VacationResponse" object to represent an autoresponder to incoming email messages. Servers that implement the VacationResponse as a Sieve script that residesamongstamong other user scripts are subject to the following requirements: </t> <ul spacing="normal"><li>MUST<li><bcp14>MUST</bcp14> allow the VacationResponse Sieve script to be fetched by the <xreftarget="get">SieveScript/get</xref> method.target="get">SieveScript/get method</xref>. </li><li>MUST<li><bcp14>MUST</bcp14> allow the VacationResponse Sieve script to be[de]activatedactivated or deactivated via the "onSuccessActivateScript" argument to the <xreftarget="set">SieveScript/set</xref> method.target="set">SieveScript/set method</xref>. </li><li>MUST NOT<li><bcp14>MUST NOT</bcp14> allow the VacationResponse Sieve script to be destroyed or have its content updated by the <xreftarget="set">SieveScript/set</xref> method.target="set">SieveScript/set method</xref>. Any such requestMUST<bcp14>MUST</bcp14> be rejected with a "forbidden" SetError. A "description" propertyMAY<bcp14>MAY</bcp14> be present with an explanation that the script can only be modified by a VacationResponse/set method. </li> </ul> </section> <section anchor="security" numbered="true" toc="default"> <name>Security Considerations</name> <t>All security considerationsofdiscussed in <xref target="RFC8620">JMAP</xref> and <xref target="RFC5228">Sieve</xref> apply to this specification.</t> <t>Additionally, implementationsMUST<bcp14>MUST</bcp14> treat Sieve script content as untrusted data. As such, script parsersMUST<bcp14>MUST</bcp14> fail gracefully in the face of syntactically invalid or malicious content andMUST<bcp14>MUST</bcp14> be prepared to deal with resource exhaustion(E.g.,(e.g., allocation of enormous strings, lists, or command blocks). </t> </section> <section numbered="true" toc="default"> <name>IANA Considerations</name> <section numbered="true" toc="default"> <name>JMAP Capability Registration for "sieve"</name> <t>IANAwill register thehas registered "sieve"JMAP Capabilityin the "JMAP Capabilities" registry as follows: </t><t>Capability Name: <tt>urn:ietf:params:jmap:sieve</tt> </t> <t>Specification document: this document </t> <t>Intended use: common </t> <t>Change Controller: IETF </t> <t>Security and privacy considerations: this document,<dl spacing="normal"> <dt>Capability Name:</dt><dd><tt>urn:ietf:params:jmap:sieve</tt></dd> <dt>Reference:</dt><dd>RFC 9661</dd> <dt>Intended Use:</dt><dd>common</dd> <dt>Change Controller:</dt><dd>IETF</dd> <dt>Security and Privacy Considerations:</dt><dd>RFC 9661, <xreftarget="security"/> </t>target="security"/></dd> </dl> </section> <section numbered="true" toc="default"> <name>JMAP Data Type Registration for "SieveScript"</name> <t>IANAwill register thehas registered "SieveScript"JMAPin the "JMAP DataTypeTypes" registry as follows: </t><t>Type Name: <tt>SieveScript</tt> </t> <t>Can<dl spacing="normal"> <dt>Type Name:</dt><dd><tt>SieveScript</tt></dd> <dt>Can ReferenceBlobs: yes </t> <t>CanBlobs:</dt><dd>Yes</dd> <dt>Can Use for StateChange: yes </t> <t>Capability: <tt>urn:ietf:params:jmap:sieve</tt> </t> <t>Specification document: this document </t>Change:</dt><dd>Yes</dd> <dt>Capability:</dt><dd><tt>urn:ietf:params:jmap:sieve</tt></dd> <dt>Reference:</dt><dd>RFC 9661</dd> </dl> </section> <section numbered="true" toc="default"> <name>JMAP Error Codes Registry</name> <t>TheIANA has registered the followingsub-sections registertwo new error codes in theJMAP"JMAP ErrorCodesCodes" registry, as defined in <xref target="RFC8620"/>. </t> <section numbered="true" toc="default"> <name>invalidSieve</name><t>JMAP<dl spacing="normal"> <dt>JMAP ErrorCode: invalidSieve </t> <t>Intended use: common </t> <t>Change controller: IETF </t> <t>Reference: This document,Code:</dt><dd>invalidSieve</dd> <dt>Intended Use:</dt><dd>common</dd> <dt>Change Controller:</dt><dd>IETF</dd> <dt>Reference:</dt><dd>RFC 9661, <xreftarget="set"/> </t> <t>Description: Thetarget="set"/></dd> <dt>Description:</dt><dd>The SieveScript violates the <xref target="RFC5228">Sievegrammar</xref>grammar</xref>, and/or one or more extensions mentioned in the script's "require" statement(s) are not supported by the Sieveinterpreter.</t>interpreter.</dd> </dl> </section> <section numbered="true" toc="default"> <name>sieveIsActive</name><t>JMAP<dl spacing="normal"> <dt>JMAP ErrorCode: sieveIsActive </t> <t>Intended use: common </t> <t>Change controller: IETF </t> <t>Reference: This document,Code:</dt><dd>sieveIsActive</dd> <dt>Intended Use:</dt><dd>common</dd> <dt>Change Controller:</dt><dd>IETF</dd> <dt>Reference:</dt><dd>RFC 9661, <xreftarget="set"/> </t> <t>Description: Thetarget="set"/></dd> <dt>Description:</dt><dd>The client tried to destroy the activeSieveScript.</t>SieveScript.</dd> </dl> </section> </section> </section> </middle> <back> <references> <name>References</name> <references> <name>Normative References</name> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8620.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8621.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5228.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5435.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6134.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3629.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5198.xml"/> </references> <references> <name>Informative References</name> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5232.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5463.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5804.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9112.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9404.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9425.xml"/> </references> </references> <sectionnumbered="true"numbered="false" toc="default"> <name>Acknowledgments</name> <t>The concepts in this document are based largely on those in <xref target="RFC5804"/>. The author would like to thank the authors of that document for providing both inspiration and some borrowed text for this document.</t> <t>The author would also like to thank the following individuals for contributing their ideas and support for writing this specification:Joris Baum, Mauro<contact fullname="Joris Baum"/>, <contact fullname="Mauro DeGennaro, Bron Gondwana, Neil Jenkins, Alexey Melnikov, and Ricardo Signes.</t> </section> </middle> <back> <references> <name>References</name> <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"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8621.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5228.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5435.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6134.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.3629.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5198.xml"/> </references> <references> <name>Informative References</name> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5232.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5463.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5804.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.9112.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.9404.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.9425.xml"/> </references> </references> <section numbered="true" toc="default"> <name>Change History (To be removed by RFC Editor before publication)</name> <t>Changes since ietf-21: </t> <ul spacing="normal"> <li>Rearranged and tweaked some /validate text.</li> </ul> <t>Changes since ietf-20: </t> <ul spacing="normal"> <li>Listed Unicode characters prohibited in script names.</li> <li>Cleaned up the language of the optional /set arguments.</li> <li>Added security considerations about parsing Sieve script content.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-19: </t> <ul spacing="normal"> <li>Tweaked the example captions.</li> </ul> <t>Changes since ietf-18: </t> <ul spacing="normal"> <li>Edited JMAP API examples for brevity to match other JMAP specs, and added explanatory text to 1.1.</li> <li>Updated <xref> elements to to use "section" and "sectionFormat" attributes.</li> </ul> <t>Changes since ietf-17: </t> <ul spacing="normal"> <li>Several editorial changes resulting from IESG review comments.</li> <li>Added a section discussuing quotas.</li> </ul> <t>Changes since ietf-16: </t> <ul spacing="normal"> <li>Renamed the "invalidScript" and "scriptIsActive" SetErrors to "invalidSieve" and "sieveIsActive" respectively.</li> </ul> <t>Changes since ietf-15: </t> <ul spacing="normal"> <li>Added registration for SieveScript JMAP Data Type.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-14: </t> <ul spacing="normal"> <li>Updated reference for JMAP Blobs.</li> </ul> <t>Changes since ietf-13: </t> <ul spacing="normal"> <li>Added implementation argument to capabilities.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-12: </t> <ul spacing="normal"> <li>Added onSuccessDeactivateScipt argument to /set method.</li> <li>Clarified that the "isActive" property must be included in the created/uodated/destroyed arguments in a response of the active script is changed and/or deactivated.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-11: </t> <ul spacing="normal"> <li>Fixed examples to be proper JSON and JMAP.</li> </ul> <t>Changes since ietf-10: </t> <ul spacing="normal"> <li>Fixed SieveScript/set response deactivating script example.</li> <li>Fixed line line nit in Blob/get request.</li> <li>Removed unused references.</li> </ul> <t>Changes since ietf-09: </t> <ul spacing="normal"> <li>Fixed Blob/upload request in example.</li> </ul> <t>Changes since ietf-08: </t> <ul spacing="normal"> <li>Fixed Blob/upload response in example.</li> <li>Removed SieveScript/test method (to be written as an extension document).</li> </ul> <t>Changes since ietf-07: </t> <ul spacing="normal"> <li>Updated example to use Blob/upload rather than Blob/set.</li> </ul> <t>Changes since ietf-06: </t> <ul spacing="normal"> <li>None (refreshed to avoid expiration).</li> </ul> <t>Changes since ietf-05: </t> <ul spacing="normal"> <li>Converted source from xml2rfc v2 to v3.</li> <li>Added examples for SieveScript/get.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-04: </t> <ul spacing="normal"> <li>SieveScript/test: Switched from using a JSON array for each completed action and its args to a JSON object.</li> <li>Switched to referencing draft-ietf-jmap-blob.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-03: </t> <ul spacing="normal"> <li>SieveScript/test: Moved positional arguments into their own array (because the specfications don't use a consistent method for defining the action syntax or naming of positional arguments).</li> </ul> <t>Changes since ietf-02: </t> <ul spacing="normal"> <li>Removed open issues.</li> <li>Reverted back to using only blob ids for script content.</li> <li>Added "rateLimit" and "requestTooLarge" to the list of possible error codes for /set method.</li> <li>Added Compatibility with JMAP Vacation Response section.</li> <li>Added RFC5228 to Security Considerations.</li> <li>Miscellaneous editorial changes.</li> </ul> <t>Changes since ietf-01: </t> <ul spacing="normal"> <li>Removed normative references to ManageSieve (RFC 5804).</li> <li>Added the 'maxSizeScriptName' capability.</li> <li>Made the 'name' property in the SieveScript object optional.</li> <li>Added requirements for the 'name' property in the SieveScript object.</li> <li>Removed the 'blobId' property from the SieveScript object.</li> <li>Removed the 'replaceOnCreate' argument from the /set method.</li> <li>Removed the 'blobId' argument from the /validate method.</li> <li>Removed the 'scriptBlobId' argument from, and added the 'scriptContent' argument to, the /test method.</li> <li>Editorial fixes from Neil Jenkins and Ricardo Signes.</li> <li>Other miscellaneous text reorganization and editorial fixes.</li> </ul> <t>Changes since ietf-00: </t> <ul spacing="normal"> <li>Specified that changes made by onSuccessActivateScript MUST be reported in the /set response as created and/or updated as appropriate.</li> <li>Reworked and specified more of the /test response based on implementation experience.</li> </ul> <t>Changes since murchison-01: </t> <ul spacing="normal"> <li>Explicitly stated that Sieve capability strings are case-sensitive.</li> <li>errorDescription is now String|null.</li> <li>Added /query method.</li> <li>Added /test method.</li> </ul> <t>Changes since murchison-00: </t> <ul spacing="normal"> <li>Added IANA registration for "scriptIsActive" JMAP error code.</li> <li>Added open issue about /set{create} with an existing script name.</li> </ul>Gennaro"/>, <contact fullname="Bron Gondwana"/>, <contact fullname="Neil Jenkins"/>, <contact fullname="Alexey Melnikov"/>, and <contact fullname="Ricardo Signes"/>.</t> </section> </back> </rfc>