1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#![doc = include_str!("../README.md")]
pub mod smtp;
use std::net::IpAddr;
use std::{fmt::Display, hash::Hash, time::Duration};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_rustls::TlsConnector;
#[cfg(feature = "builder")]
pub use mail_builder;
#[cfg(feature = "dkim")]
pub use mail_auth;
#[derive(Debug)]
pub enum Error {
/// I/O error
Io(std::io::Error),
/// TLS error
Tls(Box<rustls::Error>),
/// Base64 decode error
Base64(base64::DecodeError),
// SMTP authentication error.
Auth(smtp::auth::Error),
/// Failure parsing SMTP reply
UnparseableReply,
/// Unexpected SMTP reply.
UnexpectedReply(smtp_proto::Response<String>),
/// SMTP authentication failure.
AuthenticationFailed(smtp_proto::Response<String>),
/// Invalid TLS name provided.
InvalidTLSName,
/// Missing authentication credentials.
MissingCredentials,
/// Missing message sender.
MissingMailFrom,
/// Missing message recipients.
MissingRcptTo,
/// The server does no support any of the available authentication methods.
UnsupportedAuthMechanism,
/// Connection timeout.
Timeout,
/// STARTTLS not available
MissingStartTls,
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(err) => err.source(),
Error::Tls(err) => err.source(),
Error::Base64(err) => err.source(),
_ => None,
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
/// SMTP client builder
#[derive(Clone)]
pub struct SmtpClientBuilder<T: AsRef<str> + PartialEq + Eq + Hash> {
pub timeout: Duration,
pub tls_connector: TlsConnector,
pub tls_hostname: T,
pub tls_implicit: bool,
pub credentials: Option<Credentials<T>>,
pub addr: String,
pub is_lmtp: bool,
pub say_ehlo: bool,
pub local_host: String,
pub local_ip: Option<IpAddr>,
}
/// SMTP client builder
pub struct SmtpClient<T: AsyncRead + AsyncWrite> {
pub stream: T,
pub timeout: Duration,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Credentials<T: AsRef<str> + PartialEq + Eq + Hash> {
Plain { username: T, secret: T },
OAuthBearer { token: T },
XOauth2 { username: T, secret: T },
}
impl Default for Credentials<String> {
fn default() -> Self {
Credentials::Plain {
username: String::new(),
secret: String::new(),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Io(e) => write!(f, "I/O error: {e}"),
Error::Tls(e) => write!(f, "TLS error: {e}"),
Error::Base64(e) => write!(f, "Base64 decode error: {e}"),
Error::Auth(e) => write!(f, "SMTP authentication error: {e}"),
Error::UnparseableReply => write!(f, "Unparseable SMTP reply"),
Error::UnexpectedReply(e) => write!(f, "Unexpected reply: {e}"),
Error::AuthenticationFailed(e) => write!(f, "Authentication failed: {e}"),
Error::InvalidTLSName => write!(f, "Invalid TLS name provided"),
Error::MissingCredentials => write!(f, "Missing authentication credentials"),
Error::MissingMailFrom => write!(f, "Missing message sender"),
Error::MissingRcptTo => write!(f, "Missing message recipients"),
Error::UnsupportedAuthMechanism => write!(
f,
"The server does no support any of the available authentication methods"
),
Error::Timeout => write!(f, "Connection timeout"),
Error::MissingStartTls => write!(f, "STARTTLS extension unavailable"),
}
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::Io(err)
}
}
impl From<base64::DecodeError> for Error {
fn from(err: base64::DecodeError) -> Self {
Error::Base64(err)
}
}
|