tiny-mailcatcher 0.9.3

A tiny MailCatcher clone
Documentation
use crate::repository::{Message, MessagePart};
use chrono::Utc;
use mailparse::{parse_mail, DispositionType, MailHeaderMap, MailParseError, ParsedMail};

pub fn parse_message(
    sender: &Option<String>,
    recipients: &[String],
    raw_email: &[u8],
) -> Result<Message, MailParseError> {
    let parsed_email = parse_mail(raw_email)?;

    let sender = sender.clone();
    let headers = parsed_email.get_headers();

    let subject = headers.get_first_value("Subject");

    let typ = parsed_email.ctype.mimetype.clone();

    let mut parsed_parts = vec![];
    flatten_parts_into(&mut parsed_parts, &parsed_email);

    let mut parts = vec![];
    let mut part_id = 1;
    for parsed_part in parsed_parts {
        let body = parsed_part.get_body_raw().unwrap().clone();
        parts.push(MessagePart {
            cid: format!("{}.mail", part_id),
            typ: parsed_part.ctype.mimetype.clone(),
            filename: parsed_part
                .ctype
                .params
                .get("name")
                .cloned()
                .unwrap_or_else(|| format!("part{}", part_id)),
            size: body.len(),
            charset: parsed_part.ctype.charset.clone(),
            body,
            is_attachment: parsed_part.get_content_disposition().disposition
                == DispositionType::Attachment,
        });
        part_id += 1;
    }

    Ok(Message {
        id: None,
        size: raw_email.len(),
        charset: parsed_email.ctype.charset.clone(),
        subject,
        sender,
        recipients: recipients.to_owned(),
        created_at: Utc::now(),
        typ,
        parts,
        source: raw_email.to_vec(),
    })
}

fn flatten_parts_into<'e>(vec: &mut Vec<&'e ParsedMail<'e>>, parsed_email: &'e ParsedMail<'e>) {
    for part in &parsed_email.subparts {
        vec.push(part);
        flatten_parts_into(vec, part);
    }
}