From 3df1e3712a9e6b1149edd27e5ab9a94c71425dff Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 20 Aug 2026 00:22:50 +0000 Subject: [PATCH] fix: send legacy securejoin key requests as multipart/mixed chatmail relays (filtermail) expect {vc,vg}-request messages to be multipart/mixed with a single part. Messages had this structure before commit e0494b0b376a0ae60c6a369271ce595f240f32af so we need to keep it for compatibility. --- src/mimefactory.rs | 17 +++++++++++++++++ src/securejoin/securejoin_tests.rs | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 3f987ee98..eac134f80 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -1560,6 +1560,23 @@ impl MimeFactory { // that normally only allows encrypted mails. message } else { + // Unencrypted message. + let message = if let Loaded::Message { msg, .. } = &self.loaded + && msg.param.get_cmd() == SystemMessage::SecurejoinMessage + && matches!( + msg.param.get(Param::Arg), + Some("vc-request") | Some("vg-request") + ) { + // Workaround for legacy SecureJoin {vc,vg}-request messages. + // They must be sent as multipart/mixed + // for compatibility with chatmail relays + // that allow to send these messages unencrypted, + // but only as long as they have this MIME structure. + MimePart::new("multipart/mixed", vec![message]) + } else { + message + }; + headers.iter().fold(message, |message, (header, value)| { debug_assert_ne!(*header, "from"); debug_assert_ne!(*header, "message-id"); diff --git a/src/securejoin/securejoin_tests.rs b/src/securejoin/securejoin_tests.rs index 270559c65..f5801dd68 100644 --- a/src/securejoin/securejoin_tests.rs +++ b/src/securejoin/securejoin_tests.rs @@ -494,6 +494,11 @@ async fn test_secure_join_group_ext(v3: bool, remove_invite: bool) -> Result<()> "vg-request" } ); + if !v3 { + // Legacy {vc,vg}-request should be sent as multipart/mixed + // to pass chatmail relay filters. + assert!(sent.payload.contains("Content-Type: multipart/mixed")); + } assert_eq!(msg.get_header(HeaderDef::SecureJoinAuth).is_some(), v3); assert_eq!( msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some(),