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