Issue Description
Apple Contacts syncs nothing against Stalwart and shows an empty address book,
with no error on either side. The cause is the default vCard version.
Apple’s CardDAV client asks for address-data without naming a version.
Stalwart then serialises vCard 4.0, which Apple Contacts cannot store. It
downloads every card, discards all of them, and reports the sync as finished.
What made this hard to find is that everything else is correct. I went through
principal discovery, addressbook-home-set, resourcetype, getctag, sync-token,
the initial sync-collection REPORT and addressbook-multiget, and Stalwart
answered properly every time. I was convinced the fault was on the client until
I read the actual traffic through a local proxy and saw the VERSION line.
Expected Behavior
When a client requests address-data without a version attribute, I would expect
vCard 3.0, or at least a way to configure the default. RFC 6352 leaves the
choice to the server, and 3.0 appears to be what other implementations settle
on precisely because Apple clients cannot handle 4.0.
Actual Behavior
address-data comes back as VERSION:4.0 whenever the client names no version.
Every Apple client therefore syncs nothing, silently. DAVx5 on Android and
iPadOS are unaffected because they request a version explicitly.
Reproduction Steps
-
Create an account with an address book containing a few contacts.
-
Ask for a card without naming a version:
curl -u USER:PASS -X REPORT -H ‘Depth: 1’ -H ‘Content-Type: application/xml’
-d ‘<?xml version="1.0"?><c:addressbook-multiget xmlns:d=“DAV:”
xmlns:c=“urn:ietf:params:xml:ns:carddav”><d:prop><d:getetag/>
<c:address-data/></d:prop><d:href>HREF</d:href></c:addressbook-multiget>’
https://HOST/dav/card/USER/default/ | grep -o ‘VERSION:[0-9.]*’→ VERSION:4.0
-
Repeat with <c:address-data content-type=“text/vcard” version=“3.0”/>
→ VERSION:3.0
-
Add the address book to Apple Contacts on macOS. All cards transfer, none
appear, and the sync is reported as complete.
Relevant Log Output
None, and that is part of the problem. Every request succeeds, so the server
log shows nothing but ordinary traffic:
INFO Authentication successful (auth.success) listenerId = “http”,
localPort = 8080, accountName = “…”, details = “Authenticated with app password”
On the client side macOS logs “Sync of source complete” and exits 0. Neither
end reports anything wrong.
Stalwart Version
v0.16.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
supported-address-data advertises 4.0, 3.0 and 2.1, in that order.
My workaround is a small local proxy on the Mac that inserts
version=“3.0” into every address-data element that doesn’t already have one.
That fixes it completely, which is what confirms the diagnosis.
Happy to test a patch.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
on