mailparsing: replace mail-parser dep

This commit is contained in:
Wez Furlong
2023-08-28 11:36:21 -07:00
parent 01996f428b
commit c7eacb63b5
4 changed files with 143 additions and 44 deletions
Generated
-10
View File
@@ -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"
-1
View File
@@ -68,5 +68,4 @@ zstd = "0.12"
[dev-dependencies]
k9 = "0.11"
mail-parser = "0.8"
maplit = "1.0"
+48 -33
View File
@@ -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",
},
},
],
),
),
)
"#
+95
View File
@@ -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)]