Fix smtp doc examples (#536)

* Fix smtp examples

Make TlsParametersBuilder a consuming builder
as `build()` consumes it. It allows chaining methods.

* Format doc examples
This commit is contained in:
Alexis Mousset
2021-02-03 10:23:08 +01:00
committed by GitHub
parent 0ea3bfbd13
commit 9d8c31bef8
19 changed files with 125 additions and 154 deletions

View File

@@ -1,5 +1,7 @@
use lettre::message::{header, MultiPart, SinglePart};
use lettre::{FileTransport, Message, Transport};
use lettre::{
message::{header, MultiPart, SinglePart},
FileTransport, Message, Transport,
};
fn main() {
// The html we want to send.

View File

@@ -1,5 +1,7 @@
use lettre::message::{header, MultiPart, SinglePart};
use lettre::{FileTransport, Message, Transport};
use lettre::{
message::{header, MultiPart, SinglePart},
FileTransport, Message, Transport,
};
use maud::html;
fn main() {

View File

@@ -1,8 +1,10 @@
use std::fs;
use lettre::{
transport::smtp::authentication::Credentials,
transport::smtp::client::{Certificate, Tls, TlsParameters},
transport::smtp::{
authentication::Credentials,
client::{Certificate, Tls, TlsParameters},
},
Message, SmtpTransport, Transport,
};
@@ -20,9 +22,10 @@ fn main() {
// Use a custom certificate stored on disk to securely verify the server's certificate
let pem_cert = fs::read("certificate.pem").unwrap();
let cert = Certificate::from_pem(&pem_cert).unwrap();
let mut tls = TlsParameters::builder("smtp.server.com".to_string());
tls.add_root_certificate(cert);
let tls = tls.build().unwrap();
let tls = TlsParameters::builder("smtp.server.com".to_string())
.add_root_certificate(cert)
.build()
.unwrap();
let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string());

View File

@@ -6,5 +6,7 @@ mod serde;
mod envelope;
mod types;
pub use self::envelope::Envelope;
pub use self::types::{Address, AddressError};
pub use self::{
envelope::Envelope,
types::{Address, AddressError},
};

View File

@@ -56,8 +56,6 @@ pub mod transport;
extern crate hyperx;
pub use crate::address::Address;
use crate::address::Envelope;
use crate::error::Error;
#[cfg(feature = "builder")]
pub use crate::message::Message;
#[cfg(feature = "file-transport")]
@@ -77,6 +75,7 @@ pub use crate::transport::smtp::SmtpTransport;
pub use crate::transport::smtp::Tokio02Connector;
#[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;

View File

@@ -1,5 +1,7 @@
use std::io::{self, Write};
use std::ops::Deref;
use std::{
io::{self, Write},
ops::Deref,
};
use crate::message::header::ContentTransferEncoding;

View File

@@ -54,7 +54,7 @@ impl Mailbox {
/// # Examples
///
/// ```
/// use lettre::{Address, message::Mailbox};
/// use lettre::{message::Mailbox, Address};
///
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -163,7 +163,10 @@ impl Mailboxes {
/// # Examples
///
/// ```
/// use lettre::{Address, message::{Mailbox, Mailboxes}};
/// use lettre::{
/// message::{Mailbox, Mailboxes},
/// Address,
/// };
///
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -182,7 +185,10 @@ impl Mailboxes {
/// # Examples
///
/// ```
/// use lettre::{Address, message::{Mailbox, Mailboxes}};
/// use lettre::{
/// message::{Mailbox, Mailboxes},
/// Address,
/// };
///
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -201,7 +207,10 @@ impl Mailboxes {
/// # Examples
///
/// ```
/// use lettre::{Address, message::{Mailbox, Mailboxes}};
/// use lettre::{
/// message::{Mailbox, Mailboxes},
/// Address,
/// };
///
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
@@ -225,7 +234,10 @@ impl Mailboxes {
/// # Examples
///
/// ```
/// use lettre::{Address, message::{Mailbox, Mailboxes}};
/// use lettre::{
/// message::{Mailbox, Mailboxes},
/// Address,
/// };
///
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {

View File

@@ -6,15 +6,12 @@ use mime::Mime;
use rand::Rng;
/// MIME part variants
///
#[derive(Debug, Clone)]
pub enum Part {
/// Single part with content
///
Single(SinglePart),
/// Multiple parts of content
///
Multi(MultiPart),
}
@@ -37,11 +34,9 @@ impl Part {
}
/// Parts of multipart body
///
pub type Parts = Vec<Part>;
/// Creates builder for single part
///
#[derive(Debug, Clone)]
pub struct SinglePartBuilder {
headers: Headers,
@@ -92,17 +87,16 @@ impl Default for SinglePartBuilder {
/// # Example
///
/// ```
/// use lettre::message::{SinglePart, header};
/// use lettre::message::{header, SinglePart};
///
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let part = SinglePart::builder()
/// .header(header::ContentType("text/plain; charset=utf8".parse()?))
/// .body(String::from("Текст письма в уникоде"));
/// .header(header::ContentType("text/plain; charset=utf8".parse()?))
/// .body(String::from("Текст письма в уникоде"));
/// # Ok(())
/// # }
/// ```
///
#[derive(Debug, Clone)]
pub struct SinglePart {
headers: Headers,
@@ -170,7 +164,6 @@ impl EmailFormat for SinglePart {
}
/// The kind of multipart
///
#[derive(Debug, Clone)]
pub enum MultiPartKind {
/// Mixed kind to combine unrelated content parts
@@ -257,7 +250,6 @@ impl From<MultiPartKind> for Mime {
}
/// Multipart builder
///
#[derive(Debug, Clone)]
pub struct MultiPartBuilder {
headers: Headers,
@@ -323,7 +315,6 @@ impl Default for MultiPartBuilder {
}
/// Multipart variant with parts
///
#[derive(Debug, Clone)]
pub struct MultiPart {
headers: Headers,

View File

@@ -114,7 +114,6 @@
//!
//! <p><b>Hello</b>, <i>world</i>! <img src="cid:123"></p>
//! --0oVZ2r6AoLAhLlb0gPNSKy6BEqdS2IfwxrcbUuo1--
//!
//! ```
//! </details>
//!
@@ -125,8 +124,8 @@
//!
//! ```rust
//! # use std::error::Error;
//! use lettre::message::{header, Body, Message, MultiPart, Part, SinglePart};
//! use std::fs;
//! use lettre::message::{Body, header, Message, MultiPart, Part, SinglePart};
//!
//! # fn main() -> Result<(), Box<dyn Error>> {
//! let image = fs::read("docs/lettre.png")?;
@@ -236,7 +235,6 @@
//!
//! fn main() { println!("Hello, World!") }
//! --0oVZ2r6AoLAhLlb0gPNSKy6BEqdS2IfwxrcbUuo1--
//!
//! ```
//! </details>
@@ -252,8 +250,7 @@ mod mailbox;
mod mimebody;
mod utf8_b;
use std::convert::TryFrom;
use std::time::SystemTime;
use std::{convert::TryFrom, time::SystemTime};
use uuid::Uuid;

View File

@@ -9,8 +9,8 @@
//!
//! # #[cfg(all(feature = "file-transport", feature = "builder"))]
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use lettre::{FileTransport, Message, Transport};
//! use std::env::temp_dir;
//! use lettre::{Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
@@ -41,8 +41,8 @@
//!
//! # #[cfg(all(feature = "file-transport-envelope", feature = "builder"))]
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use lettre::{FileTransport, Message, Transport};
//! use std::env::temp_dir;
//! use lettre::{Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::with_envelope(temp_dir());
@@ -133,14 +133,13 @@
//! ```
pub use self::error::Error;
use crate::address::Envelope;
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio1")]
use crate::Tokio1Transport;
use crate::Transport;
use crate::{address::Envelope, Transport};
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))]
use async_trait::async_trait;
use std::{

View File

@@ -96,14 +96,13 @@
//! ```
pub use self::error::Error;
use crate::address::Envelope;
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio1")]
use crate::Tokio1Transport;
use crate::Transport;
use crate::{address::Envelope, Transport};
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio1"))]
use async_trait::async_trait;
use std::{

View File

@@ -10,8 +10,10 @@ use std::{
task::{Context, Poll},
};
use futures_io::{AsyncRead as FuturesAsyncRead, AsyncWrite as FuturesAsyncWrite};
use futures_io::{Error as IoError, ErrorKind, Result as IoResult};
use futures_io::{
AsyncRead as FuturesAsyncRead, AsyncWrite as FuturesAsyncWrite, Error as IoError, ErrorKind,
Result as IoResult,
};
#[cfg(feature = "tokio02")]
use tokio02_crate::io::{AsyncRead as _, AsyncWrite as _};
#[cfg(feature = "tokio1")]
@@ -370,8 +372,7 @@ impl AsyncNetworkStream {
#[cfg(feature = "async-std1-rustls-tls")]
return {
use async_rustls::webpki::DNSNameRef;
use async_rustls::TlsConnector;
use async_rustls::{webpki::DNSNameRef, TlsConnector};
let domain = DNSNameRef::try_from_ascii_str(&domain)?;

View File

@@ -6,13 +6,15 @@ use std::{
};
use super::{ClientCodec, NetworkStream, TlsParameters};
use crate::address::Envelope;
use crate::transport::smtp::{
authentication::{Credentials, Mechanism},
commands::*,
error::Error,
extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo},
response::{parse_response, Response},
use crate::{
address::Envelope,
transport::smtp::{
authentication::{Credentials, Mechanism},
commands::*,
error::Error,
extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo},
response::{parse_response, Response},
},
};
#[cfg(feature = "tracing")]

View File

@@ -65,7 +65,7 @@ impl TlsParametersBuilder {
/// Add a custom root certificate
///
/// Can be used to safely connect to a server using a self signed certificate, for example.
pub fn add_root_certificate(&mut self, cert: Certificate) -> &mut Self {
pub fn add_root_certificate(mut self, cert: Certificate) -> Self {
self.root_certs.push(cert);
self
}
@@ -85,10 +85,7 @@ impl TlsParametersBuilder {
/// Hostname verification can only be disabled with the `native-tls` TLS backend.
#[cfg(feature = "native-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
pub fn dangerous_accept_invalid_hostnames(
&mut self,
accept_invalid_hostnames: bool,
) -> &mut Self {
pub fn dangerous_accept_invalid_hostnames(mut self, accept_invalid_hostnames: bool) -> Self {
self.accept_invalid_hostnames = accept_invalid_hostnames;
self
}
@@ -109,7 +106,7 @@ impl TlsParametersBuilder {
///
/// This method should only be used as a last resort, as it introduces
/// significant vulnerabilities to man-in-the-middle attacks.
pub fn dangerous_accept_invalid_certs(&mut self, accept_invalid_certs: bool) -> &mut Self {
pub fn dangerous_accept_invalid_certs(mut self, accept_invalid_certs: bool) -> Self {
self.accept_invalid_certs = accept_invalid_certs;
self
}

View File

@@ -43,8 +43,7 @@
//! .body(String::from("Be happy!"))?;
//!
//! // Create TLS transport on port 465
//! let sender = SmtpTransport::relay("smtp.example.com")
//! .expect("relay valid")
//! let sender = SmtpTransport::relay("smtp.example.com")?
//! .build();
//! // Send the email via remote relay
//! let result = sender.send(&email);
@@ -52,107 +51,70 @@
//! # Ok(())
//! # }
//! ```
//! #### Complete example
//!
//! ```todo
//! # #[cfg(feature = "smtp-transport")]
//! # {
//! use lettre::transport::smtp::authentication::{Credentials, Mechanism};
//! use lettre::{Email, Envelope, Transport, SmtpClient};
//! use lettre::transport::smtp::extension::ClientId;
//! #### Authentication
//!
//! let email_1 = Email::new(
//! Envelope::new(
//! Some(EmailAddress::new("user@localhost".to_string())?),
//! vec![EmailAddress::new("root@localhost".to_string())?],
//! )?,
//! "id1".to_string(),
//! "Hello world".to_string().into_bytes(),
//! );
//! Example with authentication and connection pool:
//!
//! let email_2 = Email::new(
//! Envelope::new(
//! Some(EmailAddress::new("user@localhost".to_string())?),
//! vec![EmailAddress::new("root@localhost".to_string())?],
//! )?,
//! "id2".to_string(),
//! "Hello world a second time".to_string().into_bytes(),
//! );
//! ```rust,no_run
//! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls-tls")))]
//! # fn test() -> Result<(), Box<dyn std::error::Error>> {
//! use lettre::{Message, Transport, SmtpTransport, transport::smtp::{PoolConfig, authentication::{Credentials, Mechanism}}};
//!
//! // Connect to a remote server on a custom port
//! let mut mailer = SmtpClient::new_simple("server.tld")?
//! // Set the name sent during EHLO/HELO, default is `localhost`
//! .hello_name(ClientId::Domain("my.hostname.tld".to_string()))
//! // Add credentials for authentication
//! .credentials(Credentials::new("username".to_string(), "password".to_string()))
//! // Enable SMTPUTF8 if the server supports it
//! .smtp_utf8(true)
//! // Configure expected authentication mechanism
//! .authentication_mechanism(Mechanism::Plain)
//! // Enable connection reuse
//! .connection_reuse(ConnectionReuseParameters::ReuseUnlimited).transport();
//! let email = Message::builder()
//! .from("NoBody <nobody@domain.tld>".parse()?)
//! .reply_to("Yuin <yuin@domain.tld>".parse()?)
//! .to("Hei <hei@domain.tld>".parse()?)
//! .subject("Happy new year")
//! .body(String::from("Be happy!"))?;
//!
//! let result_1 = mailer.send(&email_1);
//! assert!(result_1.is_ok());
//! // Create TLS transport on port 587 with STARTTLS
//! let sender = SmtpTransport::starttls_relay("smtp.example.com")?
//! // Add credentials for authentication
//! .credentials(Credentials::new("username".to_string(), "password".to_string()))
//! // Configure expected authentication mechanism
//! .authentication(vec![Mechanism::Plain])
//! // Connection pool settings
//! .pool_config( PoolConfig::new().max_size(20))
//! .build();
//!
//! // The second email will use the same connection
//! let result_2 = mailer.send(&email_2);
//! assert!(result_2.is_ok());
//!
//! // Explicitly close the SMTP transaction as we enabled connection reuse
//! mailer.close();
//! // Send the email via remote relay
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! You can specify custom TLS settings:
//!
//! ```todo
//! # #[cfg(feature = "native-tls")]
//! # {
//! use lettre::{
//! ClientSecurity, ClientTlsParameters, EmailAddress, Envelope,
//! Email, SmtpClient, Transport,
//! };
//! use lettre::transport::smtp::authentication::{Credentials, Mechanism};
//! use lettre::transport::smtp::ConnectionReuseParameters;
//! use native_tls::{Protocol, TlsConnector};
//! ```rust,no_run
//! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls-tls")))]
//! # fn test() -> Result<(), Box<dyn std::error::Error>> {
//! use lettre::{Message, Transport, SmtpTransport, transport::smtp::client::{TlsParameters, Tls}};
//!
//! let email = Email::new(
//! Envelope::new(
//! Some(EmailAddress::new("user@localhost".to_string())?),
//! vec![EmailAddress::new("root@localhost".to_string())?],
//! )?,
//! "message_id".to_string(),
//! "Hello world".to_string().into_bytes(),
//! );
//! let email = Message::builder()
//! .from("NoBody <nobody@domain.tld>".parse()?)
//! .reply_to("Yuin <yuin@domain.tld>".parse()?)
//! .to("Hei <hei@domain.tld>".parse()?)
//! .subject("Happy new year")
//! .body(String::from("Be happy!"))?;
//!
//! let mut tls_builder = TlsConnector::builder();
//! tls_builder.min_protocol_version(Some(Protocol::Tlsv10));
//! let tls_parameters =
//! ClientTlsParameters::new(
//! "smtp.example.com".to_string(),
//! tls_builder.build()?
//! );
//! // Custom TLS configuration
//! let tls = TlsParameters::builder("smtp.example.com".to_string())
//! .dangerous_accept_invalid_certs(true).build()?;
//!
//! let mut mailer = SmtpClient::new(
//! ("smtp.example.com", 465), ClientSecurity::Wrapper(tls_parameters)
//! )?
//! .authentication_mechanism(Mechanism::Login)
//! .credentials(Credentials::new(
//! "example_username".to_string(), "example_password".to_string()
//! ))
//! .connection_reuse(ConnectionReuseParameters::ReuseUnlimited)
//! .transport();
//! // Create TLS transport on port 465
//! let sender = SmtpTransport::relay("smtp.example.com")?
//! // Custom TLS configuration
//! .tls(Tls::Required(tls))
//! .build();
//!
//! let result = mailer.send(&email);
//!
//! assert!(result.is_ok());
//!
//! mailer.close();
//! // Send the email via remote relay
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//! ```
//!
#[cfg(feature = "async-std1")]
pub use self::async_transport::AsyncStd1Connector;

View File

@@ -16,6 +16,11 @@ pub struct PoolConfig {
}
impl PoolConfig {
/// Create a new pool configuration with default values
pub fn new() -> Self {
Self::default()
}
/// Minimum number of idle connections
///
/// Defaults to `0`

View File

@@ -8,8 +8,7 @@ use super::PoolConfig;
use super::{ClientId, Credentials, Error, Mechanism, Response, SmtpConnection, SmtpInfo};
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
use super::{Tls, TlsParameters, SUBMISSIONS_PORT, SUBMISSION_PORT};
use crate::address::Envelope;
use crate::Transport;
use crate::{address::Envelope, Transport};
#[allow(missing_debug_implementations)]
#[derive(Clone)]

View File

@@ -9,8 +9,7 @@
//! ```rust
//! # #[cfg(feature = "builder")]
//! # {
//! use lettre::{Message, Transport};
//! use lettre::transport::stub::StubTransport;
//! use lettre::{transport::stub::StubTransport, Message, Transport};
//!
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
@@ -29,12 +28,11 @@
//! # }
//! ```
use crate::address::Envelope;
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
use crate::Transport;
use crate::{address::Envelope, Transport};
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
use async_trait::async_trait;
use std::{error::Error as StdError, fmt};

View File

@@ -1,7 +1,6 @@
#[cfg(all(test, feature = "smtp-transport", feature = "r2d2"))]
mod test {
use lettre::address::Envelope;
use lettre::{SmtpTransport, Transport};
use lettre::{address::Envelope, SmtpTransport, Transport};
use std::{sync::mpsc, thread};