Tokio 0.3 support (#485)
* Tokio 0.3 support * Tokio 0.3 TLS support * Tokio 0.3 sendmail transport * Tokio 0.3 file transport * Forgotten re-exports * Tokio 0.3 examples * fix tokio 0.2 file-transport * It works
This commit is contained in:
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -44,6 +44,10 @@ jobs:
|
||||
with:
|
||||
command: test
|
||||
args: --features=tokio02
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --features=tokio03
|
||||
|
||||
check:
|
||||
name: Check
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -58,6 +58,9 @@ async-trait = { version = "0.1", optional = true }
|
||||
tokio02_crate = { package = "tokio", version = "0.2.7", features = ["fs", "process", "tcp", "dns", "io-util"], optional = true }
|
||||
tokio02_native_tls_crate = { package = "tokio-native-tls", version = "0.1", optional = true }
|
||||
tokio02_rustls = { package = "tokio-rustls", version = "0.14", optional = true }
|
||||
tokio03_crate = { package = "tokio", version = "0.3", features = ["fs", "process", "net", "io-util"], optional = true }
|
||||
tokio03_native_tls_crate = { package = "tokio-native-tls", version = "0.2", optional = true }
|
||||
tokio03_rustls = { package = "tokio-rustls", version = "0.20", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
@@ -65,6 +68,7 @@ tracing-subscriber = "0.2.10"
|
||||
glob = "0.3"
|
||||
walkdir = "2"
|
||||
tokio02_crate = { package = "tokio", version = "0.2.7", features = ["macros", "rt-threaded"] }
|
||||
tokio03_crate = { package = "tokio", version = "0.3", features = ["macros", "rt-multi-thread"] }
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
@@ -87,6 +91,9 @@ async-std1 = ["async-std", "async-trait", "async-attributes"]
|
||||
tokio02 = ["tokio02_crate", "async-trait", "futures-io", "futures-util"]
|
||||
tokio02-native-tls = ["tokio02", "native-tls", "tokio02_native_tls_crate"]
|
||||
tokio02-rustls-tls = ["tokio02", "rustls-tls", "tokio02_rustls"]
|
||||
tokio03 = ["tokio03_crate", "async-trait", "futures-io", "futures-util"]
|
||||
tokio03-native-tls = ["tokio03", "native-tls", "tokio03_native_tls_crate"]
|
||||
tokio03-rustls-tls = ["tokio03", "rustls-tls", "tokio03_rustls"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
@@ -115,3 +122,12 @@ required-features = ["smtp-transport", "tokio02", "tokio02-native-tls"]
|
||||
[[example]]
|
||||
name = "tokio02_smtp_starttls"
|
||||
required-features = ["smtp-transport", "tokio02", "tokio02-native-tls"]
|
||||
|
||||
[[example]]
|
||||
name = "tokio03_smtp_tls"
|
||||
required-features = ["smtp-transport", "tokio03", "tokio03-native-tls"]
|
||||
|
||||
[[example]]
|
||||
name = "tokio03_smtp_starttls"
|
||||
required-features = ["smtp-transport", "tokio03", "tokio03-native-tls"]
|
||||
|
||||
|
||||
36
examples/tokio03_smtp_starttls.rs
Normal file
36
examples/tokio03_smtp_starttls.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
// This line is only to make it compile from lettre's examples folder,
|
||||
// since it uses Rust 2018 crate renaming to import tokio.
|
||||
// Won't be needed in user's code.
|
||||
use tokio03_crate as tokio;
|
||||
|
||||
use lettre::{
|
||||
transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio03Connector,
|
||||
Tokio03Transport,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||
.to("Hei <hei@domain.tld>".parse().unwrap())
|
||||
.subject("Happy new async year")
|
||||
.body("Be happy with async!")
|
||||
.unwrap();
|
||||
|
||||
let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string());
|
||||
|
||||
// Open a remote connection to gmail using STARTTLS
|
||||
let mailer = AsyncSmtpTransport::<Tokio03Connector>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
Ok(_) => println!("Email sent successfully!"),
|
||||
Err(e) => panic!("Could not send email: {:?}", e),
|
||||
}
|
||||
}
|
||||
36
examples/tokio03_smtp_tls.rs
Normal file
36
examples/tokio03_smtp_tls.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
// This line is only to make it compile from lettre's examples folder,
|
||||
// since it uses Rust 2018 crate renaming to import tokio.
|
||||
// Won't be needed in user's code.
|
||||
use tokio03_crate as tokio;
|
||||
|
||||
use lettre::{
|
||||
transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio03Connector,
|
||||
Tokio03Transport,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||
.to("Hei <hei@domain.tld>".parse().unwrap())
|
||||
.subject("Happy new async year")
|
||||
.body("Be happy with async!")
|
||||
.unwrap();
|
||||
|
||||
let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string());
|
||||
|
||||
// Open a remote connection to gmail
|
||||
let mailer = AsyncSmtpTransport::<Tokio03Connector>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
Ok(_) => println!("Email sent successfully!"),
|
||||
Err(e) => panic!("Could not send email: {:?}", e),
|
||||
}
|
||||
}
|
||||
37
src/lib.rs
37
src/lib.rs
@@ -18,6 +18,9 @@
|
||||
//! * **tokio02**: Allow to asyncronously send emails using tokio 0.2.x
|
||||
//! * **tokio02-rustls-tls**: Async TLS support with the `rustls` crate using tokio 0.2
|
||||
//! * **tokio02-native-tls**: Async TLS support with the `native-tls` crate using tokio 0.2
|
||||
//! * **tokio03**: Allow to asyncronously send emails using tokio 0.3.x
|
||||
//! * **tokio03-rustls-tls**: Async TLS support with the `rustls` crate using tokio 0.3
|
||||
//! * **tokio03-native-tls**: Async TLS support with the `native-tls` crate using tokio 0.3
|
||||
//! * **async-std1**: Allow to asyncronously send emails using async-std 1.x (SMTP isn't supported yet)
|
||||
//! * **r2d2**: Connection pool for SMTP transport
|
||||
//! * **tracing**: Logging using the `tracing` crate
|
||||
@@ -61,12 +64,19 @@ pub use crate::transport::file::FileTransport;
|
||||
pub use crate::transport::sendmail::SendmailTransport;
|
||||
#[cfg(all(feature = "smtp-transport", feature = "connection-pool"))]
|
||||
pub use crate::transport::smtp::r2d2::SmtpConnectionManager;
|
||||
#[cfg(all(
|
||||
feature = "smtp-transport",
|
||||
any(feature = "tokio02", feature = "tokio03")
|
||||
))]
|
||||
pub use crate::transport::smtp::AsyncSmtpTransport;
|
||||
#[cfg(feature = "smtp-transport")]
|
||||
pub use crate::transport::smtp::SmtpTransport;
|
||||
#[cfg(all(feature = "smtp-transport", feature = "tokio02"))]
|
||||
pub use crate::transport::smtp::{AsyncSmtpTransport, Tokio02Connector};
|
||||
pub use crate::transport::smtp::Tokio02Connector;
|
||||
#[cfg(all(feature = "smtp-transport", feature = "tokio03"))]
|
||||
pub use crate::transport::smtp::Tokio03Connector;
|
||||
pub use crate::{address::Address, transport::stub::StubTransport};
|
||||
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
|
||||
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
|
||||
use async_trait::async_trait;
|
||||
#[cfg(feature = "builder")]
|
||||
use std::convert::TryFrom;
|
||||
@@ -257,6 +267,29 @@ pub trait Tokio02Transport {
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
/// tokio 0.3.x based Transport method for emails
|
||||
#[cfg(feature = "tokio03")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "tokio03")))]
|
||||
#[async_trait]
|
||||
pub trait Tokio03Transport {
|
||||
/// Response produced by the Transport
|
||||
type Ok;
|
||||
/// Error produced by the Transport
|
||||
type Error;
|
||||
|
||||
/// Sends the email
|
||||
#[cfg(feature = "builder")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
|
||||
// TODO take &Message
|
||||
async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
|
||||
let raw = message.formatted();
|
||||
let envelope = message.envelope();
|
||||
self.send_raw(&envelope, &raw).await
|
||||
}
|
||||
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
@@ -90,8 +90,10 @@ pub use self::error::Error;
|
||||
use crate::AsyncStd1Transport;
|
||||
#[cfg(feature = "tokio02")]
|
||||
use crate::Tokio02Transport;
|
||||
#[cfg(feature = "tokio03")]
|
||||
use crate::Tokio03Transport;
|
||||
use crate::{Envelope, Transport};
|
||||
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
|
||||
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
|
||||
use async_trait::async_trait;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
@@ -199,3 +201,19 @@ impl Tokio02Transport for FileTransport {
|
||||
Ok(email_id.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio03")]
|
||||
#[async_trait]
|
||||
impl Tokio03Transport for FileTransport {
|
||||
type Ok = Id;
|
||||
type Error = Error;
|
||||
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
use tokio03_crate::fs;
|
||||
|
||||
let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?;
|
||||
|
||||
fs::write(file, serialized).await?;
|
||||
Ok(email_id.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,10 @@ pub use self::error::Error;
|
||||
use crate::AsyncStd1Transport;
|
||||
#[cfg(feature = "tokio02")]
|
||||
use crate::Tokio02Transport;
|
||||
#[cfg(feature = "tokio03")]
|
||||
use crate::Tokio03Transport;
|
||||
use crate::{Envelope, Transport};
|
||||
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
|
||||
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
|
||||
use async_trait::async_trait;
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
@@ -125,6 +127,21 @@ impl SendmailTransport {
|
||||
.stdout(Stdio::piped());
|
||||
c
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio03")]
|
||||
fn tokio03_command(&self, envelope: &Envelope) -> tokio03_crate::process::Command {
|
||||
use tokio03_crate::process::Command;
|
||||
|
||||
let mut c = Command::new(&self.command);
|
||||
c.kill_on_drop(true);
|
||||
c.arg("-i")
|
||||
.arg("-f")
|
||||
.arg(envelope.from().map(|f| f.as_ref()).unwrap_or("\"\""))
|
||||
.args(envelope.to())
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped());
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SendmailTransport {
|
||||
@@ -204,3 +221,28 @@ impl Tokio02Transport for SendmailTransport {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio03")]
|
||||
#[async_trait]
|
||||
impl Tokio03Transport for SendmailTransport {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
use tokio03_crate::io::AsyncWriteExt;
|
||||
|
||||
let mut command = self.tokio03_command(envelope);
|
||||
|
||||
// Spawn the sendmail command
|
||||
let mut process = command.spawn()?;
|
||||
|
||||
process.stdin.as_mut().unwrap().write_all(&email).await?;
|
||||
let output = process.wait_with_output().await?;
|
||||
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Client(String::from_utf8(output.stderr)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
use super::Tls;
|
||||
use super::{
|
||||
client::AsyncSmtpConnection, ClientId, Credentials, Error, Mechanism, Response, SmtpInfo,
|
||||
};
|
||||
use crate::{Envelope, Tokio02Transport};
|
||||
use crate::Envelope;
|
||||
#[cfg(feature = "tokio02")]
|
||||
use crate::Tokio02Transport;
|
||||
#[cfg(feature = "tokio03")]
|
||||
use crate::Tokio03Transport;
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[derive(Clone)]
|
||||
@@ -14,6 +18,7 @@ pub struct AsyncSmtpTransport<C> {
|
||||
inner: AsyncSmtpClient<C>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[async_trait]
|
||||
impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
|
||||
type Ok = Response;
|
||||
@@ -31,6 +36,24 @@ impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio03")]
|
||||
#[async_trait]
|
||||
impl Tokio03Transport for AsyncSmtpTransport<Tokio03Connector> {
|
||||
type Ok = Response;
|
||||
type Error = Error;
|
||||
|
||||
/// Sends an email
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
let mut conn = self.inner.connection().await?;
|
||||
|
||||
let result = conn.send(envelope, email).await?;
|
||||
|
||||
conn.quit().await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> AsyncSmtpTransport<C>
|
||||
where
|
||||
C: AsyncSmtpConnector,
|
||||
@@ -41,11 +64,16 @@ where
|
||||
///
|
||||
/// Creates an encrypted transport over submissions port, using the provided domain
|
||||
/// to validate TLS certificates.
|
||||
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
|
||||
#[cfg(any(
|
||||
feature = "tokio02-native-tls",
|
||||
feature = "tokio02-rustls-tls",
|
||||
feature = "tokio03-native-tls",
|
||||
feature = "tokio03-rustls-tls"
|
||||
))]
|
||||
pub fn relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
|
||||
use super::{TlsParameters, SUBMISSIONS_PORT};
|
||||
|
||||
let tls_parameters = TlsParameters::builder(relay.into()).build_tokio02()?;
|
||||
let tls_parameters = TlsParameters::new(relay.into())?;
|
||||
|
||||
Ok(Self::builder_dangerous(relay)
|
||||
.port(SUBMISSIONS_PORT)
|
||||
@@ -63,7 +91,12 @@ where
|
||||
///
|
||||
/// An error is returned if the connection can't be upgraded. No credentials
|
||||
/// or emails will be sent to the server, protecting from downgrade attacks.
|
||||
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
|
||||
#[cfg(any(
|
||||
feature = "tokio02-native-tls",
|
||||
feature = "tokio02-rustls-tls",
|
||||
feature = "tokio03-native-tls",
|
||||
feature = "tokio03-rustls-tls"
|
||||
))]
|
||||
pub fn starttls_relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
|
||||
use super::{TlsParameters, SUBMISSION_PORT};
|
||||
|
||||
@@ -133,7 +166,12 @@ impl AsyncSmtpTransportBuilder {
|
||||
}
|
||||
|
||||
/// Set the TLS settings to use
|
||||
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
|
||||
#[cfg(any(
|
||||
feature = "tokio02-native-tls",
|
||||
feature = "tokio02-rustls-tls",
|
||||
feature = "tokio03-native-tls",
|
||||
feature = "tokio03-rustls-tls"
|
||||
))]
|
||||
pub fn tls(mut self, tls: Tls) -> Self {
|
||||
self.info.tls = tls;
|
||||
self
|
||||
@@ -235,6 +273,48 @@ impl AsyncSmtpConnector for Tokio02Connector {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
#[cfg(feature = "tokio03")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "tokio03")))]
|
||||
pub struct Tokio03Connector;
|
||||
|
||||
#[async_trait]
|
||||
#[cfg(feature = "tokio03")]
|
||||
impl AsyncSmtpConnector for Tokio03Connector {
|
||||
async fn connect(
|
||||
hostname: &str,
|
||||
port: u16,
|
||||
hello_name: &ClientId,
|
||||
tls: &Tls,
|
||||
) -> Result<AsyncSmtpConnection, Error> {
|
||||
#[allow(clippy::match_single_binding)]
|
||||
let tls_parameters = match tls {
|
||||
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
|
||||
Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
|
||||
_ => None,
|
||||
};
|
||||
#[allow(unused_mut)]
|
||||
let mut conn =
|
||||
AsyncSmtpConnection::connect_tokio03(hostname, port, hello_name, tls_parameters)
|
||||
.await?;
|
||||
|
||||
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
|
||||
match tls {
|
||||
Tls::Opportunistic(ref tls_parameters) => {
|
||||
if conn.can_starttls() {
|
||||
conn.starttls(tls_parameters.clone(), hello_name).await?;
|
||||
}
|
||||
}
|
||||
Tls::Required(ref tls_parameters) => {
|
||||
conn.starttls(tls_parameters.clone(), hello_name).await?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
use super::*;
|
||||
|
||||
@@ -242,4 +322,7 @@ mod private {
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
impl Sealed for Tokio02Connector {}
|
||||
|
||||
#[cfg(feature = "tokio03")]
|
||||
impl Sealed for Tokio03Connector {}
|
||||
}
|
||||
|
||||
@@ -45,11 +45,10 @@ impl AsyncSmtpConnection {
|
||||
&self.server_info
|
||||
}
|
||||
|
||||
// FIXME add simple connect and rename this one
|
||||
|
||||
/// Connects to the configured server
|
||||
///
|
||||
/// Sends EHLO and parses server information
|
||||
#[cfg(feature = "tokio02")]
|
||||
pub async fn connect_tokio02(
|
||||
hostname: &str,
|
||||
port: u16,
|
||||
@@ -60,6 +59,20 @@ impl AsyncSmtpConnection {
|
||||
Self::connect_impl(stream, hello_name).await
|
||||
}
|
||||
|
||||
/// Connects to the configured server
|
||||
///
|
||||
/// Sends EHLO and parses server information
|
||||
#[cfg(feature = "tokio03")]
|
||||
pub async fn connect_tokio03(
|
||||
hostname: &str,
|
||||
port: u16,
|
||||
hello_name: &ClientId,
|
||||
tls_parameters: Option<TlsParameters>,
|
||||
) -> Result<AsyncSmtpConnection, Error> {
|
||||
let stream = AsyncNetworkStream::connect_tokio03(hostname, port, tls_parameters).await?;
|
||||
Self::connect_impl(stream, hello_name).await
|
||||
}
|
||||
|
||||
async fn connect_impl(
|
||||
stream: AsyncNetworkStream,
|
||||
hello_name: &ClientId,
|
||||
|
||||
@@ -8,17 +8,30 @@ use std::{
|
||||
|
||||
use futures_io::{Error as IoError, ErrorKind, Result as IoResult};
|
||||
#[cfg(feature = "tokio02")]
|
||||
use tokio02_crate::io::{AsyncRead, AsyncWrite};
|
||||
use tokio02_crate::io::{AsyncRead as _, AsyncWrite as _};
|
||||
#[cfg(feature = "tokio02")]
|
||||
use tokio02_crate::net::TcpStream;
|
||||
use tokio02_crate::net::TcpStream as Tokio02TcpStream;
|
||||
#[cfg(feature = "tokio03")]
|
||||
use tokio03_crate::io::{AsyncRead as _, AsyncWrite as _, ReadBuf as Tokio03ReadBuf};
|
||||
#[cfg(feature = "tokio03")]
|
||||
use tokio03_crate::net::TcpStream as Tokio03TcpStream;
|
||||
|
||||
#[cfg(feature = "tokio02-native-tls")]
|
||||
use tokio02_native_tls_crate::TlsStream;
|
||||
use tokio02_native_tls_crate::TlsStream as Tokio02TlsStream;
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
use tokio03_native_tls_crate::TlsStream as Tokio03TlsStream;
|
||||
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
use tokio02_rustls::client::TlsStream as RustlsTlsStream;
|
||||
use tokio02_rustls::client::TlsStream as Tokio02RustlsTlsStream;
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
use tokio03_rustls::client::TlsStream as Tokio03RustlsTlsStream;
|
||||
|
||||
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
|
||||
#[cfg(any(
|
||||
feature = "tokio02-native-tls",
|
||||
feature = "tokio02-rustls-tls",
|
||||
feature = "tokio03-native-tls",
|
||||
feature = "tokio03-rustls-tls"
|
||||
))]
|
||||
use super::InnerTlsParameters;
|
||||
use super::TlsParameters;
|
||||
use crate::transport::smtp::Error;
|
||||
@@ -31,15 +44,24 @@ pub struct AsyncNetworkStream {
|
||||
/// Represents the different types of underlying network streams
|
||||
#[allow(dead_code)]
|
||||
enum InnerAsyncNetworkStream {
|
||||
/// Plain TCP stream
|
||||
/// Plain Tokio 0.2 TCP stream
|
||||
#[cfg(feature = "tokio02")]
|
||||
Tokio02Tcp(TcpStream),
|
||||
/// Encrypted TCP stream
|
||||
Tokio02Tcp(Tokio02TcpStream),
|
||||
/// Encrypted Tokio 0.2 TCP stream
|
||||
#[cfg(feature = "tokio02-native-tls")]
|
||||
Tokio02NativeTls(TlsStream<TcpStream>),
|
||||
/// Encrypted TCP stream
|
||||
Tokio02NativeTls(Tokio02TlsStream<Tokio02TcpStream>),
|
||||
/// Encrypted Tokio 0.2 TCP stream
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
Tokio02RustlsTls(Box<RustlsTlsStream<TcpStream>>),
|
||||
Tokio02RustlsTls(Box<Tokio02RustlsTlsStream<Tokio02TcpStream>>),
|
||||
/// Plain Tokio 0.3 TCP stream
|
||||
#[cfg(feature = "tokio03")]
|
||||
Tokio03Tcp(Tokio03TcpStream),
|
||||
/// Encrypted Tokio 0.3 TCP stream
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
Tokio03NativeTls(Tokio03TlsStream<Tokio03TcpStream>),
|
||||
/// Encrypted Tokio 0.3 TCP stream
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
Tokio03RustlsTls(Box<Tokio03RustlsTlsStream<Tokio03TcpStream>>),
|
||||
/// Can't be built
|
||||
None,
|
||||
}
|
||||
@@ -47,7 +69,7 @@ enum InnerAsyncNetworkStream {
|
||||
impl AsyncNetworkStream {
|
||||
fn new(inner: InnerAsyncNetworkStream) -> Self {
|
||||
if let InnerAsyncNetworkStream::None = inner {
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
|
||||
}
|
||||
|
||||
AsyncNetworkStream { inner }
|
||||
@@ -64,11 +86,19 @@ impl AsyncNetworkStream {
|
||||
}
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio02RustlsTls(ref s) => s.get_ref().0.peer_addr(),
|
||||
#[cfg(feature = "tokio03")]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(ref s) => s.peer_addr(),
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03NativeTls(ref s) => {
|
||||
s.get_ref().get_ref().get_ref().peer_addr()
|
||||
}
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03RustlsTls(ref s) => s.get_ref().0.peer_addr(),
|
||||
InnerAsyncNetworkStream::None => {
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
|
||||
Err(IoError::new(
|
||||
ErrorKind::Other,
|
||||
"InnerAsyncNetworkStream::None should never be built",
|
||||
"InnerAsyncNetworkStream::None must never be built",
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -85,8 +115,16 @@ impl AsyncNetworkStream {
|
||||
}
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio02RustlsTls(ref s) => s.get_ref().0.shutdown(how),
|
||||
#[cfg(feature = "tokio03")]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(ref s) => s.shutdown(how),
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03NativeTls(ref s) => {
|
||||
s.get_ref().get_ref().get_ref().shutdown(how)
|
||||
}
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03RustlsTls(ref s) => s.get_ref().0.shutdown(how),
|
||||
InnerAsyncNetworkStream::None => {
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -98,7 +136,7 @@ impl AsyncNetworkStream {
|
||||
port: u16,
|
||||
tls_parameters: Option<TlsParameters>,
|
||||
) -> Result<AsyncNetworkStream, Error> {
|
||||
let tcp_stream = TcpStream::connect((hostname, port)).await?;
|
||||
let tcp_stream = Tokio02TcpStream::connect((hostname, port)).await?;
|
||||
|
||||
let mut stream = AsyncNetworkStream::new(InnerAsyncNetworkStream::Tokio02Tcp(tcp_stream));
|
||||
if let Some(tls_parameters) = tls_parameters {
|
||||
@@ -107,9 +145,27 @@ impl AsyncNetworkStream {
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio03")]
|
||||
pub async fn connect_tokio03(
|
||||
hostname: &str,
|
||||
port: u16,
|
||||
tls_parameters: Option<TlsParameters>,
|
||||
) -> Result<AsyncNetworkStream, Error> {
|
||||
let tcp_stream = Tokio03TcpStream::connect((hostname, port)).await?;
|
||||
|
||||
let mut stream = AsyncNetworkStream::new(InnerAsyncNetworkStream::Tokio03Tcp(tcp_stream));
|
||||
if let Some(tls_parameters) = tls_parameters {
|
||||
stream.upgrade_tls(tls_parameters).await?;
|
||||
}
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
pub async fn upgrade_tls(&mut self, tls_parameters: TlsParameters) -> Result<(), Error> {
|
||||
match &self.inner {
|
||||
#[cfg(not(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls")))]
|
||||
#[cfg(all(
|
||||
feature = "tokio02",
|
||||
not(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))
|
||||
))]
|
||||
InnerAsyncNetworkStream::Tokio02Tcp(_) => {
|
||||
let _ = tls_parameters;
|
||||
panic!("Trying to upgrade an AsyncNetworkStream without having enabled either the tokio02-native-tls or the tokio02-rustls-tls feature");
|
||||
@@ -127,6 +183,27 @@ impl AsyncNetworkStream {
|
||||
self.inner = Self::upgrade_tokio02_tls(tcp_stream, tls_parameters).await?;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(all(
|
||||
feature = "tokio03",
|
||||
not(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))
|
||||
))]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(_) => {
|
||||
let _ = tls_parameters;
|
||||
panic!("Trying to upgrade an AsyncNetworkStream without having enabled either the tokio03-native-tls or the tokio03-rustls-tls feature");
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(_) => {
|
||||
// get owned TcpStream
|
||||
let tcp_stream = std::mem::replace(&mut self.inner, InnerAsyncNetworkStream::None);
|
||||
let tcp_stream = match tcp_stream {
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(tcp_stream) => tcp_stream,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.inner = Self::upgrade_tokio03_tls(tcp_stream, tls_parameters).await?;
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
@@ -134,7 +211,7 @@ impl AsyncNetworkStream {
|
||||
#[allow(unused_variables)]
|
||||
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
|
||||
async fn upgrade_tokio02_tls(
|
||||
tcp_stream: TcpStream,
|
||||
tcp_stream: Tokio02TcpStream,
|
||||
mut tls_parameters: TlsParameters,
|
||||
) -> Result<InnerAsyncNetworkStream, Error> {
|
||||
let domain = std::mem::take(&mut tls_parameters.domain);
|
||||
@@ -173,6 +250,48 @@ impl AsyncNetworkStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
|
||||
async fn upgrade_tokio03_tls(
|
||||
tcp_stream: Tokio03TcpStream,
|
||||
mut tls_parameters: TlsParameters,
|
||||
) -> Result<InnerAsyncNetworkStream, Error> {
|
||||
let domain = std::mem::take(&mut tls_parameters.domain);
|
||||
|
||||
match tls_parameters.connector {
|
||||
#[cfg(feature = "native-tls")]
|
||||
InnerTlsParameters::NativeTls(connector) => {
|
||||
#[cfg(not(feature = "tokio03-native-tls"))]
|
||||
panic!("built without the tokio03-native-tls feature");
|
||||
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
return {
|
||||
use tokio03_native_tls_crate::TlsConnector;
|
||||
|
||||
let connector = TlsConnector::from(connector);
|
||||
let stream = connector.connect(&domain, tcp_stream).await?;
|
||||
Ok(InnerAsyncNetworkStream::Tokio03NativeTls(stream))
|
||||
};
|
||||
}
|
||||
#[cfg(feature = "rustls-tls")]
|
||||
InnerTlsParameters::RustlsTls(config) => {
|
||||
#[cfg(not(feature = "tokio03-rustls-tls"))]
|
||||
panic!("built without the tokio03-rustls-tls feature");
|
||||
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
return {
|
||||
use tokio03_rustls::{webpki::DNSNameRef, TlsConnector};
|
||||
|
||||
let domain = DNSNameRef::try_from_ascii_str(&domain)?;
|
||||
|
||||
let connector = TlsConnector::from(Arc::new(config));
|
||||
let stream = connector.connect(domain, tcp_stream).await?;
|
||||
Ok(InnerAsyncNetworkStream::Tokio03RustlsTls(Box::new(stream)))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_encrypted(&self) -> bool {
|
||||
match self.inner {
|
||||
#[cfg(feature = "tokio02")]
|
||||
@@ -181,6 +300,12 @@ impl AsyncNetworkStream {
|
||||
InnerAsyncNetworkStream::Tokio02NativeTls(_) => true,
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio02RustlsTls(_) => true,
|
||||
#[cfg(feature = "tokio03")]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(_) => false,
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03NativeTls(_) => true,
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03RustlsTls(_) => true,
|
||||
InnerAsyncNetworkStream::None => false,
|
||||
}
|
||||
}
|
||||
@@ -199,8 +324,35 @@ impl futures_io::AsyncRead for AsyncNetworkStream {
|
||||
InnerAsyncNetworkStream::Tokio02NativeTls(ref mut s) => Pin::new(s).poll_read(cx, buf),
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio02RustlsTls(ref mut s) => Pin::new(s).poll_read(cx, buf),
|
||||
#[cfg(feature = "tokio03")]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(ref mut s) => {
|
||||
let mut b = Tokio03ReadBuf::new(buf);
|
||||
match Pin::new(s).poll_read(cx, &mut b) {
|
||||
Poll::Ready(Ok(())) => Poll::Ready(Ok(b.filled().len())),
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03NativeTls(ref mut s) => {
|
||||
let mut b = Tokio03ReadBuf::new(buf);
|
||||
match Pin::new(s).poll_read(cx, &mut b) {
|
||||
Poll::Ready(Ok(())) => Poll::Ready(Ok(b.filled().len())),
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03RustlsTls(ref mut s) => {
|
||||
let mut b = Tokio03ReadBuf::new(buf);
|
||||
match Pin::new(s).poll_read(cx, &mut b) {
|
||||
Poll::Ready(Ok(())) => Poll::Ready(Ok(b.filled().len())),
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
InnerAsyncNetworkStream::None => {
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
|
||||
Poll::Ready(Ok(0))
|
||||
}
|
||||
}
|
||||
@@ -220,8 +372,14 @@ impl futures_io::AsyncWrite for AsyncNetworkStream {
|
||||
InnerAsyncNetworkStream::Tokio02NativeTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio02RustlsTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
|
||||
#[cfg(feature = "tokio03")]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(ref mut s) => Pin::new(s).poll_write(cx, buf),
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03NativeTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03RustlsTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
|
||||
InnerAsyncNetworkStream::None => {
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
|
||||
Poll::Ready(Ok(0))
|
||||
}
|
||||
}
|
||||
@@ -235,8 +393,14 @@ impl futures_io::AsyncWrite for AsyncNetworkStream {
|
||||
InnerAsyncNetworkStream::Tokio02NativeTls(ref mut s) => Pin::new(s).poll_flush(cx),
|
||||
#[cfg(feature = "tokio02-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio02RustlsTls(ref mut s) => Pin::new(s).poll_flush(cx),
|
||||
#[cfg(feature = "tokio03")]
|
||||
InnerAsyncNetworkStream::Tokio03Tcp(ref mut s) => Pin::new(s).poll_flush(cx),
|
||||
#[cfg(feature = "tokio03-native-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03NativeTls(ref mut s) => Pin::new(s).poll_flush(cx),
|
||||
#[cfg(feature = "tokio03-rustls-tls")]
|
||||
InnerAsyncNetworkStream::Tokio03RustlsTls(ref mut s) => Pin::new(s).poll_flush(cx),
|
||||
InnerAsyncNetworkStream::None => {
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
|
||||
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
#[cfg(feature = "serde")]
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
pub(crate) use self::async_connection::AsyncSmtpConnection;
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
pub(crate) use self::async_net::AsyncNetworkStream;
|
||||
use self::net::NetworkStream;
|
||||
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
|
||||
@@ -37,9 +37,9 @@ pub use self::{
|
||||
tls::{Certificate, Tls, TlsParameters, TlsParametersBuilder},
|
||||
};
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
mod async_connection;
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
mod async_net;
|
||||
mod connection;
|
||||
mod mock;
|
||||
|
||||
@@ -126,15 +126,6 @@ impl TlsParametersBuilder {
|
||||
return self.build_rustls();
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
|
||||
pub(crate) fn build_tokio02(self) -> Result<TlsParameters, Error> {
|
||||
#[cfg(feature = "tokio02-native-tls")]
|
||||
return self.build_native();
|
||||
|
||||
#[cfg(not(feature = "tokio02-native-tls"))]
|
||||
return self.build_rustls();
|
||||
}
|
||||
|
||||
/// Creates a new `TlsParameters` using native-tls with the provided configuration
|
||||
#[cfg(feature = "native-tls")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
|
||||
|
||||
@@ -155,8 +155,12 @@
|
||||
//!
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
pub use self::async_transport::Tokio02Connector;
|
||||
#[cfg(feature = "tokio03")]
|
||||
pub use self::async_transport::Tokio03Connector;
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
pub use self::async_transport::{
|
||||
AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder, Tokio02Connector,
|
||||
AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder,
|
||||
};
|
||||
#[cfg(feature = "r2d2")]
|
||||
pub use self::pool::PoolConfig;
|
||||
@@ -176,7 +180,7 @@ use crate::transport::smtp::{
|
||||
use client::Tls;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
|
||||
mod async_transport;
|
||||
pub mod authentication;
|
||||
pub mod client;
|
||||
|
||||
Reference in New Issue
Block a user