From 04bd241ba510b2102edbe81423ebeb83ef010f83 Mon Sep 17 00:00:00 2001 From: Tobias Weiss Date: Tue, 15 Sep 2026 15:30:47 +0200 Subject: [PATCH] fix(mime): Q-encode RFC822 specials in header words Display names such as 'Surname, Firstname [Org]' (a common collected-address convention) were Q-encoded as '=?utf-8?q?Surname=2C_Firstname_[Org]?=' - the comma forces the encode path, but '[' and ']' stayed literal bytes inside the encoded word. Dovecot's rfc822 parser treats that literal '[' as a domain-literal opening, never reaches the real and fabricates a recipient with its MISSING_DOMAIN fallback (mailbox truncated at '[', host lost). SOGo then renders the Dovecot envelope verbatim, e.g. To: 'Surname, Firstname @MISSING_DOMAIN'. Exclude the full RFC 822 specials set (( ) < > [ ] \ . , ; : @ ") from 'printable' so Q-encoding escapes them (=5B/=5D etc.). Verified: 'Surname, Firstname [Org]' now encodes to the round-trip-safe '=?utf-8?q?Surname=2C_Firstname_=5BOrg=5D?=' which Dovecot parses with correct mailbox host. --- sope-mime/NGMime/NGMimeHeaderFieldGenerator.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sope-mime/NGMime/NGMimeHeaderFieldGenerator.m b/sope-mime/NGMime/NGMimeHeaderFieldGenerator.m index 4caddb792..b1ecb22a9 100644 --- a/sope-mime/NGMime/NGMimeHeaderFieldGenerator.m +++ b/sope-mime/NGMime/NGMimeHeaderFieldGenerator.m @@ -25,7 +25,13 @@ static BOOL isPrintable(char ch) { // match printable ASCII-characters according to https://tools.ietf.org/html/rfc2047#section-4.2 - return ch >= 32 && ch < 127 && ch != '=' && ch != '?' && ch != '_' && ch != '.' && ch != ',' && ch != ';' && ch != ':' && ch != '@' && ch != '"'; + // RFC 822 `specials` (`()<>[]:;@\,.")` must also be Q-encoded: a literal `[Org]` + // inside an encoded word breaks Dovecot's rfc822 parser, which then fabricates + // a recipient like `Name @MISSING_DOMAIN` (mailbox truncated at `[`, domain lost). + return ch >= 32 && ch < 127 && ch != '=' && ch != '?' && ch != '_' + && ch != '(' && ch != ')' && ch != '<' && ch != '>' + && ch != '[' && ch != ']' && ch != '\\' + && ch != '.' && ch != ',' && ch != ';' && ch != ':' && ch != '@' && ch != '"'; } @implementation NGMimeHeaderFieldGenerator