Object metadata
Clients often need to remember small pieces of information about the objects they work with: a label colour on a mailbox, a client-specific setting on a calendar, a property that a WebDAV client records on a file. Object metadata are these annotations, stored on the server together with the object.
Stalwart keeps the annotations of each object in one store, and exposes that store through three protocols:
- JMAP exposes them through the
metadataandprivateMetadataproperties, described in the Internet-Draft draft-ietf-jmap-metadata (JMAP Object Metadata). The server advertises support as theurn:ietf:params:jmap:metadatacapability. - IMAP exposes them through the METADATA extension (RFC 5464), which covers mailbox and server annotations, and through LIST-METADATA (RFC 9590), which returns the annotations together with the mailbox list.
- WebDAV, CalDAV and CardDAV expose them as dead properties (RFC 4918). A dead property is one that a client sets with
PROPPATCHand that the server stores without interpreting it.
Metadata come in two kinds. Shared metadata are visible to everyone who can access the object. Private metadata are visible only to the user who stored them.
The limits and permissions are set on the Metadata singleton (found in the WebUI under Settings › Network › Metadata). The defaults suit most deployments.
Objects that carry metadata
Section titled “Objects that carry metadata”dataTypes lists the JMAP data types whose objects carry metadata. Out of the box, every type that supports metadata is listed: AddressBook, Calendar, CalendarEvent, ContactCard, Email, FileNode, Mailbox and SieveScript. Removing a type from the set removes the metadata properties from that type in JMAP. When no type is left, the JMAP capability is no longer advertised.
JMAP metadata are stored under namespaces, which keep the data of different applications apart. Applications store their own data under vendor namespaces, named in the form of a domain name such as client.example.com. Stalwart accepts vendor namespaces unless vendorNamespaces is turned off. Turning it off leaves JMAP clients no namespace to write to, so the JMAP capability is then no longer advertised either.
Users can store private metadata unless privateMetadata is turned off.
Limits
Section titled “Limits”Without bounds, a client could grow the metadata of an object without limit. The size and number of entries are therefore limited per object:
| Setting | Default | Limits |
|---|---|---|
maxEntrySize | 8 KiB | Bytes in one entry: a JMAP namespace value, an IMAP annotation or a WebDAV dead property |
maxSize | 64 KiB | Bytes of shared metadata on one object |
maxPrivateSize | 16 KiB | Bytes of private metadata one user stores on one object |
maxEntries | 128 | Entries in the metadata of one object |
maxDepth | 8 | Nesting depth of a JMAP namespace value; empty means no limit |
maxQueryScan | 50000 | Annotated objects a JMAP query scans for a text condition on metadata |
A change that does not make the metadata of an object larger is always accepted. Lowering a limit therefore does not prevent clients from removing entries that exceed it.
Metadata also count towards the storage quota. Shared metadata count towards the quota of the object’s owner, and private metadata towards the quota of the user who stored them.
A write that exceeds a limit is refused, and each protocol reports the refusal in its own way:
- JMAP returns
invalidPropertieson the offending property, with a description such asMetadata size <n> exceeds the maximum of <m> bytes.An account over quota receivesoverQuota. A query with a text condition over more thanmaxQueryScanobjects is refused withunsupportedFilter. - IMAP returns
[METADATA MAXSIZE <n>]for an entry or a set of entries that is too large, and[METADATA TOOMANY]when the object would have too many entries. It returns[METADATA NOPRIVATE]when private entries are not allowed, and[OVERQUOTA]when the account is over quota. - WebDAV answers the
PROPPATCHwith status507for the affected property, with the descriptionProperty value is too longorProperty storage limit exceeded.
The METADATA and LIST-METADATA capabilities are advertised after authentication, and only to users who hold the imapMetadataGet permission.
Besides the annotations of mailboxes, IMAP defines server annotations, which describe the server as a whole. Two of them come from the Metadata object, and clients can read them but not change them:
/shared/commentcomes fromimapServerComment./shared/admincomes fromimapServerAdmin, for examplemailto:[email protected].
Neither is set by default.
The private annotation /private/specialuse of a mailbox, defined in RFC 6154, reflects the mailbox’s role: Sent, Drafts, Trash and so on. Setting the annotation changes the role.
Permissions
Section titled “Permissions”Access to metadata is controlled by the following permissions:
| Permission | Allows |
|---|---|
jmapMetadataGet | Reading metadata over JMAP; the capability is advertised only to users who hold it |
jmapMetadataSet | Writing shared metadata over JMAP |
jmapMetadataPrivate | Reading and writing private metadata over JMAP |
imapMetadataGet | The IMAP GETMETADATA and SETMETADATA commands and LIST with metadata |
imapMetadataSet | Setting shared annotations over IMAP |
imapMetadataPrivate | Reading and setting private annotations over IMAP |
sysMetadataGet, sysMetadataUpdate | Reading and changing the Metadata object |
SETMETADATA requires imapMetadataGet for every annotation. It also requires imapMetadataSet for shared annotations, or imapMetadataPrivate for private ones.
The permissions decide what kind of access a user may have at all. The access rights of the object apply in addition: reading metadata requires read access to the object, and writing shared metadata requires the right to modify it.