diff --git a/src/main.rs b/src/main.rs index 6472fde..1c0161c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,12 +23,15 @@ fn main() -> Result<(), anyhow::Error> { result } }; - let message = mailparse::parse_mail(&input)?.parse()?; - println!("Subject: {}", message.subject.unwrap_or_default()); - if let Some(date) = message.date { + let message = mailparse::parse_mail(&input)?; + println!("Subject: {}", message.subject().unwrap_or_default()); + if let Some(date) = message.date()? { println!("Date: {}", date); } println!("---"); - print!("{}", message.body.unwrap_or_default()); + print!( + "{}", + message.body()?.unwrap_or_default().text.unwrap_or_default() + ); Ok(()) } diff --git a/src/parsing.rs b/src/parsing.rs index e21abb7..d0d399c 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -1,16 +1,15 @@ use mailparse::{DispositionType, MailHeaderMap, ParsedMail}; -#[derive(PartialEq, Eq, Debug)] -pub struct MailMessage { - pub subject: Option, - pub date: Option>, - pub body: Option, +#[derive(PartialEq, Eq, Debug, Default)] +pub struct Body { + pub text: Option, } pub trait ParsedMailExt { fn is_attachment(&self) -> bool; - fn get_body_text(&self) -> Result, anyhow::Error>; - fn parse(&self) -> Result; + fn subject(&self) -> Option; + fn date(&self) -> Result>, anyhow::Error>; + fn body(&self) -> Result, anyhow::Error>; } impl<'a> ParsedMailExt for ParsedMail<'a> { @@ -18,37 +17,34 @@ impl<'a> ParsedMailExt for ParsedMail<'a> { self.get_content_disposition().disposition == DispositionType::Attachment } - fn get_body_text(&self) -> Result, anyhow::Error> { - let mimetype: mime::Mime = self.ctype.mimetype.parse()?; - if self.is_attachment() { - return Ok(None); - } - if mimetype == mime::TEXT_PLAIN { - return Ok(Some(self.get_body()?)); - } - for subpart in &self.subparts { - if let Some(body) = subpart.get_body_text()? { - return Ok(Some(body)); - } - } - Ok(None) + fn subject(&self) -> Option { + self.headers.get_first_value("Subject") } - - fn parse(&self) -> Result { - let subject = self.headers.get_first_value("Subject"); + fn date(&self) -> Result>, anyhow::Error> { let date = self .headers .get_first_value("Date") .map(|s| chrono::DateTime::parse_from_rfc2822(&s)) .transpose()?; + Ok(date) + } - let body = self.get_body_text()?; - let message = MailMessage { - subject, - date, - body, - }; - Ok(message) + fn body(&self) -> Result, anyhow::Error> { + let mimetype: mime::Mime = self.ctype.mimetype.parse()?; + if self.is_attachment() { + return Ok(None); + } + if mimetype == mime::TEXT_PLAIN { + return Ok(Some(Body { + text: Some(self.get_body()?), + })); + } + for subpart in &self.subparts { + if let Some(body) = subpart.body()? { + return Ok(Some(body)); + } + } + Ok(None) } } @@ -151,49 +147,67 @@ TsSbamFrw6EgcMWZw61sb2hhLgo= #[test] fn test_plain_text_body() -> Result<(), anyhow::Error> { - let message = mailparse::parse_mail(TEXT_PLAIN.as_bytes())?.parse()?; - let expected_message = MailMessage { - subject: Some("Plain text body".to_string()), - date: Some( + let message = mailparse::parse_mail(TEXT_PLAIN.as_bytes())?; + assert_eq!(message.subject(), Some("Plain text body".to_string())); + assert_eq!( + message.date()?, + Some( chrono::FixedOffset::east(3600 * 2) .ymd(2021, 7, 17) .and_hms(18, 4, 10), - ), - body: Some("Prostý text.".to_string()), - }; - assert_eq!(message, expected_message); + ) + ); + assert_eq!( + message.body()?, + Some(Body { + text: Some("Prostý text.".to_string()) + }), + ); Ok(()) } #[test] fn test_multipart_alternative_text_body() -> Result<(), anyhow::Error> { - let message = mailparse::parse_mail(MULTIPART_ALTERNATIVE.as_bytes())?.parse()?; - let expected_message = MailMessage { - subject: Some("Plain text with HTML".to_string()), - date: Some( + let message = mailparse::parse_mail(MULTIPART_ALTERNATIVE.as_bytes())?; + assert_eq!(message.subject(), Some("Plain text with HTML".to_string())); + assert_eq!( + message.date()?, + Some( chrono::FixedOffset::east(3600 * 2) .ymd(2021, 7, 17) .and_hms(18, 13, 26), - ), - body: Some("Prostý text.".to_string()), - }; - assert_eq!(message, expected_message); + ) + ); + assert_eq!( + message.body()?, + Some(Body { + text: Some("Prostý text.".to_string()) + }), + ); Ok(()) } #[test] fn test_multipart_mixed_alternative_text_body() -> Result<(), anyhow::Error> { - let message = mailparse::parse_mail(MULTIPART_MIXED_ALTERNATIVE.as_bytes())?.parse()?; - let expected_message = MailMessage { - subject: Some("Plain text with HTML and attachment".to_string()), - date: Some( + let message = mailparse::parse_mail(MULTIPART_MIXED_ALTERNATIVE.as_bytes())?; + assert_eq!( + message.subject(), + Some("Plain text with HTML and attachment".to_string()) + ); + assert_eq!( + message.date()?, + Some( chrono::FixedOffset::east(3600 * 2) .ymd(2021, 7, 17) .and_hms(21, 39, 8), - ), - body: Some("Prostý text.".to_string()), - }; - assert_eq!(message, expected_message); + ) + ); + assert_eq!( + message.body()?, + Some(Body { + text: Some("Prostý text.".to_string()) + }), + ); Ok(()) } }