diff --git a/src/mimefactory.rs b/src/mimefactory.rs index a95861c20..05b85180f 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -607,10 +607,7 @@ impl MimeFactory { || to.len() + past_members.len() == self.member_timestamps.len() ); if to.is_empty() { - to.push(Address::new_group( - Some("hidden-recipients".to_string()), - Vec::new(), - )); + to.push(hidden_recipients()); } // Start with Internet Message Format headers in the order of the standard example @@ -888,21 +885,23 @@ impl MimeFactory { } else if header_name == "to" { protected_headers.push(header.clone()); if is_encrypted { + let mut to_without_names = to + .clone() + .into_iter() + .filter_map(|header| match header { + Address::Address(mb) => Some(Address::Address(EmailAddress { + name: None, + email: mb.email, + })), + _ => None, + }) + .collect::>(); + if to_without_names.is_empty() { + to_without_names.push(hidden_recipients()); + } unprotected_headers.push(( original_header_name, - Address::new_list( - to.clone() - .into_iter() - .filter_map(|header| match header { - Address::Address(mb) => Some(Address::Address(EmailAddress { - name: None, - email: mb.email, - })), - _ => None, - }) - .collect::>(), - ) - .into(), + Address::new_list(to_without_names).into(), )); } else { unprotected_headers.push(header.clone()); @@ -1633,6 +1632,10 @@ impl MimeFactory { } } +fn hidden_recipients() -> Address<'static> { + Address::new_group(Some("hidden-recipients".to_string()), Vec::new()) +} + async fn build_body_file(context: &Context, msg: &Message) -> Result> { let file_name = msg.get_filename().context("msg has no file")?; let suffix = Path::new(&file_name) diff --git a/src/mimefactory/mimefactory_tests.rs b/src/mimefactory/mimefactory_tests.rs index 47f7b8613..b8cc6af00 100644 --- a/src/mimefactory/mimefactory_tests.rs +++ b/src/mimefactory/mimefactory_tests.rs @@ -898,3 +898,23 @@ async fn test_dont_remove_self() -> Result<()> { Ok(()) } + +/// Regression test: mimefactory should never create an empty to header, +/// also not if the Selftalk parameter is missing +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_no_empty_to_header() -> Result<()> { + let alice = &TestContext::new_alice().await; + let mut self_chat = alice.get_self_chat().await; + self_chat.param.remove(Param::Selftalk); + self_chat.update_param(alice).await?; + + let payload = alice.send_text(self_chat.id, "Hi").await.payload; + assert!( + // It would be equally fine if the payload contained `To: alice@example.org` or similar, + // as long as it's a valid header + payload.contains("To: \"hidden-recipients\": ;"), + "Payload doesn't contain correct To: header: {payload}" + ); + + Ok(()) +}