From 5c83120986c38918b4dd539e79d42a88aa51c2c6 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Sat, 27 Feb 2021 17:36:59 +0100 Subject: [PATCH] Executor refactor (#545) * Executor * Move transports inside the transport module * AsyncTransport refactor * Update examples * Update docs * impl Default for AsyncSendmailTransport * Implement AsyncFileTransport::read * Generalize AsyncFileTransport AsyncTransport implementation * Remove remaining uses of AsyncSmtpConnector --- examples/asyncstd1_smtp_starttls.rs | 11 +- examples/asyncstd1_smtp_tls.rs | 11 +- examples/tokio02_smtp_starttls.rs | 11 +- examples/tokio02_smtp_tls.rs | 11 +- examples/tokio1_smtp_starttls.rs | 11 +- examples/tokio1_smtp_tls.rs | 11 +- src/executor.rs | 232 ++++++++++++++++++++++++++ src/lib.rs | 124 ++++---------- src/transport/file/mod.rs | 144 ++++++++-------- src/transport/mod.rs | 64 +++++++ src/transport/sendmail/mod.rs | 74 ++++++-- src/transport/smtp/async_transport.rs | 214 +++++------------------- src/transport/smtp/mod.rs | 19 ++- src/transport/stub/mod.rs | 23 +-- tests/transport_file.rs | 8 +- tests/transport_sendmail.rs | 8 +- 16 files changed, 562 insertions(+), 414 deletions(-) create mode 100644 src/executor.rs diff --git a/examples/asyncstd1_smtp_starttls.rs b/examples/asyncstd1_smtp_starttls.rs index 678422a..d3fb228 100644 --- a/examples/asyncstd1_smtp_starttls.rs +++ b/examples/asyncstd1_smtp_starttls.rs @@ -1,5 +1,5 @@ use lettre::{ - transport::smtp::authentication::Credentials, AsyncSmtpTransport, AsyncStd1Connector, + transport::smtp::authentication::Credentials, AsyncSmtpTransport, AsyncStd1Executor, AsyncStd1Transport, Message, }; @@ -18,10 +18,11 @@ async fn main() { let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string()); // Open a remote connection to gmail using STARTTLS - let mailer = AsyncSmtpTransport::::starttls_relay("smtp.gmail.com") - .unwrap() - .credentials(creds) - .build(); + let mailer: AsyncSmtpTransport = + AsyncSmtpTransport::::starttls_relay("smtp.gmail.com") + .unwrap() + .credentials(creds) + .build(); // Send the email match mailer.send(email).await { diff --git a/examples/asyncstd1_smtp_tls.rs b/examples/asyncstd1_smtp_tls.rs index 6c459f2..8af95e5 100644 --- a/examples/asyncstd1_smtp_tls.rs +++ b/examples/asyncstd1_smtp_tls.rs @@ -1,5 +1,5 @@ use lettre::{ - transport::smtp::authentication::Credentials, AsyncSmtpTransport, AsyncStd1Connector, + transport::smtp::authentication::Credentials, AsyncSmtpTransport, AsyncStd1Executor, AsyncStd1Transport, Message, }; @@ -18,10 +18,11 @@ async fn main() { let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string()); // Open a remote connection to gmail - let mailer = AsyncSmtpTransport::::relay("smtp.gmail.com") - .unwrap() - .credentials(creds) - .build(); + let mailer: AsyncSmtpTransport = + AsyncSmtpTransport::::relay("smtp.gmail.com") + .unwrap() + .credentials(creds) + .build(); // Send the email match mailer.send(email).await { diff --git a/examples/tokio02_smtp_starttls.rs b/examples/tokio02_smtp_starttls.rs index 37e2d3f..da204f7 100644 --- a/examples/tokio02_smtp_starttls.rs +++ b/examples/tokio02_smtp_starttls.rs @@ -4,7 +4,7 @@ use tokio02_crate as tokio; use lettre::{ - transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio02Connector, + transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio02Executor, Tokio02Transport, }; @@ -23,10 +23,11 @@ async fn main() { let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string()); // Open a remote connection to gmail using STARTTLS - let mailer = AsyncSmtpTransport::::starttls_relay("smtp.gmail.com") - .unwrap() - .credentials(creds) - .build(); + let mailer: AsyncSmtpTransport = + AsyncSmtpTransport::::starttls_relay("smtp.gmail.com") + .unwrap() + .credentials(creds) + .build(); // Send the email match mailer.send(email).await { diff --git a/examples/tokio02_smtp_tls.rs b/examples/tokio02_smtp_tls.rs index 6d40c80..3801c1c 100644 --- a/examples/tokio02_smtp_tls.rs +++ b/examples/tokio02_smtp_tls.rs @@ -4,7 +4,7 @@ use tokio02_crate as tokio; use lettre::{ - transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio02Connector, + transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio02Executor, Tokio02Transport, }; @@ -23,10 +23,11 @@ async fn main() { let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string()); // Open a remote connection to gmail - let mailer = AsyncSmtpTransport::::relay("smtp.gmail.com") - .unwrap() - .credentials(creds) - .build(); + let mailer: AsyncSmtpTransport = + AsyncSmtpTransport::::relay("smtp.gmail.com") + .unwrap() + .credentials(creds) + .build(); // Send the email match mailer.send(email).await { diff --git a/examples/tokio1_smtp_starttls.rs b/examples/tokio1_smtp_starttls.rs index 1d43655..2b90567 100644 --- a/examples/tokio1_smtp_starttls.rs +++ b/examples/tokio1_smtp_starttls.rs @@ -4,7 +4,7 @@ use tokio1_crate as tokio; use lettre::{ - transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio1Connector, + transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio1Executor, Tokio1Transport, }; @@ -23,10 +23,11 @@ async fn main() { let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string()); // Open a remote connection to gmail using STARTTLS - let mailer = AsyncSmtpTransport::::starttls_relay("smtp.gmail.com") - .unwrap() - .credentials(creds) - .build(); + let mailer: AsyncSmtpTransport = + AsyncSmtpTransport::::starttls_relay("smtp.gmail.com") + .unwrap() + .credentials(creds) + .build(); // Send the email match mailer.send(email).await { diff --git a/examples/tokio1_smtp_tls.rs b/examples/tokio1_smtp_tls.rs index 60addbd..8156a8d 100644 --- a/examples/tokio1_smtp_tls.rs +++ b/examples/tokio1_smtp_tls.rs @@ -4,7 +4,7 @@ use tokio1_crate as tokio; use lettre::{ - transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio1Connector, + transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio1Executor, Tokio1Transport, }; @@ -23,10 +23,11 @@ async fn main() { let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string()); // Open a remote connection to gmail - let mailer = AsyncSmtpTransport::::relay("smtp.gmail.com") - .unwrap() - .credentials(creds) - .build(); + let mailer: AsyncSmtpTransport = + AsyncSmtpTransport::::relay("smtp.gmail.com") + .unwrap() + .credentials(creds) + .build(); // Send the email match mailer.send(email).await { diff --git a/src/executor.rs b/src/executor.rs new file mode 100644 index 0000000..2e08078 --- /dev/null +++ b/src/executor.rs @@ -0,0 +1,232 @@ +use async_trait::async_trait; + +#[cfg(feature = "file-transport")] +use std::io::Result as IoResult; +#[cfg(feature = "file-transport")] +use std::path::Path; + +#[cfg(all( + feature = "smtp-transport", + any(feature = "tokio02", feature = "tokio1", feature = "async-std1") +))] +use crate::transport::smtp::client::AsyncSmtpConnection; +#[cfg(all( + feature = "smtp-transport", + any(feature = "tokio02", feature = "tokio1", feature = "async-std1") +))] +use crate::transport::smtp::client::Tls; +#[cfg(all( + feature = "smtp-transport", + any(feature = "tokio02", feature = "tokio1", feature = "async-std1") +))] +use crate::transport::smtp::extension::ClientId; +#[cfg(all( + feature = "smtp-transport", + any(feature = "tokio02", feature = "tokio1", feature = "async-std1") +))] +use crate::transport::smtp::Error; + +#[async_trait] +pub trait Executor: Send + Sync + private::Sealed { + #[doc(hidden)] + #[cfg(feature = "smtp-transport")] + async fn connect( + hostname: &str, + port: u16, + hello_name: &ClientId, + tls: &Tls, + ) -> Result; + + #[doc(hidden)] + #[cfg(feature = "file-transport-envelope")] + async fn fs_read(path: &Path) -> IoResult>; + + #[doc(hidden)] + #[cfg(feature = "file-transport")] + async fn fs_write(path: &Path, contents: &[u8]) -> IoResult<()>; +} + +#[allow(missing_copy_implementations)] +#[non_exhaustive] +#[cfg(feature = "tokio02")] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio02")))] +pub struct Tokio02Executor; + +#[async_trait] +#[cfg(feature = "tokio02")] +impl Executor for Tokio02Executor { + #[doc(hidden)] + #[cfg(feature = "smtp-transport")] + async fn connect( + hostname: &str, + port: u16, + hello_name: &ClientId, + tls: &Tls, + ) -> Result { + #[allow(clippy::match_single_binding)] + let tls_parameters = match tls { + #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))] + Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()), + _ => None, + }; + #[allow(unused_mut)] + let mut conn = + AsyncSmtpConnection::connect_tokio02(hostname, port, hello_name, tls_parameters) + .await?; + + #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-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) + } + + #[doc(hidden)] + #[cfg(feature = "file-transport-envelope")] + async fn fs_read(path: &Path) -> IoResult> { + tokio02_crate::fs::read(path).await + } + + #[doc(hidden)] + #[cfg(feature = "file-transport")] + async fn fs_write(path: &Path, contents: &[u8]) -> IoResult<()> { + tokio02_crate::fs::write(path, contents).await + } +} + +#[allow(missing_copy_implementations)] +#[non_exhaustive] +#[cfg(feature = "tokio1")] +#[cfg_attr(docsrs, doc(cfg(feature = "tokio1")))] +pub struct Tokio1Executor; + +#[async_trait] +#[cfg(feature = "tokio1")] +impl Executor for Tokio1Executor { + #[doc(hidden)] + #[cfg(feature = "smtp-transport")] + async fn connect( + hostname: &str, + port: u16, + hello_name: &ClientId, + tls: &Tls, + ) -> Result { + #[allow(clippy::match_single_binding)] + let tls_parameters = match tls { + #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))] + Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()), + _ => None, + }; + #[allow(unused_mut)] + let mut conn = + AsyncSmtpConnection::connect_tokio1(hostname, port, hello_name, tls_parameters).await?; + + #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-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) + } + + #[doc(hidden)] + #[cfg(feature = "file-transport-envelope")] + async fn fs_read(path: &Path) -> IoResult> { + tokio1_crate::fs::read(path).await + } + + #[doc(hidden)] + #[cfg(feature = "file-transport")] + async fn fs_write(path: &Path, contents: &[u8]) -> IoResult<()> { + tokio1_crate::fs::write(path, contents).await + } +} + +#[allow(missing_copy_implementations)] +#[non_exhaustive] +#[cfg(feature = "async-std1")] +#[cfg_attr(docsrs, doc(cfg(feature = "async-std1")))] +pub struct AsyncStd1Executor; + +#[async_trait] +#[cfg(feature = "async-std1")] +impl Executor for AsyncStd1Executor { + #[doc(hidden)] + #[cfg(feature = "smtp-transport")] + async fn connect( + hostname: &str, + port: u16, + hello_name: &ClientId, + tls: &Tls, + ) -> Result { + #[allow(clippy::match_single_binding)] + let tls_parameters = match tls { + #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-rustls-tls"))] + Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()), + _ => None, + }; + #[allow(unused_mut)] + let mut conn = + AsyncSmtpConnection::connect_asyncstd1(hostname, port, hello_name, tls_parameters) + .await?; + + #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-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) + } + + #[doc(hidden)] + #[cfg(feature = "file-transport-envelope")] + async fn fs_read(path: &Path) -> IoResult> { + async_std::fs::read(path).await + } + + #[doc(hidden)] + #[cfg(feature = "file-transport")] + async fn fs_write(path: &Path, contents: &[u8]) -> IoResult<()> { + async_std::fs::write(path, contents).await + } +} + +mod private { + use super::*; + + pub trait Sealed {} + + #[cfg(feature = "tokio02")] + impl Sealed for Tokio02Executor {} + + #[cfg(feature = "tokio1")] + impl Sealed for Tokio1Executor {} + + #[cfg(feature = "async-std1")] + impl Sealed for AsyncStd1Executor {} +} diff --git a/src/lib.rs b/src/lib.rs index 957986e..76f49c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,8 @@ pub mod address; pub mod error; +#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))] +mod executor; #[cfg(feature = "builder")] #[cfg_attr(docsrs, doc(cfg(feature = "builder")))] pub mod message; @@ -55,11 +57,31 @@ pub mod transport; #[macro_use] extern crate hyperx; +#[cfg(feature = "async-std1")] +pub use self::executor::AsyncStd1Executor; +#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))] +pub use self::executor::Executor; +#[cfg(feature = "tokio02")] +pub use self::executor::Tokio02Executor; +#[cfg(feature = "tokio1")] +pub use self::executor::Tokio1Executor; +#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))] +pub use self::transport::AsyncTransport; pub use crate::address::Address; #[cfg(feature = "builder")] pub use crate::message::Message; +#[cfg(all( + feature = "file-transport", + any(feature = "tokio02", feature = "tokio1", feature = "async-std1") +))] +pub use crate::transport::file::AsyncFileTransport; #[cfg(feature = "file-transport")] pub use crate::transport::file::FileTransport; +#[cfg(all( + feature = "sendmail-transport", + any(feature = "tokio02", feature = "tokio1", feature = "async-std1") +))] +pub use crate::transport::sendmail::AsyncSendmailTransport; #[cfg(feature = "sendmail-transport")] pub use crate::transport::sendmail::SendmailTransport; #[cfg(all( @@ -67,104 +89,32 @@ pub use crate::transport::sendmail::SendmailTransport; any(feature = "tokio02", feature = "tokio1") ))] pub use crate::transport::smtp::AsyncSmtpTransport; +pub use crate::transport::Transport; +use crate::{address::Envelope, error::Error}; + +#[doc(hidden)] +#[allow(deprecated)] #[cfg(all(feature = "smtp-transport", feature = "async-std1"))] pub use crate::transport::smtp::AsyncStd1Connector; #[cfg(feature = "smtp-transport")] pub use crate::transport::smtp::SmtpTransport; +#[doc(hidden)] +#[allow(deprecated)] #[cfg(all(feature = "smtp-transport", feature = "tokio02"))] pub use crate::transport::smtp::Tokio02Connector; +#[doc(hidden)] +#[allow(deprecated)] #[cfg(all(feature = "smtp-transport", feature = "tokio1"))] pub use crate::transport::smtp::Tokio1Connector; -use crate::{address::Envelope, error::Error}; -#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] -use async_trait::async_trait; - -/// Blocking Transport method for emails -pub trait Transport { - /// 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")))] - fn send(&self, message: &Message) -> Result { - let raw = message.formatted(); - self.send_raw(message.envelope(), &raw) - } - - fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; -} - -/// async-std 1.x based Transport method for emails +#[doc(hidden)] #[cfg(feature = "async-std1")] -#[cfg_attr(docsrs, doc(cfg(feature = "async-std1")))] -#[async_trait] -pub trait AsyncStd1Transport { - /// 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 { - let raw = message.formatted(); - let envelope = message.envelope(); - self.send_raw(&envelope, &raw).await - } - - async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; -} - -/// tokio 0.2.x based Transport method for emails +pub use crate::transport::AsyncStd1Transport; +#[doc(hidden)] #[cfg(feature = "tokio02")] -#[cfg_attr(docsrs, doc(cfg(feature = "tokio02")))] -#[async_trait] -pub trait Tokio02Transport { - /// 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 { - let raw = message.formatted(); - let envelope = message.envelope(); - self.send_raw(&envelope, &raw).await - } - - async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; -} - -/// tokio 1.x based Transport method for emails +pub use crate::transport::Tokio02Transport; +#[doc(hidden)] #[cfg(feature = "tokio1")] -#[cfg_attr(docsrs, doc(cfg(feature = "tokio1")))] -#[async_trait] -pub trait Tokio1Transport { - /// 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 { - let raw = message.formatted(); - let envelope = message.envelope(); - self.send_raw(&envelope, &raw).await - } - - async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; -} +pub use crate::transport::Tokio1Transport; #[cfg(test)] #[cfg(feature = "builder")] diff --git a/src/transport/file/mod.rs b/src/transport/file/mod.rs index a163424..994e0a8 100644 --- a/src/transport/file/mod.rs +++ b/src/transport/file/mod.rs @@ -70,10 +70,10 @@ //! # #[cfg(all(feature = "tokio1", feature = "file-transport", feature = "builder"))] //! # async fn run() -> Result<(), Box> { //! use std::env::temp_dir; -//! use lettre::{Tokio1Transport, Message, FileTransport}; +//! use lettre::{AsyncTransport, Tokio1Executor, Message, AsyncFileTransport}; //! //! // Write to the local temp directory -//! let sender = FileTransport::new(temp_dir()); +//! let sender = AsyncFileTransport::::new(temp_dir()); //! let email = Message::builder() //! .from("NoBody ".parse()?) //! .reply_to("Yuin ".parse()?) @@ -95,10 +95,10 @@ //! # #[cfg(all(feature = "async-std1", feature = "file-transport", feature = "builder"))] //! # async fn run() -> Result<(), Box> { //! use std::env::temp_dir; -//! use lettre::{AsyncStd1Transport, Message, FileTransport}; +//! use lettre::{AsyncTransport, AsyncStd1Executor, Message, AsyncFileTransport}; //! //! // Write to the local temp directory -//! let sender = FileTransport::new(temp_dir()); +//! let sender = AsyncFileTransport::::new(temp_dir()); //! let email = Message::builder() //! .from("NoBody ".parse()?) //! .reply_to("Yuin ".parse()?) @@ -133,15 +133,13 @@ //! ``` pub use self::error::Error; -#[cfg(feature = "async-std1")] -use crate::AsyncStd1Transport; -#[cfg(feature = "tokio02")] -use crate::Tokio02Transport; -#[cfg(feature = "tokio1")] -use crate::Tokio1Transport; use crate::{address::Envelope, Transport}; #[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +use crate::{AsyncTransport, Executor}; +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] use async_trait::async_trait; +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +use std::marker::PhantomData; use std::{ path::{Path, PathBuf}, str, @@ -161,6 +159,14 @@ pub struct FileTransport { save_envelope: bool, } +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +pub struct AsyncFileTransport { + inner: FileTransport, + marker_: PhantomData, +} + impl FileTransport { /// Creates a new transport to the given directory /// @@ -208,6 +214,49 @@ impl FileTransport { } } +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +impl AsyncFileTransport +where + E: Executor, +{ + /// Creates a new transport to the given directory + /// + /// Writes the email content in eml format. + pub fn new>(path: P) -> Self { + Self { + inner: FileTransport::new(path), + marker_: PhantomData, + } + } + + /// Creates a new transport to the given directory + /// + /// Writes the email content in eml format and the envelope + /// in json format. + #[cfg(feature = "file-transport-envelope")] + pub fn with_envelope>(path: P) -> Self { + Self { + inner: FileTransport::with_envelope(path), + marker_: PhantomData, + } + } + + /// Read a message that was written using the file transport. + /// + /// Reads the envelope and the raw message content. + #[cfg(feature = "file-transport-envelope")] + pub async fn read(&self, email_id: &str) -> Result<(Envelope, Vec), Error> { + let eml_file = self.inner.path.join(format!("{}.eml", email_id)); + let eml = E::fs_read(&eml_file).await?; + + let json_file = self.inner.path.join(format!("{}.json", email_id)); + let json = E::fs_read(&json_file).await?; + let envelope = serde_json::from_slice(&json)?; + + Ok((envelope, eml)) + } +} + impl Transport for FileTransport { type Ok = Id; type Error = Error; @@ -234,80 +283,27 @@ impl Transport for FileTransport { } } -#[cfg(feature = "async-std1")] +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] #[async_trait] -impl AsyncStd1Transport for FileTransport { +impl AsyncTransport for AsyncFileTransport +where + E: Executor, +{ type Ok = Id; type Error = Error; async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { - use async_std::fs; - let email_id = Uuid::new_v4(); - let file = self.path(&email_id, "eml"); - fs::write(file, email).await?; + let file = self.inner.path(&email_id, "eml"); + E::fs_write(&file, email).await?; #[cfg(feature = "file-transport-envelope")] { - if self.save_envelope { - let file = self.path(&email_id, "json"); - fs::write(file, serde_json::to_string(&envelope)?).await?; - } - } - // use envelope anyway - let _ = envelope; - - Ok(email_id.to_string()) - } -} - -#[cfg(feature = "tokio02")] -#[async_trait] -impl Tokio02Transport for FileTransport { - type Ok = Id; - type Error = Error; - - async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { - use tokio02_crate::fs; - - let email_id = Uuid::new_v4(); - let file = self.path(&email_id, "eml"); - fs::write(file, email).await?; - - #[cfg(feature = "file-transport-envelope")] - { - if self.save_envelope { - let file = self.path(&email_id, "json"); - fs::write(file, serde_json::to_string(&envelope)?).await?; - } - } - // use envelope anyway - let _ = envelope; - - Ok(email_id.to_string()) - } -} - -#[cfg(feature = "tokio1")] -#[async_trait] -impl Tokio1Transport for FileTransport { - type Ok = Id; - type Error = Error; - - async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { - use tokio1_crate::fs; - - let email_id = Uuid::new_v4(); - - let file = self.path(&email_id, "eml"); - fs::write(file, email).await?; - - #[cfg(feature = "file-transport-envelope")] - { - if self.save_envelope { - let file = self.path(&email_id, "json"); - fs::write(file, serde_json::to_string(&envelope)?).await?; + if self.inner.save_envelope { + let file = self.inner.path(&email_id, "json"); + let buf = serde_json::to_vec(&envelope)?; + E::fs_write(&file, &buf).await?; } } // use envelope anyway diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 29483fb..f5bdc51 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -16,6 +16,26 @@ //! * The `StubTransport` is useful for debugging, and only prints the content of the email in the //! logs. +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +use async_trait::async_trait; + +#[doc(hidden)] +#[deprecated(note = "use lettre::AsyncStd1Transport")] +#[cfg(feature = "async-std1")] +pub use self::AsyncTransport as AsyncStd1Transport; +#[doc(hidden)] +#[deprecated(note = "use lettre::Tokio1Transport")] +#[cfg(feature = "tokio1")] +pub use self::AsyncTransport as Tokio1Transport; +#[doc(hidden)] +#[deprecated(note = "use lettre::Tokio02Transport")] +#[cfg(feature = "tokio02")] +pub use self::AsyncTransport as Tokio02Transport; + +use crate::Envelope; +#[cfg(feature = "builder")] +use crate::Message; + #[cfg(feature = "file-transport")] #[cfg_attr(docsrs, doc(cfg(feature = "file-transport")))] pub mod file; @@ -26,3 +46,47 @@ pub mod sendmail; #[cfg_attr(docsrs, doc(cfg(feature = "smtp-transport")))] pub mod smtp; pub mod stub; + +/// Blocking Transport method for emails +pub trait Transport { + /// 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")))] + fn send(&self, message: &Message) -> Result { + let raw = message.formatted(); + self.send_raw(message.envelope(), &raw) + } + + fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; +} + +/// Async Transport method for emails +#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] +#[cfg_attr( + docsrs, + doc(cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))) +)] +#[async_trait] +pub trait AsyncTransport { + /// 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 { + let raw = message.formatted(); + let envelope = message.envelope(); + self.send_raw(&envelope, &raw).await + } + + async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; +} diff --git a/src/transport/sendmail/mod.rs b/src/transport/sendmail/mod.rs index a59157f..914f28d 100644 --- a/src/transport/sendmail/mod.rs +++ b/src/transport/sendmail/mod.rs @@ -33,7 +33,7 @@ //! //! # #[cfg(all(feature = "tokio02", feature = "sendmail-transport", feature = "builder"))] //! # async fn run() -> Result<(), Box> { -//! use lettre::{Message, Tokio02Transport, SendmailTransport}; +//! use lettre::{Message, AsyncTransport, Tokio02Executor, AsyncSendmailTransport, SendmailTransport}; //! //! let email = Message::builder() //! .from("NoBody ".parse()?) @@ -42,7 +42,7 @@ //! .subject("Happy new year") //! .body(String::from("Be happy!"))?; //! -//! let sender = SendmailTransport::new(); +//! let sender = AsyncSendmailTransport::::new(); //! let result = sender.send(email).await; //! assert!(result.is_ok()); //! # Ok(()) @@ -56,7 +56,7 @@ //! //! # #[cfg(all(feature = "tokio1", feature = "sendmail-transport", feature = "builder"))] //! # async fn run() -> Result<(), Box> { -//! use lettre::{Message, Tokio1Transport, SendmailTransport}; +//! use lettre::{Message, AsyncTransport, Tokio1Executor, AsyncSendmailTransport, SendmailTransport}; //! //! let email = Message::builder() //! .from("NoBody ".parse()?) @@ -65,7 +65,7 @@ //! .subject("Happy new year") //! .body(String::from("Be happy!"))?; //! -//! let sender = SendmailTransport::new(); +//! let sender = AsyncSendmailTransport::::new(); //! let result = sender.send(email).await; //! assert!(result.is_ok()); //! # Ok(()) @@ -79,7 +79,7 @@ //! //! # #[cfg(all(feature = "async-std1", feature = "sendmail-transport", feature = "builder"))] //! # async fn run() -> Result<(), Box> { -//! use lettre::{Message, AsyncStd1Transport, SendmailTransport}; +//! use lettre::{Message, AsyncTransport, AsyncStd1Executor, AsyncSendmailTransport}; //! //! let email = Message::builder() //! .from("NoBody ".parse()?) @@ -88,7 +88,7 @@ //! .subject("Happy new year") //! .body(String::from("Be happy!"))?; //! -//! let sender = SendmailTransport::new(); +//! let sender = AsyncSendmailTransport::::new(); //! let result = sender.send(email).await; //! assert!(result.is_ok()); //! # Ok(()) @@ -97,14 +97,18 @@ pub use self::error::Error; #[cfg(feature = "async-std1")] -use crate::AsyncStd1Transport; +use crate::AsyncStd1Executor; #[cfg(feature = "tokio02")] -use crate::Tokio02Transport; +use crate::Tokio02Executor; #[cfg(feature = "tokio1")] -use crate::Tokio1Transport; +use crate::Tokio1Executor; use crate::{address::Envelope, Transport}; #[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +use crate::{AsyncTransport, Executor}; +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] use async_trait::async_trait; +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +use std::marker::PhantomData; use std::{ ffi::OsString, io::prelude::*, @@ -122,6 +126,14 @@ pub struct SendmailTransport { command: OsString, } +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +pub struct AsyncSendmailTransport { + inner: SendmailTransport, + marker_: PhantomData, +} + impl SendmailTransport { /// Creates a new transport with the default `/usr/sbin/sendmail` command pub fn new() -> SendmailTransport { @@ -150,12 +162,34 @@ impl SendmailTransport { .stderr(Stdio::piped()); c } +} + +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +impl AsyncSendmailTransport +where + E: Executor, +{ + /// Creates a new transport with the default `/usr/sbin/sendmail` command + pub fn new() -> Self { + Self { + inner: SendmailTransport::new(), + marker_: PhantomData, + } + } + + /// Creates a new transport to the given sendmail command + pub fn new_with_command>(command: S) -> Self { + Self { + inner: SendmailTransport::new_with_command(command), + marker_: PhantomData, + } + } #[cfg(feature = "tokio02")] fn tokio02_command(&self, envelope: &Envelope) -> tokio02_crate::process::Command { use tokio02_crate::process::Command; - let mut c = Command::new(&self.command); + let mut c = Command::new(&self.inner.command); c.kill_on_drop(true); c.arg("-i"); if let Some(from) = envelope.from() { @@ -173,7 +207,7 @@ impl SendmailTransport { fn tokio1_command(&self, envelope: &Envelope) -> tokio1_crate::process::Command { use tokio1_crate::process::Command; - let mut c = Command::new(&self.command); + let mut c = Command::new(&self.inner.command); c.kill_on_drop(true); c.arg("-i"); if let Some(from) = envelope.from() { @@ -191,7 +225,7 @@ impl SendmailTransport { fn async_std_command(&self, envelope: &Envelope) -> async_std::process::Command { use async_std::process::Command; - let mut c = Command::new(&self.command); + let mut c = Command::new(&self.inner.command); // TODO: figure out why enabling this kills it earlier // c.kill_on_drop(true); c.arg("-i"); @@ -213,6 +247,16 @@ impl Default for SendmailTransport { } } +#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))] +impl Default for AsyncSendmailTransport +where + E: Executor, +{ + fn default() -> Self { + Self::new() + } +} + impl Transport for SendmailTransport { type Ok = (); type Error = Error; @@ -234,7 +278,7 @@ impl Transport for SendmailTransport { #[cfg(feature = "async-std1")] #[async_trait] -impl AsyncStd1Transport for SendmailTransport { +impl AsyncTransport for AsyncSendmailTransport { type Ok = (); type Error = Error; @@ -259,7 +303,7 @@ impl AsyncStd1Transport for SendmailTransport { #[cfg(feature = "tokio02")] #[async_trait] -impl Tokio02Transport for SendmailTransport { +impl AsyncTransport for AsyncSendmailTransport { type Ok = (); type Error = Error; @@ -284,7 +328,7 @@ impl Tokio02Transport for SendmailTransport { #[cfg(feature = "tokio1")] #[async_trait] -impl Tokio1Transport for SendmailTransport { +impl AsyncTransport for AsyncSendmailTransport { type Ok = (); type Error = Error; diff --git a/src/transport/smtp/async_transport.rs b/src/transport/smtp/async_transport.rs index e144841..e9c2bf1 100644 --- a/src/transport/smtp/async_transport.rs +++ b/src/transport/smtp/async_transport.rs @@ -2,28 +2,28 @@ use std::marker::PhantomData; use async_trait::async_trait; -#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] -use super::Tls; use super::{ client::AsyncSmtpConnection, ClientId, Credentials, Error, Mechanism, Response, SmtpInfo, }; #[cfg(feature = "async-std1")] -use crate::AsyncStd1Transport; -use crate::Envelope; +use crate::AsyncStd1Executor; +#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] +use crate::AsyncTransport; #[cfg(feature = "tokio02")] -use crate::Tokio02Transport; +use crate::Tokio02Executor; #[cfg(feature = "tokio1")] -use crate::Tokio1Transport; +use crate::Tokio1Executor; +use crate::{Envelope, Executor}; #[allow(missing_debug_implementations)] -pub struct AsyncSmtpTransport { +pub struct AsyncSmtpTransport { // TODO: pool - inner: AsyncSmtpClient, + inner: AsyncSmtpClient, } #[cfg(feature = "tokio02")] #[async_trait] -impl Tokio02Transport for AsyncSmtpTransport { +impl AsyncTransport for AsyncSmtpTransport { type Ok = Response; type Error = Error; @@ -41,7 +41,7 @@ impl Tokio02Transport for AsyncSmtpTransport { #[cfg(feature = "tokio1")] #[async_trait] -impl Tokio1Transport for AsyncSmtpTransport { +impl AsyncTransport for AsyncSmtpTransport { type Ok = Response; type Error = Error; @@ -59,7 +59,7 @@ impl Tokio1Transport for AsyncSmtpTransport { #[cfg(feature = "async-std1")] #[async_trait] -impl AsyncStd1Transport for AsyncSmtpTransport { +impl AsyncTransport for AsyncSmtpTransport { type Ok = Response; type Error = Error; @@ -75,9 +75,9 @@ impl AsyncStd1Transport for AsyncSmtpTransport { } } -impl AsyncSmtpTransport +impl AsyncSmtpTransport where - C: AsyncSmtpConnector, + E: Executor, { /// Simple and secure transport, using TLS connections to communicate with the SMTP server /// @@ -94,7 +94,7 @@ where feature = "async-std1-rustls-tls" ))] pub fn relay(relay: &str) -> Result { - use super::{TlsParameters, SUBMISSIONS_PORT}; + use super::{Tls, TlsParameters, SUBMISSIONS_PORT}; let tls_parameters = TlsParameters::new(relay.into())?; @@ -123,7 +123,7 @@ where feature = "async-std1-rustls-tls" ))] pub fn starttls_relay(relay: &str) -> Result { - use super::{TlsParameters, SUBMISSION_PORT}; + use super::{Tls, TlsParameters, SUBMISSION_PORT}; let tls_parameters = TlsParameters::new(relay.into())?; @@ -135,7 +135,7 @@ where /// Creates a new local SMTP client to port 25 /// /// Shortcut for local unencrypted relay (typical local email daemon that will handle relaying) - pub fn unencrypted_localhost() -> AsyncSmtpTransport { + pub fn unencrypted_localhost() -> AsyncSmtpTransport { Self::builder_dangerous("localhost").build() } @@ -159,9 +159,9 @@ where } } -impl Clone for AsyncSmtpTransport +impl Clone for AsyncSmtpTransport where - C: AsyncSmtpConnector, + E: Executor, { fn clone(&self) -> Self { Self { @@ -213,15 +213,15 @@ impl AsyncSmtpTransportBuilder { feature = "async-std1-native-tls", feature = "async-std1-rustls-tls" ))] - pub fn tls(mut self, tls: Tls) -> Self { + pub fn tls(mut self, tls: super::Tls) -> Self { self.info.tls = tls; self } /// Build the transport (with default pool if enabled) - pub fn build(self) -> AsyncSmtpTransport + pub fn build(self) -> AsyncSmtpTransport where - C: AsyncSmtpConnector, + E: Executor, { let client = AsyncSmtpClient { info: self.info, @@ -237,15 +237,15 @@ pub struct AsyncSmtpClient { marker_: PhantomData, } -impl AsyncSmtpClient +impl AsyncSmtpClient where - C: AsyncSmtpConnector, + E: Executor, { /// Creates a new connection directly usable to send emails /// /// Handles encryption and authentication pub async fn connection(&self) -> Result { - let mut conn = C::connect( + let mut conn = E::connect( &self.info.server, self.info.port, &self.info.hello_name, @@ -260,9 +260,9 @@ where } } -impl AsyncSmtpClient +impl AsyncSmtpClient where - C: AsyncSmtpConnector, + E: Executor, { fn clone(&self) -> Self { Self { @@ -272,159 +272,21 @@ where } } -#[async_trait] -pub trait AsyncSmtpConnector: private::Sealed { - #[doc(hidden)] - async fn connect( - hostname: &str, - port: u16, - hello_name: &ClientId, - tls: &Tls, - ) -> Result; -} +#[doc(hidden)] +#[deprecated(note = "use lettre::Executor instead")] +pub use crate::Executor as AsyncSmtpConnector; -#[allow(missing_copy_implementations)] -#[non_exhaustive] +#[doc(hidden)] +#[deprecated(note = "use lettre::Tokio02Executor instead")] #[cfg(feature = "tokio02")] -#[cfg_attr(docsrs, doc(cfg(feature = "tokio02")))] -pub struct Tokio02Connector; +pub type Tokio02Connector = crate::Tokio02Executor; -#[async_trait] -#[cfg(feature = "tokio02")] -impl AsyncSmtpConnector for Tokio02Connector { - #[doc(hidden)] - async fn connect( - hostname: &str, - port: u16, - hello_name: &ClientId, - tls: &Tls, - ) -> Result { - #[allow(clippy::match_single_binding)] - let tls_parameters = match tls { - #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))] - Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()), - _ => None, - }; - #[allow(unused_mut)] - let mut conn = - AsyncSmtpConnection::connect_tokio02(hostname, port, hello_name, tls_parameters) - .await?; - - #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-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) - } -} - -#[allow(missing_copy_implementations)] -#[non_exhaustive] +#[doc(hidden)] +#[deprecated(note = "use lettre::Tokio1Executor instead")] #[cfg(feature = "tokio1")] -#[cfg_attr(docsrs, doc(cfg(feature = "tokio1")))] -pub struct Tokio1Connector; +pub type Tokio1Connector = crate::Tokio1Executor; -#[async_trait] -#[cfg(feature = "tokio1")] -impl AsyncSmtpConnector for Tokio1Connector { - #[doc(hidden)] - async fn connect( - hostname: &str, - port: u16, - hello_name: &ClientId, - tls: &Tls, - ) -> Result { - #[allow(clippy::match_single_binding)] - let tls_parameters = match tls { - #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))] - Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()), - _ => None, - }; - #[allow(unused_mut)] - let mut conn = - AsyncSmtpConnection::connect_tokio1(hostname, port, hello_name, tls_parameters).await?; - - #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-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) - } -} - -#[allow(missing_copy_implementations)] -#[non_exhaustive] +#[doc(hidden)] +#[deprecated(note = "use lettre::AsyncStd1Executor instead")] #[cfg(feature = "async-std1")] -#[cfg_attr(docsrs, doc(cfg(feature = "async-std1")))] -pub struct AsyncStd1Connector; - -#[async_trait] -#[cfg(feature = "async-std1")] -impl AsyncSmtpConnector for AsyncStd1Connector { - #[doc(hidden)] - async fn connect( - hostname: &str, - port: u16, - hello_name: &ClientId, - tls: &Tls, - ) -> Result { - #[allow(clippy::match_single_binding)] - let tls_parameters = match tls { - #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-rustls-tls"))] - Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()), - _ => None, - }; - #[allow(unused_mut)] - let mut conn = - AsyncSmtpConnection::connect_asyncstd1(hostname, port, hello_name, tls_parameters) - .await?; - - #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-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::*; - - pub trait Sealed {} - - #[cfg(feature = "tokio02")] - impl Sealed for Tokio02Connector {} - - #[cfg(feature = "tokio1")] - impl Sealed for Tokio1Connector {} - - #[cfg(feature = "async-std1")] - impl Sealed for AsyncStd1Connector {} -} +pub type AsyncStd1Connector = crate::AsyncStd1Executor; diff --git a/src/transport/smtp/mod.rs b/src/transport/smtp/mod.rs index 63f75d0..fa3ed33 100644 --- a/src/transport/smtp/mod.rs +++ b/src/transport/smtp/mod.rs @@ -116,12 +116,6 @@ //! # } //! ``` -#[cfg(feature = "async-std1")] -pub use self::async_transport::AsyncStd1Connector; -#[cfg(feature = "tokio02")] -pub use self::async_transport::Tokio02Connector; -#[cfg(feature = "tokio1")] -pub use self::async_transport::Tokio1Connector; #[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] pub use self::async_transport::{ AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder, @@ -145,6 +139,19 @@ use crate::transport::smtp::{ use client::Tls; use std::time::Duration; +#[doc(hidden)] +#[allow(deprecated)] +#[cfg(feature = "async-std1")] +pub use self::async_transport::AsyncStd1Connector; +#[doc(hidden)] +#[allow(deprecated)] +#[cfg(feature = "tokio02")] +pub use self::async_transport::Tokio02Connector; +#[doc(hidden)] +#[allow(deprecated)] +#[cfg(feature = "tokio1")] +pub use self::async_transport::Tokio1Connector; + #[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] mod async_transport; pub mod authentication; diff --git a/src/transport/stub/mod.rs b/src/transport/stub/mod.rs index 0b27f89..aec2c09 100644 --- a/src/transport/stub/mod.rs +++ b/src/transport/stub/mod.rs @@ -28,12 +28,10 @@ //! # } //! ``` -#[cfg(feature = "async-std1")] -use crate::AsyncStd1Transport; -#[cfg(feature = "tokio02")] -use crate::Tokio02Transport; +#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] +use crate::AsyncTransport; use crate::{address::Envelope, Transport}; -#[cfg(any(feature = "async-std1", feature = "tokio02"))] +#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] use async_trait::async_trait; use std::{error::Error as StdError, fmt}; @@ -82,20 +80,9 @@ impl Transport for StubTransport { } } -#[cfg(feature = "async-std1")] +#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))] #[async_trait] -impl AsyncStd1Transport for StubTransport { - type Ok = (); - type Error = Error; - - async fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Result { - self.response - } -} - -#[cfg(feature = "tokio02")] -#[async_trait] -impl Tokio02Transport for StubTransport { +impl AsyncTransport for StubTransport { type Ok = (); type Error = Error; diff --git a/tests/transport_file.rs b/tests/transport_file.rs index 8286fde..71e6da3 100644 --- a/tests/transport_file.rs +++ b/tests/transport_file.rs @@ -99,9 +99,9 @@ mod test { #[cfg(feature = "async-std1")] #[async_std::test] async fn file_transport_asyncstd1() { - use lettre::AsyncStd1Transport; + use lettre::{AsyncFileTransport, AsyncStd1Executor, AsyncTransport}; - let sender = FileTransport::new(temp_dir()); + let sender = AsyncFileTransport::::new(temp_dir()); let email = Message::builder() .from("NoBody ".parse().unwrap()) .reply_to("Yuin ".parse().unwrap()) @@ -136,9 +136,9 @@ mod test { #[cfg(feature = "tokio02")] #[tokio::test] async fn file_transport_tokio02() { - use lettre::Tokio02Transport; + use lettre::{AsyncFileTransport, AsyncTransport, Tokio02Executor}; - let sender = FileTransport::new(temp_dir()); + let sender = AsyncFileTransport::::new(temp_dir()); let email = Message::builder() .from("NoBody ".parse().unwrap()) .reply_to("Yuin ".parse().unwrap()) diff --git a/tests/transport_sendmail.rs b/tests/transport_sendmail.rs index d9f2cd1..67aed23 100644 --- a/tests/transport_sendmail.rs +++ b/tests/transport_sendmail.rs @@ -26,9 +26,9 @@ mod test { #[cfg(feature = "async-std1")] #[async_std::test] async fn sendmail_transport_asyncstd1() { - use lettre::AsyncStd1Transport; + use lettre::{AsyncSendmailTransport, AsyncStd1Executor, AsyncTransport}; - let sender = SendmailTransport::new(); + let sender = AsyncSendmailTransport::::new(); let email = Message::builder() .from("NoBody ".parse().unwrap()) .reply_to("Yuin ".parse().unwrap()) @@ -46,9 +46,9 @@ mod test { #[cfg(feature = "tokio02")] #[tokio::test] async fn sendmail_transport_tokio02() { - use lettre::Tokio02Transport; + use lettre::{AsyncSendmailTransport, Tokio02Executor, Tokio02Transport}; - let sender = SendmailTransport::new(); + let sender = AsyncSendmailTransport::::new(); let email = Message::builder() .from("NoBody ".parse().unwrap()) .reply_to("Yuin ".parse().unwrap())