Compare commits
3 Commits
v0.10.0-rc
...
v0.10.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47cad567b0 | ||
|
|
b0e2fc9bca | ||
|
|
1d8249165c |
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "lettre"
|
||||
# remember to update html_root_url and README.md (Cargo.toml example and deps.rs badge)
|
||||
version = "0.10.0-rc.2"
|
||||
version = "0.10.0-rc.3"
|
||||
description = "Email client"
|
||||
readme = "README.md"
|
||||
homepage = "https://lettre.rs"
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://deps.rs/crate/lettre/0.10.0-rc.2">
|
||||
<img src="https://deps.rs/crate/lettre/0.10.0-rc.2/status.svg"
|
||||
<a href="https://deps.rs/crate/lettre/0.10.0-rc.3">
|
||||
<img src="https://deps.rs/crate/lettre/0.10.0-rc.3/status.svg"
|
||||
alt="dependency status" />
|
||||
</a>
|
||||
</div>
|
||||
@@ -71,7 +71,7 @@ To use this library, add the following to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
lettre = "0.10.0-rc.2"
|
||||
lettre = "0.10.0-rc.3"
|
||||
```
|
||||
|
||||
```rust,no_run
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
//! [Tokio 1.x]: https://docs.rs/tokio/1
|
||||
//! [async-std 1.x]: https://docs.rs/async-std/1
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/crate/lettre/0.10.0-rc.2")]
|
||||
#![doc(html_root_url = "https://docs.rs/crate/lettre/0.10.0-rc.3")]
|
||||
#![doc(html_favicon_url = "https://lettre.rs/favicon.ico")]
|
||||
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
@@ -26,6 +26,9 @@ mod mailbox;
|
||||
mod special;
|
||||
mod textual;
|
||||
|
||||
/// Represents an email header
|
||||
///
|
||||
/// Email header as defined in [RFC5322](https://datatracker.ietf.org/doc/html/rfc5322) and extensions.
|
||||
pub trait Header: Clone {
|
||||
fn name() -> HeaderName;
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ pub struct MimeVersion {
|
||||
minor: u8,
|
||||
}
|
||||
|
||||
/// MIME version 1.0
|
||||
///
|
||||
/// Should be used in all MIME messages.
|
||||
pub const MIME_VERSION_1_0: MimeVersion = MimeVersion::new(1, 0);
|
||||
|
||||
impl MimeVersion {
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::transport::smtp::error::{self, Error};
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
|
||||
/// Accepted authentication mechanisms
|
||||
///
|
||||
/// Trying LOGIN last as it is deprecated.
|
||||
pub const DEFAULT_MECHANISMS: &[Mechanism] = &[Mechanism::Plain, Mechanism::Login];
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@ impl AsyncSmtpConnection {
|
||||
return if response.is_positive() {
|
||||
Ok(response)
|
||||
} else {
|
||||
Err(error::code(response.code))
|
||||
Err(error::code(response.code()))
|
||||
}
|
||||
}
|
||||
Err(nom::Err::Failure(e)) => {
|
||||
|
||||
@@ -276,7 +276,7 @@ impl SmtpConnection {
|
||||
return if response.is_positive() {
|
||||
Ok(response)
|
||||
} else {
|
||||
Err(error::code(response.code))
|
||||
Err(error::code(response.code()))
|
||||
};
|
||||
}
|
||||
Err(nom::Err::Failure(e)) => {
|
||||
|
||||
@@ -78,7 +78,15 @@ impl ClientCodec {
|
||||
match self.escape_count {
|
||||
0 => self.escape_count = if *byte == b'\r' { 1 } else { 0 },
|
||||
1 => self.escape_count = if *byte == b'\n' { 2 } else { 0 },
|
||||
2 => self.escape_count = if *byte == b'.' { 3 } else { 0 },
|
||||
2 => {
|
||||
self.escape_count = if *byte == b'.' {
|
||||
3
|
||||
} else if *byte == b'\r' {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
if self.escape_count == 3 {
|
||||
@@ -111,6 +119,7 @@ mod test {
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
|
||||
codec.encode(b"test\r\n", &mut buf);
|
||||
codec.encode(b"test\r\n\r\n", &mut buf);
|
||||
codec.encode(b".\r\n", &mut buf);
|
||||
codec.encode(b"\r\ntest", &mut buf);
|
||||
codec.encode(b"te\r\n.\r\nst", &mut buf);
|
||||
@@ -121,7 +130,7 @@ mod test {
|
||||
codec.encode(b"test", &mut buf);
|
||||
assert_eq!(
|
||||
String::from_utf8(buf).unwrap(),
|
||||
"test\r\n..\r\n\r\ntestte\r\n..\r\nsttesttest.test\n.test\ntest"
|
||||
"test\r\ntest\r\n\r\n..\r\n\r\ntestte\r\n..\r\nsttesttest.test\n.test\ntest"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ impl ClientId {
|
||||
/// Supported ESMTP keywords
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[non_exhaustive]
|
||||
pub enum Extension {
|
||||
/// 8BITMIME keyword
|
||||
///
|
||||
@@ -107,11 +108,11 @@ pub struct ServerInfo {
|
||||
/// Server name
|
||||
///
|
||||
/// The name given in the server banner
|
||||
pub name: String,
|
||||
name: String,
|
||||
/// ESMTP features supported by the server
|
||||
///
|
||||
/// It contains the features supported by the server and known by the `Extension` module.
|
||||
pub features: HashSet<Extension>,
|
||||
features: HashSet<Extension>,
|
||||
}
|
||||
|
||||
impl Display for ServerInfo {
|
||||
@@ -135,7 +136,7 @@ impl ServerInfo {
|
||||
|
||||
let mut features: HashSet<Extension> = HashSet::new();
|
||||
|
||||
for line in response.message.as_slice() {
|
||||
for line in response.message() {
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -197,6 +198,11 @@ impl ServerInfo {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// The name given in the server banner
|
||||
pub fn name(&self) -> &str {
|
||||
self.name.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// A `MAIL FROM` extension parameter
|
||||
|
||||
@@ -148,7 +148,7 @@ pub mod extension;
|
||||
mod pool;
|
||||
pub mod response;
|
||||
mod transport;
|
||||
pub mod util;
|
||||
pub(super) mod util;
|
||||
|
||||
// Registered port numbers:
|
||||
// https://www.iana.
|
||||
@@ -164,7 +164,7 @@ pub const SUBMISSION_PORT: u16 = 587;
|
||||
pub const SUBMISSIONS_PORT: u16 = 465;
|
||||
|
||||
/// Default timeout
|
||||
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct SmtpInfo {
|
||||
|
||||
@@ -137,10 +137,10 @@ impl Code {
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Response {
|
||||
/// Response code
|
||||
pub code: Code,
|
||||
code: Code,
|
||||
/// Server response string (optional)
|
||||
/// Handle multiline responses
|
||||
pub message: Vec<String>,
|
||||
message: Vec<String>,
|
||||
}
|
||||
|
||||
impl FromStr for Response {
|
||||
@@ -180,6 +180,16 @@ impl Response {
|
||||
pub fn first_line(&self) -> Option<&str> {
|
||||
self.message.first().map(String::as_str)
|
||||
}
|
||||
|
||||
/// Response code
|
||||
pub fn code(&self) -> Code {
|
||||
self.code
|
||||
}
|
||||
|
||||
/// Server response string (array of lines)
|
||||
pub fn message(&self) -> impl Iterator<Item = &str> {
|
||||
self.message.iter().map(String::as_str)
|
||||
}
|
||||
}
|
||||
|
||||
// Parsers (originally from tokio-smtp)
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
/// Encode a string as xtext
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct XText<'a>(pub &'a str);
|
||||
|
||||
impl<'a> Display for XText<'a> {
|
||||
|
||||
Reference in New Issue
Block a user