///|
/// The high-level SMTP client: drives a full session over a `SmtpTransport`
/// from a rendered message and an envelope, and returns the diagnostic trace.
pub struct SmtpClient[T] {
session : SmtpSession[T]
}
///|
pub fn[T] SmtpClient::new(transport : T, config : SmtpConfig) -> SmtpClient[T] {
{ session: SmtpSession::new(transport, config) }
}
///|
/// Access the underlying session (and through it the transport), for
/// inspection in tests and tooling.
pub fn[T] SmtpClient::session(self : SmtpClient[T]) -> SmtpSession[T] {
self.session
}
///|
/// Access the transport captured inside the client (post-send state).
pub fn[T] SmtpClient::transport(self : SmtpClient[T]) -> T {
self.session.transport
}
///|
/// Render a `MailMessage` and send it over the session.
pub async fn[T : SmtpTransport] SmtpClient::send(
self : SmtpClient[T],
message : MailMessage,
envelope : Envelope,
render : RenderConfig,
) -> SmtpTrace raise MailFailure {
let wire = render_message(message, render)
self.send_rendered(wire, envelope)
}
///|
/// Send an already rendered wire message (CRLF line endings) over the session.
/// The message is dot-stuffed and line-length checked before transmission.
pub async fn[T : SmtpTransport] SmtpClient::send_rendered(
self : SmtpClient[T],
wire : String,
envelope : Envelope,
) -> SmtpTrace raise MailFailure {
self.session.connect()
self.session.ehlo()
match self.session.config.auth {
Some(a) => self.session.auth(a)
None => ()
}
// enforce the server SIZE limit and the RFC 5322 998-octet line limit
// before starting the mail transaction
let caps = self.session.caps()
match caps.size {
Some(max) =>
if string_to_bytes(wire).length() > max {
raise MailFailure::content_length(
"message size \{string_to_bytes(wire).length()} exceeds server SIZE limit \{max}",
)
}
None => ()
}
check_line_lengths(wire, 998)
self.session.mail_from(envelope.mail_from())
for path in envelope.rcpt_to() {
self.session.rcpt_to(path)
}
let stuffed = dot_stuff(normalize_crlf(wire))
let lines = to_lines(stuffed)
self.session.send_data(lines)
self.session.quit()
self.session.trace()
}