Files
RustBox/docs/CALDAV_CARDDAV.md
T
Mateusz Gruszczyński a3ac2a68fe
RustBox CI / rustbox (push) Waiting to run
v0.2.30
2026-11-08 07:32:12 +01:00

6.4 KiB

CalDAV / CardDAV server

RustBox can serve each account's calendar and contacts over CalDAV (RFC 4791) and CardDAV (RFC 6352). The DAV view and the webmail use the same tables, so an event created on a phone appears in the webmail calendar and a contact edited in the webmail appears on the phone after its next sync.

The server is off by default.

Enabling

[dav]
enabled = true
auth_cache_secs = 300           # remember a successful login for 5 minutes (0 = always ask IMAP)
max_resource_size = 8388608     # largest accepted event / vCard in bytes
calendar_name = "Calendar"
addressbook_name = "Contacts"

Environment overrides use the usual form: DAV__ENABLED=true, DAV__AUTH_CACHE_SECS=60.

Run RustBox behind HTTPS when DAV is enabled: clients send the mail password with every request (HTTP Basic).

URLs

Below <base_path>/dav (with the default base path: https://mail.example.com/dav/):

Resource Path
Service root (for discovery) /dav/
Principal /dav/principals/<login>/
Calendar home /dav/calendars/<login>/
Calendar /dav/calendars/<login>/default/
Address book home /dav/addressbooks/<login>/
Address book /dav/addressbooks/<login>/default/

/.well-known/caldav and /.well-known/carddav redirect to <base_path>/dav/ (RFC 6764). They are registered at the host root even when RustBox runs under a base path; a reverse proxy that only forwards the base path must forward these two paths as well.

<login> is the IMAP login the client authenticates with (normally the e-mail address). A client may only open its own collections; other logins get 403.

Authentication

HTTP Basic with the IMAP login and password. RustBox checks them against the configured imap_host exactly like the webmail login and protects the endpoint with the same brute-force guard ([login_rate_limit]). A successful login is cached in memory for auth_cache_secs, keyed by a hash of login and password, so changing the mail password takes effect for DAV within that time. The tenant database is created on the first DAV login, so DAV works for accounts that never opened the webmail.

Supported protocol

  • OPTIONS (no authentication), PROPFIND (Depth 0/1), PROPPATCH (answered with 403 per property: collection properties are fixed), GET/HEAD, PUT, DELETE.
  • REPORT: calendar-query (VEVENT with optional time-range), calendar-multiget, addressbook-query (prop-filter / text-match, anyof/allof, limit), addressbook-multiget. Other reports (for example sync-collection) return 403 DAV:supported-report; sync-token is not advertised, so clients fall back to CTag polling.
  • Strong ETags (hash of the served object) with If-Match / If-None-Match, and a collection CTag (CS:getctag) that changes on every change, including webmail edits and deletions.
  • One calendar (VEVENT only; supported-calendar-component-set lists VEVENT) and one address book (vCard 3.0 and 4.0) per account. MKCALENDAR / MKCOL return 403. Tasks (VTODO) are not supported.
  • RFC 4791 UID uniqueness: a second resource with an existing UID is refused with CALDAV:no-uid-conflict — except that an event created in the webmail (for example from an e-mail invitation) is adopted, so accepting an invitation on a phone does not duplicate it.

How data is mapped

Objects uploaded by a client are stored verbatim (dav_data) under the client's resource name (dav_name) and decoded into the webmail columns:

iCalendar Webmail field
SUMMARY, DESCRIPTION, LOCATION title, description, location
DTSTART / DTEND / DURATION start / end (times with TZID are converted to UTC; dates make an all-day event)
RRULE recurrence rule
ATTENDEE, ORGANIZER attendees, organizer
STATUS, URL, COLOR status, meeting link, colour
first two VALARM triggers before the start reminders

Only the master component is decoded; recurrence overrides (RECURRENCE-ID), EXDATE, VTIMEZONE and unknown properties stay in the stored object and are served back unchanged.

vCard Webmail field
FN (or N) name
EMAIL (preferred first) e-mail and further addresses
TEL, ADR phone numbers, postal addresses
ORG, TITLE, NOTE, URL, BDAY company, job title, notes, website, birthday
embedded PHOTO (JPEG/PNG/GIF/WebP up to 3 MB) contact photo

Cards without an e-mail address are accepted. Since migration V055 several contacts may share an e-mail address.

When an event or contact that came from a DAV client is edited in the webmail, only the properties whose value actually changed are rewritten in the stored object (plus DTSTAMP/LAST-MODIFIED/SEQUENCE or REV); time zones, exceptions, alarms the webmail does not model and vendor properties are kept. Events and contacts created in the webmail are served as <id>.ics / <id>.vcf with a generated object (iCalendar 2.0 / vCard 3.0).

Clients

  • ActivePush (Exchange ActiveSync gateway): no code changes are needed, only the backend URLs. Its default paths already match RustBox:

    [caldav]
    enabled = true
    base_url = "https://mail.example.com"
    path = "/dav/calendars/%u/"
    
    [carddav]
    enabled = true
    base_url = "https://mail.example.com"
    path = "/dav/addressbooks/%u/"
    

    With a RustBox base_path (for example /mail) prefix the paths: /mail/dav/calendars/%u/. ActivePush authenticates with the same login and password the phone uses, which must be the IMAP login RustBox accepts. Tasks stay disabled because the calendar advertises VEVENT only; creating extra calendar or contact folders from the phone is refused.

  • DAVx⁵, Thunderbird, Apple Calendar/Contacts, Evolution: use the server URL https://mail.example.com/ (discovery through .well-known) or https://mail.example.com/dav/, and the mail login and password.

Limits

  • Recurring events are not expanded server side: a time-range query returns a recurring event whenever its first occurrence starts before the end of the range.
  • ETags and the CTag are computed from the objects on each request; this is cheap for personal calendars and address books (thousands of entries) but means a CTag poll reads the whole collection.
  • Contact groups are not exported as group vCards.
  • Contacts photos added in the webmail are not included in generated vCards.