diff --git a/src/headerdef.rs b/src/headerdef.rs
index ca282a81b..f65729c9a 100644
--- a/src/headerdef.rs
+++ b/src/headerdef.rs
@@ -38,6 +38,9 @@ pub enum HeaderDef {
/// Mailing list ID defined in [RFC 2919](https://tools.ietf.org/html/rfc2919).
ListId,
ListPost,
+
+ /// List-Help header defined in [RFC 2369](https://datatracker.ietf.org/doc/html/rfc2369).
+ ListHelp,
References,
/// In-Reply-To header containing Message-ID of the parent message.
diff --git a/src/mimeparser.rs b/src/mimeparser.rs
index 95aab357f..0d1acef8f 100644
--- a/src/mimeparser.rs
+++ b/src/mimeparser.rs
@@ -1365,6 +1365,15 @@ impl MimeMessage {
self.get_mailinglist_header().is_some()
}
+ /// Detects Schleuder mailing list by List-Help header.
+ pub(crate) fn is_schleuder_message(&self) -> bool {
+ if let Some(list_help) = self.get_header(HeaderDef::ListHelp) {
+ list_help == ""
+ } else {
+ false
+ }
+ }
+
pub fn replace_msg_by_error(&mut self, error_msg: &str) {
self.is_system_message = SystemMessage::Unknown;
if let Some(part) = self.parts.first_mut() {
@@ -1593,8 +1602,12 @@ impl MimeMessage {
/// eg. when the user-edited-content is html.
/// As these footers would appear as repeated, separate text-bubbles,
/// we remove them.
+ ///
+ /// We make an exception for Schleuder mailing lists
+ /// because they typically create messages with two text parts,
+ /// one for headers and one for the actual contents.
fn maybe_remove_inline_mailinglist_footer(&mut self) {
- if self.is_mailinglist_message() {
+ if self.is_mailinglist_message() && !self.is_schleuder_message() {
let text_part_cnt = self
.parts
.iter()
@@ -3786,4 +3799,24 @@ Content-Disposition: reaction\n\
Ok(())
}
+
+ #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+ async fn test_schleuder() -> Result<()> {
+ let context = TestContext::new_alice().await;
+ let raw = include_bytes!("../test-data/message/schleuder.eml");
+
+ let msg = MimeMessage::from_bytes(&context.ctx, &raw[..], None)
+ .await
+ .unwrap();
+ assert_eq!(msg.parts.len(), 2);
+
+ // Header part.
+ assert_eq!(msg.parts[0].typ, Viewtype::Text);
+
+ // Actual contents part.
+ assert_eq!(msg.parts[1].typ, Viewtype::Text);
+ assert_eq!(msg.parts[1].msg, "hello,\nbye");
+
+ Ok(())
+ }
}
diff --git a/test-data/message/schleuder.eml b/test-data/message/schleuder.eml
new file mode 100644
index 000000000..bdcbe492a
--- /dev/null
+++ b/test-data/message/schleuder.eml
@@ -0,0 +1,66 @@
+Return-Path:
+Delivered-To: alice@testrun.org
+Date: Tue, 02 Jan 2024 05:00:00 +0000
+From: mailing-list@example.org
+Sender: mailing-list-bounce@example.org
+To: alice@testrun.org
+Message-ID: <87wmss8juz.fsf@example.org>
+In-Reply-To:
+References:
+Subject: [REPOST] Some subject
+Mime-Version: 1.0
+Content-Type: multipart/signed;
+ boundary="--==_mimepart_65938a80866e8_663a2abed9b585c064398";
+ micalg=pgp-sha1;
+ protocol="application/pgp-signature"
+Content-Transfer-Encoding: 7bit
+List-Id:
+List-Owner: (Use list's public
+ key)
+List-Help:
+List-Post:
+
+This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
+----==_mimepart_65938a80866e8_663a2abed9b585c064398
+Content-Type: multipart/mixed;
+ boundary="--==_mimepart_65938a8086476_663a2abed9b585c0642c7";
+ charset=UTF-8
+Content-Transfer-Encoding: 7bit
+
+
+----==_mimepart_65938a8086476_663a2abed9b585c0642c7
+Content-Type: text/plain;
+ charset=UTF-8
+Content-Transfer-Encoding: 7bit
+
+From: bob@example.org
+To: mailing-list@example.org
+Cc:
+Date: Tue, 02 Jan 2024 05:00:00 +0000
+Sig: Unsigned
+Enc: Unencrypted
+
+----==_mimepart_65938a8086476_663a2abed9b585c0642c7
+Content-Type: text/plain;
+ charset=utf-8
+Content-Transfer-Encoding: quoted-printable
+
+hello,
+bye
+
+----==_mimepart_65938a8086476_663a2abed9b585c0642c7--
+
+----==_mimepart_65938a80866e8_663a2abed9b585c064398
+Content-Type: application/pgp-signature;
+ name=signature.asc
+Content-Transfer-Encoding: 7bit
+Content-Disposition: attachment;
+ filename=signature.asc
+Content-Description: OpenPGP digital signature
+
+-----BEGIN PGP SIGNATURE-----
+
+REDACTED
+-----END PGP SIGNATURE-----
+
+----==_mimepart_65938a80866e8_663a2abed9b585c064398--