use lettre::message::header::{Header, HeaderName, HeaderValue};
use std::error::Error as StdError;
macro_rules! define_text_header {
($(#[$attr:meta])* $type_name:ident, $header_name:expr) => {
$(#[$attr])*
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct $type_name(String);
impl $type_name {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn value(&self) -> &str {
&self.0
}
}
impl Header for $type_name {
fn name() -> HeaderName {
HeaderName::new_from_ascii_str($header_name)
}
fn parse(s: &str) -> Result<Self, Box<dyn StdError + Send + Sync>> {
Ok(Self(s.to_string()))
}
fn display(&self) -> HeaderValue {
HeaderValue::new(Self::name(), self.0.clone())
}
}
impl From<String> for $type_name {
fn from(s: String) -> Self {
Self(s)
}
}
impl From<&str> for $type_name {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
};
}
define_text_header!(
XMailer,
"X-Mailer"
);
define_text_header!(
XPriority,
"X-Priority"
);
define_text_header!(
ListUnsubscribe,
"List-Unsubscribe"
);
define_text_header!(
ListUnsubscribePost,
"List-Unsubscribe-Post"
);
define_text_header!(
XEntityRefId,
"X-Entity-Ref-ID"
);
define_text_header!(
Precedence,
"Precedence"
);
pub const SUPPORTED_HEADERS: &[&str] = &[
"x-mailer",
"x-priority",
"list-unsubscribe",
"list-unsubscribe-post",
"x-entity-ref-id",
"precedence",
];
pub fn is_supported_header(name: &str) -> bool {
SUPPORTED_HEADERS.contains(&name.to_lowercase().as_str())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_x_mailer() {
let header = XMailer::new("Test Mailer 1.0");
assert_eq!(header.value(), "Test Mailer 1.0");
assert_eq!(format!("{}", XMailer::name()), "X-Mailer");
}
#[test]
fn test_x_priority() {
let header = XPriority::new("1");
assert_eq!(header.value(), "1");
assert_eq!(format!("{}", XPriority::name()), "X-Priority");
}
#[test]
fn test_list_unsubscribe() {
let header = ListUnsubscribe::new("<https://example.com/unsubscribe>");
assert_eq!(header.value(), "<https://example.com/unsubscribe>");
}
#[test]
fn test_list_unsubscribe_post() {
let header = ListUnsubscribePost::new("List-Unsubscribe=One-Click");
assert_eq!(header.value(), "List-Unsubscribe=One-Click");
}
#[test]
fn test_x_entity_ref_id() {
let header = XEntityRefId::new("ref-123");
assert_eq!(header.value(), "ref-123");
}
#[test]
fn test_precedence() {
let header = Precedence::new("bulk");
assert_eq!(header.value(), "bulk");
}
#[test]
fn test_is_supported_header() {
assert!(is_supported_header("X-Mailer"));
assert!(is_supported_header("x-mailer"));
assert!(is_supported_header("X-MAILER"));
assert!(is_supported_header("List-Unsubscribe"));
assert!(!is_supported_header("X-Custom-Header"));
assert!(!is_supported_header("Unknown-Header"));
}
#[test]
fn test_from_string() {
let header: XMailer = "Test".into();
assert_eq!(header.value(), "Test");
let header: XMailer = String::from("Test2").into();
assert_eq!(header.value(), "Test2");
}
#[test]
fn test_header_parse() {
let header = XMailer::parse("Parsed Value").unwrap();
assert_eq!(header.value(), "Parsed Value");
}
}