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 with403per property: collection properties are fixed),GET/HEAD,PUT,DELETE.REPORT:calendar-query(VEVENT with optionaltime-range),calendar-multiget,addressbook-query(prop-filter / text-match,anyof/allof,limit),addressbook-multiget. Other reports (for examplesync-collection) return403 DAV:supported-report;sync-tokenis 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-setlists VEVENT) and one address book (vCard 3.0 and 4.0) per account.MKCALENDAR/MKCOLreturn403. 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) orhttps://mail.example.com/dav/, and the mail login and password.
Limits
- Recurring events are not expanded server side: a
time-rangequery 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.