2023-06-08 19:43:32 +00:00
|
|
|
use std::collections::HashMap;
|
2023-06-12 09:54:15 +00:00
|
|
|
use chrono::{DateTime,FixedOffset,ParseError};
|
|
|
|
|
2023-06-13 11:31:43 +00:00
|
|
|
#[derive(Debug, PartialEq, Default)]
|
2023-06-12 09:54:15 +00:00
|
|
|
pub enum HeaderDate {
|
|
|
|
Parsed(DateTime<FixedOffset>),
|
|
|
|
Unknown(String, ParseError),
|
|
|
|
#[default]
|
|
|
|
None,
|
|
|
|
}
|
2023-06-08 19:43:32 +00:00
|
|
|
|
2023-06-13 07:00:40 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct AddrSpec {
|
|
|
|
pub local_part: String,
|
|
|
|
pub domain: String,
|
|
|
|
}
|
|
|
|
impl AddrSpec {
|
|
|
|
pub fn fully_qualified(&self) -> String {
|
|
|
|
format!("{}@{}", self.local_part, self.domain)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-13 07:18:36 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
2023-06-13 07:00:40 +00:00
|
|
|
pub struct MailboxRef {
|
2023-06-12 14:05:06 +00:00
|
|
|
// The actual "email address" like hello@example.com
|
2023-06-13 07:00:40 +00:00
|
|
|
pub addrspec: AddrSpec,
|
|
|
|
pub name: Option<String>,
|
|
|
|
}
|
|
|
|
impl From<AddrSpec> for MailboxRef {
|
|
|
|
fn from(addr: AddrSpec) -> Self {
|
|
|
|
MailboxRef {
|
|
|
|
name: None,
|
|
|
|
addrspec: addr,
|
|
|
|
}
|
|
|
|
}
|
2023-06-12 14:05:06 +00:00
|
|
|
}
|
|
|
|
|
2023-06-13 11:21:00 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
2023-06-13 07:00:40 +00:00
|
|
|
pub struct GroupRef {
|
|
|
|
pub name: String,
|
2023-06-13 10:25:00 +00:00
|
|
|
pub participants: Vec<MailboxRef>,
|
2023-06-12 14:05:06 +00:00
|
|
|
}
|
|
|
|
|
2023-06-13 11:21:00 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
2023-06-13 07:00:40 +00:00
|
|
|
pub enum AddressRef {
|
|
|
|
Single(MailboxRef),
|
|
|
|
Many(GroupRef),
|
2023-06-12 14:05:06 +00:00
|
|
|
}
|
2023-06-13 10:25:00 +00:00
|
|
|
impl From<MailboxRef> for AddressRef {
|
|
|
|
fn from(mx: MailboxRef) -> Self {
|
|
|
|
AddressRef::Single(mx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl From<GroupRef> for AddressRef {
|
|
|
|
fn from(grp: GroupRef) -> Self {
|
|
|
|
AddressRef::Many(grp)
|
|
|
|
}
|
|
|
|
}
|
2023-06-12 14:05:06 +00:00
|
|
|
|
2023-06-13 13:12:16 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct MessageId<'a> {
|
|
|
|
pub left: &'a str,
|
|
|
|
pub right: &'a str,
|
|
|
|
}
|
|
|
|
|
2023-06-13 20:50:29 +00:00
|
|
|
#[derive(Debug, PartialEq, Default)]
|
2023-06-13 17:35:41 +00:00
|
|
|
pub struct Trace<'a> {
|
2023-06-13 15:47:57 +00:00
|
|
|
// 3.6.7 Traces
|
2023-06-13 20:50:29 +00:00
|
|
|
pub received: Vec<&'a str>,
|
|
|
|
pub return_path: Option<MailboxRef>,
|
2023-06-13 15:47:57 +00:00
|
|
|
|
|
|
|
// 3.6.6. Resent Fields
|
|
|
|
pub resent_date: HeaderDate,
|
|
|
|
pub resent_from: Vec<MailboxRef>,
|
|
|
|
pub resent_sender: Option<MailboxRef>,
|
|
|
|
pub resent_to: Vec<AddressRef>,
|
|
|
|
pub resent_cc: Vec<AddressRef>,
|
|
|
|
pub resent_bcc: Vec<AddressRef>,
|
|
|
|
pub resent_msg_id: Option<MessageId<'a>>,
|
|
|
|
|
|
|
|
// 3.6.8. Optional Fields
|
|
|
|
pub optional: HashMap<&'a str, String>,
|
|
|
|
//pub failed: HashMap<&'a str, String>,
|
|
|
|
//pub garbage: &'a str,
|
|
|
|
}
|
|
|
|
|
2023-06-12 14:05:06 +00:00
|
|
|
/// Permissive Header Section
|
|
|
|
///
|
|
|
|
/// This is a structure intended for parsing/decoding,
|
|
|
|
/// hence it's support cases where the email is considered
|
|
|
|
/// as invalid according to RFC5322 but for which we can
|
|
|
|
/// still extract some data.
|
2023-06-08 19:43:32 +00:00
|
|
|
#[derive(Debug, Default)]
|
2023-06-13 15:47:57 +00:00
|
|
|
pub struct CommonFields<'a> {
|
2023-06-13 12:44:41 +00:00
|
|
|
// 3.6.1. The Origination Date Field
|
|
|
|
pub date: HeaderDate,
|
|
|
|
|
|
|
|
// 3.6.2. Originator Fields
|
2023-06-13 07:00:40 +00:00
|
|
|
pub from: Vec<MailboxRef>,
|
|
|
|
pub sender: Option<MailboxRef>,
|
|
|
|
pub reply_to: Vec<AddressRef>,
|
2023-06-13 12:44:41 +00:00
|
|
|
|
|
|
|
// 3.6.3. Destination Address Fields
|
|
|
|
pub to: Vec<AddressRef>,
|
|
|
|
pub cc: Vec<AddressRef>,
|
|
|
|
pub bcc: Vec<AddressRef>,
|
|
|
|
|
2023-06-13 13:43:14 +00:00
|
|
|
// 3.6.4. Identification Fields
|
|
|
|
pub msg_id: Option<MessageId<'a>>,
|
|
|
|
pub in_reply_to: Vec<MessageId<'a>>,
|
|
|
|
pub references: Vec<MessageId<'a>>,
|
2023-06-13 14:22:04 +00:00
|
|
|
|
|
|
|
// 3.6.5. Informational Fields
|
|
|
|
pub subject: Option<String>,
|
|
|
|
pub comments: Vec<String>,
|
|
|
|
pub keywords: Vec<String>,
|
|
|
|
|
|
|
|
// 3.6.8. Optional Fields
|
2023-06-08 19:43:32 +00:00
|
|
|
pub optional: HashMap<&'a str, String>,
|
2023-06-13 15:47:57 +00:00
|
|
|
//pub failed: HashMap<&'a str, String>,
|
|
|
|
//pub garbage: &'a str,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct HeaderSection<'a> {
|
|
|
|
// 3.6.7 Traces
|
2023-06-13 17:35:41 +00:00
|
|
|
pub traces: Vec<Trace<'a>>,
|
2023-06-13 15:47:57 +00:00
|
|
|
|
|
|
|
// 3.6.x
|
2023-06-13 17:35:41 +00:00
|
|
|
pub common: CommonFields<'a>,
|
2023-06-12 09:54:15 +00:00
|
|
|
}
|