///|
/// SMTP authentication mechanism selection.
pub(all) enum AuthMethod {
Login(String, String)
Plain(String, String)
CramMd5(String, String)
} derive(Eq, Debug)
///|
pub fn AuthMethod::username(self : AuthMethod) -> String {
match self {
Login(u, _) => u
Plain(u, _) => u
CramMd5(u, _) => u
}
}
///|
/// Connection configuration for an SMTP session.
pub struct SmtpConfig {
host : String
port : Int
mut auth : AuthMethod?
mut timeout_ms : Int64
mut connect_retries : Int
} derive(Eq, Debug)
///|
pub fn SmtpConfig::new(host : String, port? : Int = 25) -> SmtpConfig {
{ host, port, auth: None, timeout_ms: 30000, connect_retries: 1 }
}
///|
pub fn SmtpConfig::host(self : SmtpConfig) -> String {
self.host
}
///|
pub fn SmtpConfig::port(self : SmtpConfig) -> Int {
self.port
}
///|
pub fn SmtpConfig::auth(self : SmtpConfig) -> AuthMethod? {
self.auth
}
///|
pub fn SmtpConfig::timeout_ms(self : SmtpConfig) -> Int64 {
self.timeout_ms
}
///|
pub fn SmtpConfig::connect_retries(self : SmtpConfig) -> Int {
self.connect_retries
}
///|
pub fn SmtpConfig::with_auth(
self : SmtpConfig,
auth : AuthMethod,
) -> SmtpConfig {
self.auth = Some(auth)
self
}
///|
pub fn SmtpConfig::with_timeout(
self : SmtpConfig,
timeout_ms : Int64,
) -> SmtpConfig {
self.timeout_ms = timeout_ms
self
}
///|
pub fn SmtpConfig::with_connect_retries(
self : SmtpConfig,
retries : Int,
) -> SmtpConfig {
self.connect_retries = retries
self
}
///|
/// The transport abstraction. The SMTP session talks only to this interface:
/// the network adapter (`socket_transport`) and the deterministic scripted
/// server (`FakeTransport`) both implement it. The core never touches a socket
/// directly, so it stays portable across backends.
pub(open) trait SmtpTransport {
///| Establish the connection (and send a greeting for scripted servers).
async fn connect(Self, SmtpConfig) -> Unit raise MailFailure
///| Write one command line (without the trailing CRLF).
async fn write_line(Self, String) -> Unit raise MailFailure
///| Read one response line (without the trailing CRLF).
async fn read_line(Self) -> String raise MailFailure
///| Close the connection (synchronous, like the underlying socket close).
fn close(Self) -> Unit
}