Issue Description
When using the CardDav account all german umlauts (äöüß) are not rendered correct & displayed. For e.g. Bökelberg becomse Bökelberg etc.
Furthermore not all contacts are synced in total (508 in adress book, only 489 are synced)
Expected Behavior
Umlauts are displayed correct & all contacts are synced
Actual Behavior
Umlauts are not displayed correct & contacts are missing.
Reproduction Steps
- Create a contact with a german umlaut
- Sync the CardDav address book with this contact to your iPhone
Stalwart Version
v0.16.x
Installation Method
Binary (Linux)
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
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
The server is already correctly setting Content-Type: text/vcard; charset=utf-8 in its CardDAV GET response. This means the garbled display (Bökelberg instead of Bökelberg) is a classic double-encoding or charset mismatch issue happening on the iOS side or during the initial import into Stalwart, not in the server’s wire response.
Here are the two likely causes and what to check:
1. Corrupted data at import time
The garbling pattern ö for ö is the classic signature of UTF-8 bytes being interpreted as Latin-1/ISO-8859-1 at some point. If you imported your contacts from a .vcf file that was saved as Latin-1 (or had no explicit charset declaration), the non-ASCII characters may have been stored incorrectly in Stalwart’s database from the start. To verify: check one of the affected contacts in the Stalwart WebUI directly. If the umlaut looks wrong there too, the problem is in the stored data, not in sync.
2. The source .vcf file or export encoding
If you exported contacts from another app/server as vCard 2.1, those files sometimes use CHARSET=ISO-8859-1 parameters on individual fields (which vCard 2.1 allowed). When re-imported into a server that treats everything as UTF-8, this can produce the exact garbling you describe.
For the missing contacts (508 vs 489): This is a separate issue. It would help to know whether those contacts are visible in the Stalwart WebUI or if they are entirely absent, to distinguish between a sync/pagination issue and an import-loss issue.
Recommended next steps:
- Open one affected contact in the Stalwart WebUI – if the umlaut is already wrong there, the fix is to re-import your contacts from a clean UTF-8 encoded
.vcf export.
- Use a tool like
file -i yourcontacts.vcf or open it in a hex editor to confirm the source file’s encoding before re-importing.
- For the missing 19 contacts, check whether they appear in the WebUI address book. If they do appear there but not on iOS, that may be a separate CardDAV sync/pagination bug worth reporting with HTTP logs.
This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.
Checked the Web-UI, the characters are display correct there as they are also displayed correct in my email client (eM Client).
The number of contacts in the WebUI address book matches the number of contacts in the email client too.
This has been fixed. The fix will be included in v0.16.7.
Thanks for the reply. I’ve analyzed this further & the main issue is that iOS can only parse vCard v3.0 & the serialized vCard that Stalwart is sending is a v4.0
grep -aoE ‘VERSION:[0-9.]+’ /tmp/all.xml | sort | uniq -c
508 VERSION:4.0
Can you confirm this behavior?
I’ve tested the 0.16.7 & sadly the error is not fixed. One issue is that Stalwart is always delivering VERSION:4.0 vCards even if we explicitly ask for a v3 version. This can be easily tested with the following curl call:
curl -su ‘yourmail:app_password’ -X REPORT -H “Depth: 1”
-H ‘Content-Type: application/xml’
–data ‘<C:addressbook-query xmlns:D=“DAV:” xmlns:C=“urn:ietf:params:xml:ns:carddav”><D:prop><C:address-data content-type=“text/vcard” version=“3.0”/></D:prop><C:filter><C:prop-filter name=“UID”/></C:filter></C:addressbook-query>’
“``https://stalwart.cloud-fuchs.eu/dav/card/yourmail/default/”`` -o /tmp/v3.xml
grep -aoE ‘VERSION:[0-9.]+’ /tmp/v3.xml | sort | uniq -c
508 VERSION:4.0
As per RFC 6352 chapter 5.1.1 the server has to respect the negotiation of the client:
"*Servers might support more than one primary media type for address
object resources, for example, vCard v3.0 and vCard v4.0. In such
cases, servers have to accept all media types that they advertise via
the CARDDAV:supported-address-data WebDAV property (see
Section 6.2.2).
However, clients can use standard HTTP content negotiation behavior
(the Accept request header defined in Section 14.1 of [RFC2616]) to
request that an address object resource’s data be returned in a
specific media type format. For example, a client merely capable of
handling vCard v3.0 would only want to have address object resources
returned in v3.0 format.*"
Source: RFC 6352 - 5.1.1