mirror of
https://github.com/mailscope/kumomta.git
synced 2026-10-28 09:16:15 +00:00
mailparsing: replace mail-parser dep
This commit is contained in:
Generated
-10
@@ -2456,7 +2456,6 @@ dependencies = [
|
||||
"kumo-server-runtime",
|
||||
"lazy_static",
|
||||
"lruttl",
|
||||
"mail-parser",
|
||||
"maildir",
|
||||
"mailparsing",
|
||||
"maplit",
|
||||
@@ -2722,15 +2721,6 @@ dependencies = [
|
||||
"gethostname",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mail-parser"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4158a1c18963244e083888b21465846dfb68d6170850ed1ab4742edd57c9d47"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maildir"
|
||||
version = "0.6.3"
|
||||
|
||||
@@ -68,5 +68,4 @@ zstd = "0.12"
|
||||
|
||||
[dev-dependencies]
|
||||
k9 = "0.11"
|
||||
mail-parser = "0.8"
|
||||
maplit = "1.0"
|
||||
|
||||
@@ -587,31 +587,34 @@ This is a test message to James Smythe
|
||||
.unwrap();
|
||||
|
||||
println!("{generated}");
|
||||
let parsed = mail_parser::Message::parse(&generated.as_bytes()).unwrap();
|
||||
println!("{parsed:?}");
|
||||
let parsed = MimePart::parse(generated.as_str()).unwrap();
|
||||
println!("{parsed:#?}");
|
||||
|
||||
assert!(parsed.header("MIME-Version").is_some());
|
||||
assert!(parsed.headers().mime_version().unwrap().is_some());
|
||||
|
||||
let structure = parsed.simplified_structure().unwrap();
|
||||
eprintln!("{structure:?}");
|
||||
|
||||
k9::snapshot!(
|
||||
parsed.body_html(0),
|
||||
structure.html,
|
||||
r#"
|
||||
Some(
|
||||
"I am the <b>html</b> text, James Smythe. 👾 <img src="cid:my-image"/>",
|
||||
"I am the <b>html</b> text, James Smythe. 👾 <img src="cid:my-image"/>\r
|
||||
",
|
||||
)
|
||||
"#
|
||||
);
|
||||
k9::snapshot!(
|
||||
parsed.body_text(0),
|
||||
structure.text,
|
||||
r#"
|
||||
Some(
|
||||
"I am the plain text, James Smythe. 😀",
|
||||
"I am the plain text, James Smythe. 😀\r
|
||||
",
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
k9::assert_equal!(parsed.html_body_count(), 1);
|
||||
k9::assert_equal!(parsed.text_body_count(), 1);
|
||||
k9::assert_equal!(parsed.attachment_count(), 1);
|
||||
k9::assert_equal!(structure.attachments.len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -651,40 +654,52 @@ Some(
|
||||
.unwrap();
|
||||
|
||||
println!("{generated}");
|
||||
let parsed = mail_parser::Message::parse(&generated.as_bytes()).unwrap();
|
||||
let parsed = MimePart::parse(generated.as_str()).unwrap();
|
||||
println!("{parsed:?}");
|
||||
|
||||
k9::snapshot!(
|
||||
parsed.header("To"),
|
||||
parsed.headers().to(),
|
||||
r#"
|
||||
Some(
|
||||
Address(
|
||||
Addr {
|
||||
name: Some(
|
||||
"James Smythe",
|
||||
),
|
||||
address: Some(
|
||||
"user@example.com",
|
||||
),
|
||||
},
|
||||
Ok(
|
||||
Some(
|
||||
AddressList(
|
||||
[
|
||||
Mailbox(
|
||||
Mailbox {
|
||||
name: Some(
|
||||
"James Smythe",
|
||||
),
|
||||
address: AddrSpec {
|
||||
local_part: "user",
|
||||
domain: "example.com",
|
||||
},
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
"#
|
||||
);
|
||||
|
||||
k9::snapshot!(
|
||||
parsed.header("From"),
|
||||
parsed.headers().from(),
|
||||
r#"
|
||||
Some(
|
||||
Address(
|
||||
Addr {
|
||||
name: Some(
|
||||
"Sender Name",
|
||||
),
|
||||
address: Some(
|
||||
"from@example.com",
|
||||
),
|
||||
},
|
||||
Ok(
|
||||
Some(
|
||||
MailboxList(
|
||||
[
|
||||
Mailbox {
|
||||
name: Some(
|
||||
"Sender Name",
|
||||
),
|
||||
address: AddrSpec {
|
||||
local_part: "from",
|
||||
domain: "example.com",
|
||||
},
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
"#
|
||||
|
||||
@@ -434,6 +434,101 @@ impl<'a> MimePart<'a> {
|
||||
outro: "".into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a SimplifiedStructure representation of the mime tree,
|
||||
/// with the (probable) primary text/plain and text/html parts
|
||||
/// pulled out, and the remaining parts recorded as a flat
|
||||
/// attachments array
|
||||
pub fn simplified_structure(&'a self) -> Result<SimplifiedStructure<'a>> {
|
||||
let info = Rfc2045Info::new(&self.headers, false)?;
|
||||
|
||||
if let Some(ct) = &info.content_type {
|
||||
if ct.value == "text/plain" {
|
||||
return Ok(SimplifiedStructure {
|
||||
text: match self.body()? {
|
||||
DecodedBody::Text(t) => Some(t),
|
||||
DecodedBody::Binary(_) => {
|
||||
return Err(MailParsingError::BodyParse(
|
||||
"expected text/plain part to be text, but it is binary".to_string(),
|
||||
))
|
||||
}
|
||||
},
|
||||
html: None,
|
||||
headers: &self.headers,
|
||||
attachments: vec![],
|
||||
});
|
||||
}
|
||||
if ct.value == "text/html" {
|
||||
return Ok(SimplifiedStructure {
|
||||
html: match self.body()? {
|
||||
DecodedBody::Text(t) => Some(t),
|
||||
DecodedBody::Binary(_) => {
|
||||
return Err(MailParsingError::BodyParse(
|
||||
"expected text/html part to be text, but it is binary".to_string(),
|
||||
))
|
||||
}
|
||||
},
|
||||
text: None,
|
||||
headers: &self.headers,
|
||||
attachments: vec![],
|
||||
});
|
||||
}
|
||||
if ct.value.starts_with("multipart/") {
|
||||
let mut text = None;
|
||||
let mut html = None;
|
||||
let mut attachments = vec![];
|
||||
|
||||
for p in &self.parts {
|
||||
if let Ok(mut s) = p.simplified_structure() {
|
||||
if s.text.is_some() && text.is_none() {
|
||||
text = s.text;
|
||||
}
|
||||
if s.html.is_some() && html.is_none() {
|
||||
html = s.html;
|
||||
}
|
||||
attachments.append(&mut s.attachments);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(SimplifiedStructure {
|
||||
html,
|
||||
text,
|
||||
headers: &self.headers,
|
||||
attachments,
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(SimplifiedStructure {
|
||||
html: None,
|
||||
text: None,
|
||||
headers: &self.headers,
|
||||
attachments: vec![self.clone()],
|
||||
});
|
||||
}
|
||||
|
||||
// Assume text/plain content-type
|
||||
Ok(SimplifiedStructure {
|
||||
text: match self.body()? {
|
||||
DecodedBody::Text(t) => Some(t),
|
||||
DecodedBody::Binary(_) => {
|
||||
return Err(MailParsingError::BodyParse(
|
||||
"expected text/plain part to be text, but it is binary".to_string(),
|
||||
))
|
||||
}
|
||||
},
|
||||
html: None,
|
||||
headers: &self.headers,
|
||||
attachments: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SimplifiedStructure<'a> {
|
||||
pub text: Option<SharedString<'a>>,
|
||||
pub html: Option<SharedString<'a>>,
|
||||
pub headers: &'a HeaderMap<'a>,
|
||||
pub attachments: Vec<MimePart<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
||||
Reference in New Issue
Block a user