Files
RustBox/src/smtp/types.rs
T
Mateusz Gruszczyński a643e7e3ab
RustBox CI / rustbox (push) Waiting to run
v0.0.5
2026-10-30 12:06:44 +01:00

156 lines
3.8 KiB
Rust

#[derive(Debug, Clone)]
pub struct SmtpCredentials {
pub host: String,
pub port: u16,
pub tls: bool,
pub tls_verify: bool,
pub email: String,
pub password: String,
}
#[derive(Debug, Clone)]
pub struct SmtpSendResult {
pub message_id: String,
pub rfc822: Vec<u8>,
}
#[derive(Clone)]
pub struct SendableMessage {
pub from: String,
pub to: Vec<String>,
pub cc: Vec<String>,
pub bcc: Vec<String>,
pub reply_to: Option<String>,
pub organization: Option<String>,
pub subject: String,
pub text_body: String,
pub html_body: Option<String>,
pub in_reply_to: Option<String>,
pub references: Option<String>,
pub read_receipt_to: Option<String>,
pub priority: String,
pub extra_headers: Vec<(String, String)>,
pub attachments: Vec<AttachmentData>,
pub pgp: Option<PgpSendConfig>,
pub max_message_size_bytes: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PgpMode {
None,
Sign,
Encrypt,
SignEncrypt,
}
#[derive(Clone)]
pub struct PgpSendConfig {
pub mode: PgpMode,
pub inline: bool,
pub secret_key_armor: Option<String>,
pub passphrase: String,
pub recipient_public_keys: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct AttachmentData {
pub filename: String,
pub content_type: String,
pub data: Vec<u8>,
pub content_id: Option<String>,
}
pub fn apply_optional_headers(
builder: lettre::message::MessageBuilder,
message: &SendableMessage,
) -> lettre::message::MessageBuilder {
use lettre::message::header::{HeaderName, HeaderValue};
let mut builder = apply_optional_header_values(
builder,
message.read_receipt_to.as_deref(),
message.organization.as_deref(),
&message.priority,
);
for (name, value) in &message.extra_headers {
if let Ok(name) = HeaderName::new_from_ascii(name.clone()) {
let clean_value = value
.chars()
.map(|ch| if matches!(ch, '\r' | '\n') { ' ' } else { ch })
.collect::<String>()
.trim()
.to_string();
if !clean_value.is_empty() {
builder = builder.raw_header(HeaderValue::new(name, clean_value));
}
}
}
builder
}
pub fn apply_optional_header_values(
mut builder: lettre::message::MessageBuilder,
read_receipt_to: Option<&str>,
organization: Option<&str>,
priority: &str,
) -> lettre::message::MessageBuilder {
use lettre::message::header::{HeaderName, HeaderValue};
fn clean(value: &str) -> String {
value
.chars()
.map(|ch| if matches!(ch, '\r' | '\n') { ' ' } else { ch })
.collect::<String>()
.trim()
.to_string()
}
fn raw(name: &'static str, value: String) -> HeaderValue {
HeaderValue::new(HeaderName::new_from_ascii_str(name), value)
}
if let Some(address) = read_receipt_to.map(clean).filter(|value| !value.is_empty()) {
builder = builder.raw_header(raw("Disposition-Notification-To", address));
}
if let Some(organization) = organization.map(clean).filter(|value| !value.is_empty()) {
builder = builder.raw_header(raw("Organization", organization));
}
let normalized_priority = priority.trim().to_ascii_lowercase();
match normalized_priority.as_str() {
"high" => {
builder = builder
.raw_header(raw("Importance", "high".to_string()))
.raw_header(raw("X-Priority", "1 (Highest)".to_string()));
}
"low" => {
builder = builder
.raw_header(raw("Importance", "low".to_string()))
.raw_header(raw("X-Priority", "5 (Lowest)".to_string()));
}
_ => {}
}
builder
}