Something went wrong. Try again.
An IMAP+SMTP gateway for less urgent communications with LLMs
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677//! Helpers for parsing incoming mail and constructing replies.
use mailparse::{MailHeaderMap, ParsedMail};
#[derive(Debug, Clone)]pub struct Headers { pub message_id: Option<String>, pub in_reply_to: Option<String>, pub references: Option<String>, pub subject: Option<String>, pub date: Option<String>,}
pub fn parse_headers(raw: &[u8]) -> Result<Headers, mailparse::MailParseError> { let parsed = mailparse::parse_mail(raw)?; Ok(Headers { message_id: parsed.headers.get_first_value("Message-ID"), in_reply_to: parsed.headers.get_first_value("In-Reply-To"), references: parsed.headers.get_first_value("References"), subject: parsed.headers.get_first_value("Subject"), date: parsed.headers.get_first_value("Date"), })}
/// Parse the full message. Used by the store to pull multiple header/// fields in one pass and to extract the body.pub fn parse_mail(raw: &[u8]) -> Result<ParsedMail<'_>, mailparse::MailParseError> { mailparse::parse_mail(raw)}
pub fn extract_body_text(raw: &[u8]) -> Result<String, mailparse::MailParseError> { let parsed = mailparse::parse_mail(raw)?; flatten_to_text(&parsed)}
fn flatten_to_text(mail: &mailparse::ParsedMail) -> Result<String, mailparse::MailParseError> { let ctype = mail.ctype.mimetype.as_str(); if ctype == "text/plain" { return mail.get_body(); } if ctype == "text/html" { let html = mail.get_body()?; return Ok(html_to_text(&html)); } if ctype.starts_with("multipart/") { for sub in &mail.subparts { let sub_ctype = sub.ctype.mimetype.as_str(); if sub_ctype == "text/plain" { return sub.get_body(); } } for sub in &mail.subparts { let sub_ctype = sub.ctype.mimetype.as_str(); if sub_ctype == "text/html" { return Ok(html_to_text(&sub.get_body()?)); } } } Ok(String::new())}
fn html_to_text(html: &str) -> String { // Very naive: strip tags and decode entities enough for LLM context. let mut out = String::with_capacity(html.len()); let mut in_tag = false; for c in html.chars() { if c == '<' { in_tag = true; } else if c == '>' { in_tag = false; } else if !in_tag { out.push(c); } } out}