Skip to content
Clone
main
94 lines 2.7 KB Rust
use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Deserialize, Serialize)]
pub struct SmtpConfig {
pub host: String,
#[serde(default = "default_port")]
pub port: u16,
#[serde(default)]
pub security: SmtpSecurity,
pub username: Option<String>,
pub password: Option<String>,
pub from: String,
#[serde(default = "default_timeout")]
pub timeout_seconds: u64,
#[serde(default = "default_max_attachment_bytes")]
pub max_attachment_bytes: usize,
}
impl SmtpConfig {
pub fn connect_timeout(&self) -> std::time::Duration {
std::time::Duration::from_secs(self.timeout_seconds)
}
pub fn is_valid(&self) -> Result<(), String> {
if self.host.trim().is_empty() {
return Err("smtp.host must be set".to_string());
}
if self.port == 0 {
return Err("smtp.port must be greater than 0".to_string());
}
let from = self.from.trim();
if from.is_empty() {
return Err("smtp.from must be set".to_string());
}
if !from.contains('@') {
return Err(format!("smtp.from is invalid: {from:?}"));
}
if self.timeout_seconds == 0 {
return Err("smtp.timeout_seconds must be greater than 0".to_string());
}
if self.max_attachment_bytes == 0 {
return Err("smtp.max_attachment_bytes must be greater than 0".to_string());
}
if self.security == SmtpSecurity::Plain && matches!(self.port, 465 | 994) {
return Err(format!(
"smtp.port {} speaks implicit TLS, set smtp.security to tls",
self.port
));
}
Ok(())
}
}
impl fmt::Debug for SmtpConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SmtpConfig")
.field("host", &self.host)
.field("port", &self.port)
.field("security", &self.security)
.field("username", &self.username)
.field("password", &self.password.as_ref().map(|_| "[REDACTED]"))
.field("from", &self.from)
.field("timeout_seconds", &self.timeout_seconds)
.field("max_attachment_bytes", &self.max_attachment_bytes)
.finish()
}
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SmtpSecurity {
#[default]
StartTls,
Tls,
Plain,
}
fn default_port() -> u16 {
587
}
fn default_timeout() -> u64 {
30
}
fn default_max_attachment_bytes() -> usize {
26_214_400
}
impl crate::loader::Section for SmtpConfig {
const KEY: &'static str = "smtp";
}