Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: Do not copy Chat-Version header into outer part
Chat-Version is used sometimes by Sieve filters to move messages to DeltaChat folder:
https://github.com/mailcow/mailcow-dockerized/blob/37beed6ad93f259b97cad41877982bce95295629/data/conf/dovecot/global_sieve_before
This probably prevents notifications to MUAs that don't watch DeltaChat but watch INBOX.

There are however disadvantages to exposing Chat-Version:
1. Spam filters may not like this header and it is difficult or impossible to tell if `Chat-Version`
   plays role in rejecting the message or delivering it into Spam folder. If there is no such header
   visible to the spam filter, this possibility can be ruled out.
2. Replies to chat messages may have no `Chat-Version` but have to be moved anyway.
3. The user may have no control over the Sieve filter, but it comes preconfigured in mailcow, so it
   is not possible to disable it on the client.

Thanks to link2xt for providing this motivation.

NOTE: Old Delta Chat will assign partially downloaded replies to an ad-hoc group with the sender
instead of the 1:1 chat, but we're removing partial downloads anyway.
  • Loading branch information
iequidoo committed Nov 14, 2025
commit a9949f87c240cc3b7f33c636b0fd69290bd99871
9 changes: 2 additions & 7 deletions src/mimefactory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,8 +947,7 @@ impl MimeFactory {
//
// These are standard headers such as Date, In-Reply-To, References, which cannot be placed
// anywhere else according to the standard. Placing headers here also allows them to be fetched
// individually over IMAP without downloading the message body. This is why Chat-Version is
// placed here.
// individually over IMAP without downloading the message body.
let mut unprotected_headers: Vec<(&'static str, HeaderType<'static>)> = Vec::new();

// Headers that MUST NOT (only) go into IMF header section:
Expand Down Expand Up @@ -1063,11 +1062,7 @@ impl MimeFactory {
mail_builder::headers::raw::Raw::new("[...]").into(),
));
}
"in-reply-to"
| "references"
| "auto-submitted"
| "chat-version"
| "autocrypt-setup-message" => {
"in-reply-to" | "references" | "auto-submitted" | "autocrypt-setup-message" => {
unprotected_headers.push(header.clone());
}
_ => {
Expand Down
12 changes: 10 additions & 2 deletions src/receive_imf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2414,7 +2414,14 @@ async fn lookup_chat_by_reply(

// If this was a private message just to self, it was probably a private reply.
// It should not go into the group then, but into the private chat.
if is_probably_private_reply(context, mime_parser, parent_chat_id).await? {
if is_probably_private_reply(
context,
mime_parser,
is_partial_download.is_some(),
parent_chat_id,
)
.await?
{
return Ok(None);
}

Expand Down Expand Up @@ -2561,6 +2568,7 @@ async fn lookup_or_create_adhoc_group(
async fn is_probably_private_reply(
context: &Context,
mime_parser: &MimeMessage,
is_partial_download: bool,
parent_chat_id: ChatId,
) -> Result<bool> {
// Message cannot be a private reply if it has an explicit Chat-Group-ID header.
Expand All @@ -2579,7 +2587,7 @@ async fn is_probably_private_reply(
return Ok(false);
}

if !mime_parser.has_chat_version() {
if !is_partial_download && !mime_parser.has_chat_version() {
let chat_contacts = chat::get_chat_contacts(context, parent_chat_id).await?;
if chat_contacts.len() == 2 && chat_contacts.contains(&ContactId::SELF) {
return Ok(false);
Expand Down