Skip to content
  • Categories
  • Recent
  • Popular
  • Tags
  • Users
  • Groups
  • Documentation
  • Downloads
  • Report a bug
  • GitHub mirror
  • Paid support
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
hMailServer Community Forum
hMailServer 6.3.8 is the current release, signed 2 November 2026. Windows and Linux, and an in-place upgrade from 5.3 or later, but for the original hMailServer's 5.7.Download 6.3.8 Documentation FAQ
  1. Support and discussion for hMailServer
  2. Running hMailServer
  3. Webmail, portal & Control Deck
  4. Calendars, contacts, the directory and shared address books over CalDAV and CardDAV

Calendars, contacts, the directory and shared address books over CalDAV and CardDAV

Scheduled Pinned Locked Moved Webmail, portal & Control Deck
webmailportalcontrol-deckadministration
1 Posts 1 Posters 129 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ProgressiverobotP
    ProgressiverobotP
    Progressiverobot
    hMailServer Team
    wrote on last edited by chris
    #1

    Written for 6.3.4. hMailServer 6.3.8 (2 November 2026) has the web services listener, which serves CalDAV and CardDAV, refuse an address an auto-ban or an IP range bans: it closes the connection with no answer, before the TLS handshake, when the IP range that decides for the address allows none of SMTP, POP3 and IMAP, where up to 6.3.7 a banned address could go on guessing passwords there. So an IP range of your own that allows some addresses nothing now closes CalDAV and CardDAV to them as well: check that these services' clients do not come from one. Loopback and the addresses in WebServicesTrustedProxies are never refused by a range, and a failed sign-in from one of them is counted against the name alone (AccountLockoutThreshold, off by default), never towards a ban of that address. A client that signs in with another spelling of the account's address than the stored one, in more than the case of the letters A to Z, or with white space at either end, may no longer sign in. See the 6.3.8 announcement.

    This topic covers what hMailServer 6.3.4 serves to a phone or a desktop client over CalDAV and CardDAV, and what the webmail's Calendar, Tasks, Contacts and Directory pages do with the same data. The one thing to know first: CalDAV and CardDAV are served on the web-services listener, they take HTTP Basic as the account - its password or an app password - over HTTPS only, and a passkey or single sign-on does not reach them. CardDAV has been there since 6.3.3 with one address book; calendars, several and shared address books, the directory and rooms are all since 6.3.4.

    Setting up a phone or a desktop client

    A client given the mail address finds the server by discovery: /.well-known/carddav and /.well-known/caldav redirect to /dav/, a PROPFIND there answers the principal, and the principal answers the address-book home and the calendar home. iOS, macOS Contacts and Calendar, DAVx5 on Android and Thunderbird all sync what is there. The IMAP logon's lockout and auto-ban apply to the sign-in.

    Which password. An account with a TOTP second factor enrolled uses an app password, because once a secret exists the account password stops being a mailbox credential. Minting an app password on the webmail's Security page asks for the account's own password again, so an account that single sign-on or SCIM made, whose random password nobody was told, needs a password set by an administrator before its person can make an app password for a phone.

    The listener. The web services are off as shipped: WebServicesHttpPort and WebServicesHttpsPort default to 0, and the HTTPS port takes WebServicesCertificateFile and WebServicesPrivateKeyFile. Since 6.3.4 these keys are kept in the database: change them in the Control Panel (Windows), over REST, or on Linux with hmailserver --set-setting NAME=VALUE, not by editing hMailServer.ini. A saved port or certificate waits for a reinitialise or a restart, since the listener binds when it starts.

    On the Devices list a DAV client appears with the protocol dav and its user agent. It has no connection to drop - each request authenticates afresh - so revoking it means revoking the app password behind it.

    Collection What it is
    /dav/calendars/<address>/calendar/ The default calendar, Calendar, made the first time it is asked for
    /dav/calendars/<address>/<name>/ Another calendar of the account's own, made in the webmail or with MKCALENDAR
    /dav/calendars/<address>/shared-<id>/ A calendar another account, or a group, shares with this one
    /dav/addressbooks/<address>/contacts/ The default address book, where a client that has synced since 6.3.3 still finds it
    /dav/addressbooks/<address>/book-<id>/ Another book of the account's own (schema 6079)
    /dav/addressbooks/<address>/shared-<id>/ A book shared with this account, or with the whole domain
    /dav/addressbooks/<address>/directory/ The organisation's directory, read-only (schema 6078)

    Each calendar collection advertises VEVENT and VTODO, so a phone's calendar and its reminders list are the same collection.

    Calendars, events and tasks

    An account has one calendar until it makes more. The Calendars box beside the grid adds one with a name and a colour (POST /api/v1/me/calendars), renames or recolours it and deletes it with its events; the default cannot be deleted. Over CalDAV the colour travels as Apple's calendar-color, so a phone shows the same one, and PROPPATCH sets the name and colour from the phone's side.

    Events. An event takes a title, start and end as wall-clock times in tz (an IANA zone the server knows), all_day, a location and notes, rrule (daily, weekly on chosen days, monthly, yearly, with an interval and an end by count or by date), alarm_minutes and guests. The server writes DTSTART;TZID=<zone> so a weekly 09:00 stays 09:00 across a clock change, and a VALARM for the reminder, which is what CalDAV clients ring for. A repeating event is expanded across daylight saving in any of the 592 zone names the server knows; calendar-query with a time range, calendar-multiget and sync-collection are all answered, with ETags and If-Match. Changing one occurrence alone writes an override; deleting one writes an EXDATE on the master.

    Tasks. The Tasks page lists every VTODO of every calendar the account can see, soonest due first. Ticking one off writes STATUS:COMPLETED, COMPLETED and PERCENT-COMPLETE:100 as a client does. A second calendar is a task list of its own.

    Sharing a calendar, and delegates

    The owner names another account of this server and whether it may write (PUT /api/v1/me/calendars/{id}/shares/{address} with write). The other account sees the calendar in its own Calendars box and in its CalDAV home as shared-{id}/, with owner pointing at the sharer's principal and a current-user-privilege-set of read, or read and write. A read-only share takes no PUT, no event from the page and no PROPPATCH. The sharee leaves with a CalDAV DELETE of shared-{id}/ or from the page.

    Shared with a group. Since schema 6086 the name may be one of the server's groups (hm_groups) instead of an address; a name that is both is the account. The membership is read at the moment a member asks, so somebody added later sees the calendar and somebody removed no longer does. A member cannot leave a group share (403): they leave the group, or the owner takes the share back by the group's name.

    A delegate. A share may be a delegation (delegate: true, which implies write😞 the sharee may answer the owner's invitations on the owner's behalf. The answer is POST /api/v1/me/calendar/events/{id}/reply with partstat ACCEPTED, TENTATIVE or DECLINED, allowed to the owner and to a delegate and refused (403) to a plain writer or a reader. The organiser receives a METHOD:REPLY whose ATTENDEE carries SENT-BY="mailto:<delegate>", From: the owner with Sender: the delegate.

    Free-busy

    An account of the domain can see when a colleague is busy, and nothing else about them. GET /api/v1/me/freebusy?address=<account>&from=<when>&to=<when> answers the busy periods of that account's own calendars - not the ones shared with it - over a window of at most 62 days (400 beyond). An event that is TRANSP:TRANSPARENT or STATUS:CANCELLED, or that the account declined, is left out; a period is tentative when the account's PARTSTAT is TENTATIVE or NEEDS-ACTION, else busy. No title, location or description is answered. Another hosted domain's account, an address nobody has, an inactive account, and an account whose freebusy preference is nobody are one and the same 404, so the route enumerates nothing. The preference is the person's own, in Settings: "Who may see when you are busy".

    Over CalDAV the same computation answers the free-busy-query REPORT on a calendar the caller may read, as one bare VFREEBUSY, over a time-range that needs both bounds and spans at most 62 days. The webmail's event editor draws an availability strip for the guests of a meeting from the same computation.

    Invitations by mail (iMIP)

    An event with guests, saved with "Send invitations by e-mail", mails each guest the event as a text/calendar part with method=REQUEST (RFC 6047) - what Outlook, Gmail and Apple Mail show as an invitation card. Saving a change mails an update with the sequence stepped; deleting the event mails METHOD:CANCEL. A message that carries a text/calendar part or an .ics attachment shows a card with Accept, Maybe, Decline and "Propose a new time" (METHOD:COUNTER).

    Filed on delivery. A METHOD:REQUEST delivered to an account is filed into its default calendar as it arrived (NEEDS-ACTION as a rule) when, and only when, it names the account as an ATTENDEE and not as the organiser. A message flagged as spam files nothing; a REQUEST naming somebody else is not kept; and an account that has never opened a calendar gets nothing filed. A stored copy under the same UID is replaced only by the same or a later SEQUENCE, and never when its ORGANIZER is not the invitation's. A REPLY delivered to the organiser sets that attendee's PARTSTAT in the stored event, so every phone syncing the calendar shows who accepted without anyone opening the mail; a CANCEL delivered to a guest marks the stored copy cancelled.

    Rooms and equipment (since 6.3.4)

    A room or a projector is an account whose kind says so: person (the default), room or equipment, a column of hm_accounts (schema 6101). It is invited like any guest and answers by itself, from its own address, by its booking policy; what it does not decide it leaves to its delegates.

    Where What
    The Control Deck The account editor's General group has a select of the three kinds; a room or equipment gets a Booking policy card
    REST kind on GET and PUT /api/v1/accounts/{address}; the policy at GET and PUT /api/v1/accounts/{address}/booking-policy
    COM (Windows) Account.Kind (0 person, 1 room, 2 equipment), saved by Save(); the booking policy is not on COM
    The Windows Control Panel Does not show it: a room is an ordinary account to it

    From the moment its kind is saved every sign-in as the room is refused, whatever the credential, with the ordinary wrong-password answer. A room with no policy row answers by the defaults:

    Field Default What it decides
    auto_accept true Answer invitations by this policy; false leaves every one for the delegates
    window_days 180 How many days ahead a booking may start, 1 to 1080
    max_duration_minutes 1440 The longest booking; 0 is no limit
    working_hours_only false Only inside the working hours, on the working days
    work_days, work_start, work_end Monday to Friday, 08:00 to 17:00 The working days and hours
    time_zone UTC The zone the working hours are in, such as Europe/London
    allow_conflicts false Accept a booking over another one
    allow_recurring true Accept a recurring meeting
    bookers empty Empty is everyone in this server's own domains; a list is an address, @domain, a distribution list's address or a group's name. An organiser from outside must be named here
    capacity 0 How many people the room seats, shown in the directory; it decides nothing
    delegates none Addresses and group names, each given a delegate share of the room's calendar

    Who is asking. The room first decides whether the invitation's ORGANIZER is who sent it, from what the server recorded when the message arrived and never from a From: header or a MAIL FROM. An organiser at this server's own domains is believed only when the message was submitted by a signed-in session as that account, or as one allowed to send as it; a message sent through an API key is not believed. An organiser from outside is believed only when bookers names the address or its @domain and the message passed DMARC for that domain. SPF on its own is not enough, and with DMARC off no outside organiser is ever believed. Anything else is neither filed nor answered, and the delegates are told, within limits.

    The answer is decided just after delivery, on a work queue of the rooms' own; no delivery and no SMTP answer waits for it. In order: who is asking; may they book; sent automatically (an empty reverse path or Auto-Submitted, never answered); auto_accept; at most 20 answers an hour to one organiser; recurrence; the window; the longest booking; working hours; conflicts, counting every booking the room holds that is not cancelled as busy. Accepted, the booking is filed and a METHOD:REPLY goes from the room's address, marked Auto-Submitted: auto-replied. Declined, the reply carries the reason alone; a conflict says when, never whose. A request left for the delegates is never put into the room's calendar on the sender's word. A room with no delegates keeps what it leaves and tells nobody: name at least one. Two servers sharing one database are not serialised for rooms: run rooms on one node.

    Finding a room. The directory lists a room with its kind and capacity, and its CardDAV card says KIND:location (KIND:device for equipment). Every CalDAV principal says its calendar-user-type - INDIVIDUAL, ROOM or RESOURCE - and the principal-property-search REPORT on /dav/principals/, which is what a client's room finder sends, answers the domain's rooms and equipment. Apple Calendar searches for locations this way; Thunderbird has no room finder. Every request stays in the room's mailbox, and a full mailbox answers nothing more, so give a room a quota and a MessageRetentionDays that suit it.

    Contacts, groups and several address books

    Kept, and other contacts. A contact has a source: manual for what the person added, imported or kept, and collected for every address the person has written to - from the webmail's send and, since 6.3.4, from a mail client over an authenticated SMTP submission. A collected address is offered under Other contacts and by the To, Cc and Bcc completion, and nowhere else: CardDAV serves only what the person kept, so a phone's address book is not filled with everyone ever written to. Keep makes it a contact.

    What a card carries. A card a CardDAV client sends is kept as sent and served back byte for byte. The page reads birthday (BDAY), note, phones (every TEL) and the embedded PHOTO; a photo that is only a URL is not the server's to fetch.

    Groups. A group is a card of kind group - KIND:group in vCard 4.0, X-ADDRESSBOOKSERVER-KIND:group in 3.0 - so a group made on the phone appears in the webmail and the reverse. A group's name in To becomes that group's recipients, so the reader sees the people and not the group. The ceilings hold on both surfaces: 500 members in one group (a card past it is refused 403 CARDDAV:valid-address-data) and 200 groups in one address book (400 over REST, 507 Insufficient Storage over CardDAV). A group is not a distribution list: nothing about it reaches SMTP.

    Several address books, and shared ones. Since schema 6079 the account starts with one book, Contacts, which cannot be deleted, and may have at most 50. The owner shares one from the Contacts page with an address - one account of this server - or with its own domain's name; Can edit makes the share writable, and a book takes at most 200 shares. A domain-wide share aimed at another hosted domain is 403, and a person cannot leave a domain share: only the owner or an administrator removes it. One account holds one address once across all its books, so a contact is moved between books, never copied. Over CardDAV a read-only collection grants read and read-current-user-privilege-set and nothing else, a PUT into it is 403, and DELETE on the collection gives the share back and deletes nobody's contacts. MKCOL is refused: a book is made from the Contacts page or /api/v1/me/address-books. No group is shared, in either direction.

    The backup carries the books and their contacts; hm_addressbookshares is not carried, so the sharing is set again. The Control Panel and the Control Deck have no page for this. An administrator has GET /api/v1/accounts/{address}/address-books, which shows the shape of the sharing and never the contacts, and a route that removes one share, recorded as address-book-share-removed.

    Import and export. The Contacts page imports a vCard file or a CSV, including Google's and Outlook's exports. Export as vCard downloads contacts.vcf; Export as CSV downloads contacts.csv and leaves groups out.

    The organisation's directory

    It is one domain at a time, and always the reader's own: every active account of the domain whose owner has not opted out, and every enabled distribution list, with what is set on top in hm_directory (schema 6078) - job title, department, work telephone, mobile, office, a photo (JPEG, PNG or GIF, at most 100 KB decoded, judged by its bytes), and a note that is the administrator's alone.

    Two switches, both rows of hm_settings and both on by default. DirectoryEnabled is whether the directory is answered at all; turn it off on a server whose one domain holds people who are not one organisation. With it off the webmail hides its Directory page and the CardDAV collection stays, empty, so a subscribed phone syncs to nothing rather than failing every poll. DirectoryUserEditable is whether a person may set their own fields. The opt-out is never what a switch takes away, and it is not invisibility: mail still arrives and the address still works. An administrator changing somebody's opt-out is on the audit trail as directory-opt-out-changed.

    The surfaces. The webmail's Directory page (#/directory); the To completion, which offers the reader's own contacts first and the directory hits after; GET /api/v1/me/directory?q=&limit= for the person and GET and PUT /api/v1/accounts/{address}/directory for the administrator; a Directory entry tab in the Windows Control Panel's account dialog, and the same card in the Control Deck; and the read-only CardDAV collection, where PUT, DELETE and PROPPATCH are refused 403. Nothing is learned from anywhere else: there is no import from Active Directory or LDAP, even on a server that authenticates against one, and no LDAP server for a mail client to search.

    What it does not do

    • No RFC 6638 scheduling (no schedule-inbox or schedule-outbox), no free-busy of a calendar on another server, no per-calendar time zone (calendar-timezone is not kept), no partial calendar-data, and no time-range filter on a VALARM.
    • No ActiveSync and no Exchange Web Services: a phone uses IMAP and SMTP for mail, and CalDAV and CardDAV for the rest.
    • Calendar shares and address-book shares are not in the backup, so set them again after a restore; the booking policy, the books, their contacts and the directory rows are.

    Where to read more

    • Wiki: Connecting a Mail Client, Rooms and Equipment, The Webmail, Ports Reference.
    • Documents: Calendar.md, Contacts.md, SharedAddressBooks.md, Directory.md, RoomsAndEquipment.md.
    • On this forum: The webmail portal at /portal, The Control Deck, Signing in, Connecting a mail client, and the 6.3.4 announcement.
    1 Reply Last reply
    0

    Hello! It looks like you're interested in this conversation, but you don't have an account yet.

    Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

    With your input, this post could be even better 💗

    Register Login
    Reply
    • Reply as topic
    Log in to reply
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes


    hMailServer Community

    The community support forum for hMailServer — the free, open-source mail server for Windows and Linux — maintained by Progressive Robot Ltd. The software is AGPL-3.0 and stays that way; this is where it is discussed, debugged and documented.

    The software

    • Documentation
    • Downloads
    • hMailServer 6.3
    • Source on GitLab

    Getting help

    • Forum rules
    • About this forum
    • Support plans
    • Pay monthly support
    • Talk to Progressive Robot

    Legal

    • Privacy policy
    • Terms and conditions
    • Cookie policy

    Progressive Robot Ltd · 220 Chester Business Park, Heronsway, Chester, Cheshire CH4 9GB, United Kingdom · +44 (0)1244 911212 · [email protected] · VAT 506152326

    Powered by NodeBB

    • Login

    • Don't have an account? Register

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Popular
    • Tags
    • Users
    • Groups
    • Documentation
    • Downloads
    • Report a bug
    • GitHub mirror
    • Paid support