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
This commit is contained in:
@@ -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::<AsyncStd1Connector>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
let mailer: AsyncSmtpTransport<AsyncStd1Executor> =
|
||||
AsyncSmtpTransport::<AsyncStd1Executor>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
|
||||
@@ -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::<AsyncStd1Connector>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
let mailer: AsyncSmtpTransport<AsyncStd1Executor> =
|
||||
AsyncSmtpTransport::<AsyncStd1Executor>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
|
||||
@@ -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::<Tokio02Connector>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
let mailer: AsyncSmtpTransport<Tokio02Executor> =
|
||||
AsyncSmtpTransport::<Tokio02Executor>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
|
||||
@@ -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::<Tokio02Connector>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
let mailer: AsyncSmtpTransport<Tokio02Executor> =
|
||||
AsyncSmtpTransport::<Tokio02Executor>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
|
||||
@@ -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::<Tokio1Connector>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
||||
AsyncSmtpTransport::<Tokio1Executor>::starttls_relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
|
||||
@@ -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::<Tokio1Connector>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
||||
AsyncSmtpTransport::<Tokio1Executor>::relay("smtp.gmail.com")
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(email).await {
|
||||
|
||||
232
src/executor.rs
Normal file
232
src/executor.rs
Normal file
@@ -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<AsyncSmtpConnection, Error>;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "file-transport-envelope")]
|
||||
async fn fs_read(path: &Path) -> IoResult<Vec<u8>>;
|
||||
|
||||
#[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<AsyncSmtpConnection, Error> {
|
||||
#[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<Vec<u8>> {
|
||||
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<AsyncSmtpConnection, Error> {
|
||||
#[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<Vec<u8>> {
|
||||
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<AsyncSmtpConnection, Error> {
|
||||
#[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<Vec<u8>> {
|
||||
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 {}
|
||||
}
|
||||
124
src/lib.rs
124
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<Self::Ok, Self::Error> {
|
||||
let raw = message.formatted();
|
||||
self.send_raw(message.envelope(), &raw)
|
||||
}
|
||||
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
/// 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<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>;
|
||||
}
|
||||
|
||||
/// 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<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>;
|
||||
}
|
||||
|
||||
/// 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<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>;
|
||||
}
|
||||
pub use crate::transport::Tokio1Transport;
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "builder")]
|
||||
|
||||
@@ -70,10 +70,10 @@
|
||||
//! # #[cfg(all(feature = "tokio1", feature = "file-transport", feature = "builder"))]
|
||||
//! # async fn run() -> Result<(), Box<dyn Error>> {
|
||||
//! 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::<Tokio1Executor>::new(temp_dir());
|
||||
//! let email = Message::builder()
|
||||
//! .from("NoBody <nobody@domain.tld>".parse()?)
|
||||
//! .reply_to("Yuin <yuin@domain.tld>".parse()?)
|
||||
@@ -95,10 +95,10 @@
|
||||
//! # #[cfg(all(feature = "async-std1", feature = "file-transport", feature = "builder"))]
|
||||
//! # async fn run() -> Result<(), Box<dyn Error>> {
|
||||
//! 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::<AsyncStd1Executor>::new(temp_dir());
|
||||
//! let email = Message::builder()
|
||||
//! .from("NoBody <nobody@domain.tld>".parse()?)
|
||||
//! .reply_to("Yuin <yuin@domain.tld>".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<E: Executor> {
|
||||
inner: FileTransport,
|
||||
marker_: PhantomData<E>,
|
||||
}
|
||||
|
||||
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<E> AsyncFileTransport<E>
|
||||
where
|
||||
E: Executor,
|
||||
{
|
||||
/// Creates a new transport to the given directory
|
||||
///
|
||||
/// Writes the email content in eml format.
|
||||
pub fn new<P: AsRef<Path>>(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<P: AsRef<Path>>(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<u8>), 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<E> AsyncTransport for AsyncFileTransport<E>
|
||||
where
|
||||
E: Executor,
|
||||
{
|
||||
type Ok = Id;
|
||||
type Error = Error;
|
||||
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
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<Self::Ok, Self::Error> {
|
||||
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<Self::Ok, Self::Error> {
|
||||
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
|
||||
|
||||
@@ -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<Self::Ok, Self::Error> {
|
||||
let raw = message.formatted();
|
||||
self.send_raw(message.envelope(), &raw)
|
||||
}
|
||||
|
||||
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
/// 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<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>;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
//!
|
||||
//! # #[cfg(all(feature = "tokio02", feature = "sendmail-transport", feature = "builder"))]
|
||||
//! # async fn run() -> Result<(), Box<dyn Error>> {
|
||||
//! use lettre::{Message, Tokio02Transport, SendmailTransport};
|
||||
//! use lettre::{Message, AsyncTransport, Tokio02Executor, AsyncSendmailTransport, SendmailTransport};
|
||||
//!
|
||||
//! let email = Message::builder()
|
||||
//! .from("NoBody <nobody@domain.tld>".parse()?)
|
||||
@@ -42,7 +42,7 @@
|
||||
//! .subject("Happy new year")
|
||||
//! .body(String::from("Be happy!"))?;
|
||||
//!
|
||||
//! let sender = SendmailTransport::new();
|
||||
//! let sender = AsyncSendmailTransport::<Tokio02Executor>::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<dyn Error>> {
|
||||
//! use lettre::{Message, Tokio1Transport, SendmailTransport};
|
||||
//! use lettre::{Message, AsyncTransport, Tokio1Executor, AsyncSendmailTransport, SendmailTransport};
|
||||
//!
|
||||
//! let email = Message::builder()
|
||||
//! .from("NoBody <nobody@domain.tld>".parse()?)
|
||||
@@ -65,7 +65,7 @@
|
||||
//! .subject("Happy new year")
|
||||
//! .body(String::from("Be happy!"))?;
|
||||
//!
|
||||
//! let sender = SendmailTransport::new();
|
||||
//! let sender = AsyncSendmailTransport::<Tokio1Executor>::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<dyn Error>> {
|
||||
//! use lettre::{Message, AsyncStd1Transport, SendmailTransport};
|
||||
//! use lettre::{Message, AsyncTransport, AsyncStd1Executor, AsyncSendmailTransport};
|
||||
//!
|
||||
//! let email = Message::builder()
|
||||
//! .from("NoBody <nobody@domain.tld>".parse()?)
|
||||
@@ -88,7 +88,7 @@
|
||||
//! .subject("Happy new year")
|
||||
//! .body(String::from("Be happy!"))?;
|
||||
//!
|
||||
//! let sender = SendmailTransport::new();
|
||||
//! let sender = AsyncSendmailTransport::<AsyncStd1Executor>::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<E: Executor> {
|
||||
inner: SendmailTransport,
|
||||
marker_: PhantomData<E>,
|
||||
}
|
||||
|
||||
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<E> AsyncSendmailTransport<E>
|
||||
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<S: Into<OsString>>(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<E> Default for AsyncSendmailTransport<E>
|
||||
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<AsyncStd1Executor> {
|
||||
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<Tokio02Executor> {
|
||||
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<Tokio1Executor> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
|
||||
@@ -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<C> {
|
||||
pub struct AsyncSmtpTransport<E> {
|
||||
// TODO: pool
|
||||
inner: AsyncSmtpClient<C>,
|
||||
inner: AsyncSmtpClient<E>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[async_trait]
|
||||
impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
|
||||
impl AsyncTransport for AsyncSmtpTransport<Tokio02Executor> {
|
||||
type Ok = Response;
|
||||
type Error = Error;
|
||||
|
||||
@@ -41,7 +41,7 @@ impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
|
||||
|
||||
#[cfg(feature = "tokio1")]
|
||||
#[async_trait]
|
||||
impl Tokio1Transport for AsyncSmtpTransport<Tokio1Connector> {
|
||||
impl AsyncTransport for AsyncSmtpTransport<Tokio1Executor> {
|
||||
type Ok = Response;
|
||||
type Error = Error;
|
||||
|
||||
@@ -59,7 +59,7 @@ impl Tokio1Transport for AsyncSmtpTransport<Tokio1Connector> {
|
||||
|
||||
#[cfg(feature = "async-std1")]
|
||||
#[async_trait]
|
||||
impl AsyncStd1Transport for AsyncSmtpTransport<AsyncStd1Connector> {
|
||||
impl AsyncTransport for AsyncSmtpTransport<AsyncStd1Executor> {
|
||||
type Ok = Response;
|
||||
type Error = Error;
|
||||
|
||||
@@ -75,9 +75,9 @@ impl AsyncStd1Transport for AsyncSmtpTransport<AsyncStd1Connector> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> AsyncSmtpTransport<C>
|
||||
impl<E> AsyncSmtpTransport<E>
|
||||
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<AsyncSmtpTransportBuilder, Error> {
|
||||
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<AsyncSmtpTransportBuilder, Error> {
|
||||
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<C> {
|
||||
pub fn unencrypted_localhost() -> AsyncSmtpTransport<E> {
|
||||
Self::builder_dangerous("localhost").build()
|
||||
}
|
||||
|
||||
@@ -159,9 +159,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Clone for AsyncSmtpTransport<C>
|
||||
impl<E> Clone for AsyncSmtpTransport<E>
|
||||
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<C>(self) -> AsyncSmtpTransport<C>
|
||||
pub fn build<E>(self) -> AsyncSmtpTransport<E>
|
||||
where
|
||||
C: AsyncSmtpConnector,
|
||||
E: Executor,
|
||||
{
|
||||
let client = AsyncSmtpClient {
|
||||
info: self.info,
|
||||
@@ -237,15 +237,15 @@ pub struct AsyncSmtpClient<C> {
|
||||
marker_: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<C> AsyncSmtpClient<C>
|
||||
impl<E> AsyncSmtpClient<E>
|
||||
where
|
||||
C: AsyncSmtpConnector,
|
||||
E: Executor,
|
||||
{
|
||||
/// Creates a new connection directly usable to send emails
|
||||
///
|
||||
/// Handles encryption and authentication
|
||||
pub async fn connection(&self) -> Result<AsyncSmtpConnection, Error> {
|
||||
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<C> AsyncSmtpClient<C>
|
||||
impl<E> AsyncSmtpClient<E>
|
||||
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<AsyncSmtpConnection, Error>;
|
||||
}
|
||||
#[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<AsyncSmtpConnection, Error> {
|
||||
#[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<AsyncSmtpConnection, Error> {
|
||||
#[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<AsyncSmtpConnection, Error> {
|
||||
#[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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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::Ok, Self::Error> {
|
||||
self.response
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio02")]
|
||||
#[async_trait]
|
||||
impl Tokio02Transport for StubTransport {
|
||||
impl AsyncTransport for StubTransport {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
|
||||
@@ -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::<AsyncStd1Executor>::new(temp_dir());
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".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::<Tokio02Executor>::new(temp_dir());
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||
|
||||
@@ -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::<AsyncStd1Executor>::new();
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".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::<Tokio02Executor>::new();
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||
|
||||
Reference in New Issue
Block a user