---
title: JMAP for Calendars is awesome
date: 2023-10-29
tags: [code]
description: The predominant protocol used for syncing calendars is CalDAV. CalDAV is a weird protocol.
---
## The old thing: CalDAV
The predominant protocol used for syncing calendars is CalDAV
([RFC 4791](https://www.rfc-editor.org/rfc/rfc4791)). CalDAV is a weird
protocol. It sends events in the iCalendar format
([RFC 5545](https://www.rfc-editor.org/rfc/rfc5545)) over WebDAV
([RFC 4918](https://www.rfc-editor.org/rfc/rfc4918)), which in turn is based on
XML and a modified version of HTTP. This is one example from the spec:
```
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
http://cal.example.com/bernard/work/abcd8.ics
"fffff-abcd8"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VFREEBUSY
ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
UID:76ef34-54a3d2@example.com
DTSTAMP:20050530T123421Z
DTSTART:20060101T100000Z
DTEND:20060108T100000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
END:VFREEBUSY
END:VCALENDAR
HTTP/1.1 200 OK
```
Note how this uses the `REPORT` method, which is not part of stock HTTP. Also,
note how iCalendar is embedded in XML. It is certainly not impossible to parse
this, but it is far more complicated than it should be.
The biggest issue with CalDAV is that it is not universally supported. For
example, [FullCalendar](https://fullcalendar.io), the go-to JavaScript
calendar, does not support CalDAV on its own. Since version 5.5 it does at
least allow to subscribe to read-only iCalendar feeds over HTTP though.
Microsoft products do the same. If you want to get proper read-write support to
your Microsoft calendars, you have to use their proprietary [Exchange
ActiveSync](https://en.wikipedia.org/wiki/Exchange_ActiveSync) protocol.
I have recently worked with CalDAV and encountered two other issues:
- The events I worked with were all associated with an URL. iCalendar does
not offer an URL field, so users had to open the event, copy the URL from
the description field, and manually enter it into their browsers. This is
not a huge issue. Still, I believe this use case is common enough to
warrant a smoother user experience.
- There is no way for the server to notify clients of changes. Clients
typically poll for new events in regular intervals. This means that users
might make appointments in slots that are already taken because they work
with outdated data.
Frustrated with all those issues, I started thinking about a new protocol that
could replace CalDAV. After a bit of research, I found that someone had already
done that work.
## The new thing: JMAP Calendars
[JMAP Calendars](https://jmap.io/spec-calendars.html) is a draft spec to send
events in JSCalendar format
([RFC 8984](https://www.rfc-editor.org/rfc/rfc8984)) over JMAP
([RFC 8620](https://www.rfc-editor.org/rfc/rfc8620)), which in turn is an
RPC protocol based on HTTP and JSON. Here is an example request from the spec:
```json
[
["CalendarEvent/set", {
"accountId": "a0x9",
"create": {
"k559": {
"uid": "5d5776f6-ff8e-4bfd-ab3e-fe2fe5d4fa91",
"calendarIds": {
"3ddf2ad7-0e0c-4fb5-852d-f0ff56f3c662": true
},
"title": "Party at Pete’s",
"start": "2023-02-03T19:00:00",
"duration": "PT3H0M0S",
"timeZone": "Australia/Melbourne",
"showWithoutTime": false,
"participants": {
"1": {
"@type": "Participant",
"name": "Jane Doe"
"scheduleId": "mailto:jane@example.com",
"sendTo": {
"imip": "mailto:jane@example.com",
"other": "https://example.com/uri/for/internal/scheduling"
}
"kind": "individual",
"roles": {
"attendee": true,
"owner": true
},
"participationStatus": "accepted",
"expectReply": false
},
"2": {
"@type": "Participant",
"name": "Joe Bloggs",
"sendTo": {
"imip": "mailto:joe@example.com"
},
"kind": "individual",
"roles": {
"attendee": true
},
"participationStatus": "needs-action",
"expectReply": true
}
},
"mayInviteSelf": false,
"mayInviteOthers": false,
"useDefaultAlerts": false,
"alerts": null
}
},
"sendSchedulingMessages": true
}, "0"]
]
```
This solves most of CalDAV problems:
- It is a much cleaner protocol. JMAP and JSCalendar both use JSON, so
parsing is simple. JMAP uses stock HTTP. I would have preferred it to be
more REST and less RPC, but that is something I can happily live with.
- JSCalendar is based on the semantics of iCalendar, but also makes some
updates. For example, it adds a `Links` field and even a `virtualLocations`
field for online meetings.
- JMAP has push support either via Server-sent events or external push
services.
Of course, support for JMAP Calendars is currently even worse than it is for
CalDAV. To my knowledge, JMAP Calendars is not supported anywhere yet, and JMAP
in general hasn't seen much adoption either.
On the other hand, HTTP and JSON are the de-facto standard for building APIs on
the web. With this clean protocol based on popular technologies, there is hope
that developers will add support once the spec stabilizes. I at least hope to
see a switch from iCalendar-over-HTTP to JSCalendar-over-HTTP.
There are some other protocols (e.g. LDAP) that I would like to see replaced by
something based on HTTP and JSON. There are certainly many pros and cons to
this idea, not least of which is the difficulty for new protocols to gain
traction. Maybe JMAP Calendars can serve as a test to see if this is worth the
effort.