Compare commits

...

8 Commits

Author SHA1 Message Date
Alexis Mousset
9dadc4d6eb Merge pull request #302 from kper/v0.8.x
Add `Reference` and `In-Reply-To` to the email header.
2018-09-20 20:26:35 +02:00
Alexis Mousset
bb7815a366 fix(email): Do not include Bcc addresses in headers 2018-09-20 20:23:10 +02:00
Alexis Mousset
b24c0a367d Merge branch 'v0.8.x' into v0.8.x 2018-09-20 20:13:25 +02:00
Alexis Mousset
e0637c9ed4 Merge pull request #307 from sameer/v0.8.x
fix(transport-smtp) Use nom 4.0 to fix build errors in #298
2018-09-12 10:25:43 +02:00
Jarred Nicholls
6c3de0e85b fix(transport-smtp): Use nom 4.0 to fix build errors in #298 2018-08-14 17:42:26 -04:00
Kevin Per
692f8a5346 Add Reference and In-Reply-To to the email header.
This is patch makes it possible to answer emails in reference to their parents and therefore it is possible for gmail to group them.
The `Reply-To` header attribute alone didn't work.
2018-07-05 22:37:37 +02:00
Alexis Mousset
60f06f1682 docs(all): Add an example of custom tls settings 2018-05-20 13:28:47 +02:00
Alexis Mousset
29b130c919 docs(all): README should not use external crates 2018-05-20 00:04:28 +02:00
6 changed files with 123 additions and 19 deletions

View File

@@ -46,7 +46,6 @@ lettre_email = "0.8"
```rust,no_run
extern crate lettre;
extern crate lettre_email;
extern crate mime;
use lettre::{EmailTransport, SmtpTransport};
use lettre_email::EmailBuilder;
@@ -60,7 +59,6 @@ fn main() {
.from("user@example.com")
.subject("Hi, Hello world")
.text("Hello world.")
.attachment(Path::new("Cargo.toml"), None, &mime::TEXT_PLAIN).unwrap()
.build()
.unwrap();

View File

@@ -20,7 +20,7 @@ is-it-maintained-open-issues = { repository = "lettre/lettre" }
[dependencies]
log = "^0.4"
nom = { version = "^3.2", optional = true }
nom = { version = "^4.0", optional = true }
bufstream = { version = "^0.1", optional = true }
native-tls = { version = "^0.1", optional = true }
base64 = { version = "^0.9", optional = true }

View File

@@ -37,7 +37,7 @@ pub enum Error {
/// TLS error
Tls(native_tls::Error),
/// Parsing error
Parsing(nom::simple_errors::Err),
Parsing(nom::ErrorKind),
}
impl Display for Error {
@@ -77,7 +77,7 @@ impl StdError for Error {
Utf8Parsing(ref err) => Some(&*err),
Io(ref err) => Some(&*err),
Tls(ref err) => Some(&*err),
Parsing(ref err) => Some(&*err),
Parsing(_) => None,
_ => None,
}
}
@@ -95,8 +95,8 @@ impl From<native_tls::Error> for Error {
}
}
impl From<nom::simple_errors::Err> for Error {
fn from(err: nom::simple_errors::Err) -> Error {
impl From<nom::ErrorKind> for Error {
fn from(err: nom::ErrorKind) -> Error {
Parsing(err)
}
}

View File

@@ -1,8 +1,7 @@
//! SMTP response, containing a mandatory return code and an optional text
//! message
use nom::{crlf, ErrorKind as NomErrorKind, IResult as NomResult};
use nom::simple_errors::Err as NomError;
use nom::{crlf, ErrorKind as NomErrorKind};
use std::fmt::{Display, Formatter, Result};
use std::result;
use std::str::{FromStr, from_utf8};
@@ -126,13 +125,12 @@ pub struct Response {
}
impl FromStr for Response {
type Err = NomError;
type Err = NomErrorKind;
fn from_str(s: &str) -> result::Result<Response, NomError> {
fn from_str(s: &str) -> result::Result<Response, NomErrorKind> {
match parse_response(s.as_bytes()) {
NomResult::Done(_, res) => Ok(res),
NomResult::Error(e) => Err(e),
NomResult::Incomplete(_) => Err(NomErrorKind::Complete),
Ok((_, res)) => Ok(res),
Err(e) => Err(e.into_error_kind()),
}
}
}

View File

@@ -106,6 +106,14 @@ impl IntoEmail for SimpleEmail {
builder.set_subject(self.subject.unwrap());
}
if self.in_reply_to.is_some() {
builder.add_in_reply_to(self.in_reply_to.unwrap().into_mailbox());
}
if self.reference.is_some() {
builder.add_reference(self.reference.unwrap().into_mailbox());
}
// No date for now
match (self.text, self.html) {
@@ -131,6 +139,8 @@ pub struct SimpleEmail {
cc: Vec<Mailbox>,
bcc: Vec<Mailbox>,
reply_to: Option<Mailbox>,
in_reply_to: Option<Mailbox>,
reference: Option<Mailbox>,
subject: Option<String>,
date: Option<Tm>,
html: Option<String>,
@@ -184,6 +194,18 @@ impl SimpleEmail {
self.cc.push(address.into_mailbox());
}
/// Adds a `In-Reply-To` to the header
pub fn in_reply_to<A: IntoMailbox>(mut self, address: A) -> SimpleEmail {
self.in_reply_to = Some(address.into_mailbox());
self
}
/// Adds a `Reference` to the header
pub fn reference<A: IntoMailbox>(mut self, address: A) -> SimpleEmail {
self.reference = Some(address.into_mailbox());
self
}
/// Adds a `Bcc` header and stores the recipient address
pub fn bcc<A: IntoMailbox>(mut self, address: A) -> SimpleEmail {
self.add_bcc(address);
@@ -296,6 +318,10 @@ pub struct EmailBuilder {
envelope: Option<Envelope>,
/// Date issued
date_issued: bool,
/// Reference Header
reference_header: Vec<Address>,
/// In-Reply-To Header
in_reply_to_header: Vec<Address>
}
/// Simple email representation
@@ -392,6 +418,8 @@ impl EmailBuilder {
sender_header: None,
envelope: None,
date_issued: false,
reference_header: vec![],
in_reply_to_header: vec![]
}
}
@@ -471,6 +499,28 @@ impl EmailBuilder {
self
}
/// Adds a `In-Reply-To` header
pub fn add_in_reply_to<A: IntoMailbox>(&mut self, address: A) {
self.in_reply_to_header.push(Address::Mailbox(address.into_mailbox()));
}
/// Adds a `Reference` header
pub fn add_reference<A: IntoMailbox>(&mut self, address: A) {
self.reference_header.push(Address::Mailbox(address.into_mailbox()));
}
/// Adds a `In-Reply-To` header
pub fn in_reply_to<A: IntoMailbox>(mut self, address: A) -> EmailBuilder {
self.add_in_reply_to(address);
self
}
/// Adds a `Reference` header
pub fn reference<A: IntoMailbox>(mut self, address: A) -> EmailBuilder {
self.add_reference(address);
self
}
/// Adds a `Reply-To` header
pub fn add_reply_to<A: IntoMailbox>(&mut self, address: A) {
let mailbox = address.into_mailbox();
@@ -773,16 +823,24 @@ impl EmailBuilder {
self.message
.add_header(Header::new_with_value("Cc".into(), self.cc_header).unwrap());
}
if !self.bcc_header.is_empty() {
self.message
.add_header(Header::new_with_value("Bcc".into(), self.bcc_header).unwrap());
}
if !self.reply_to_header.is_empty() {
self.message.add_header(
Header::new_with_value("Reply-To".into(), self.reply_to_header).unwrap(),
);
}
if !self.reference_header.is_empty() {
self.message.add_header(
Header::new_with_value("Reference".into(), self.reference_header).unwrap(),
);
}
if !self.in_reply_to_header.is_empty() {
self.message.add_header(
Header::new_with_value("In-Reply-To".into(), self.in_reply_to_header).unwrap(),
);
}
if !self.date_issued {
self.message
.add_header(("Date", Tm::rfc822z(&now()).to_string().as_ref()));
@@ -902,7 +960,7 @@ mod test {
"Date: {}\r\nSubject: Hello\r\nX-test: value\r\nSender: \
<sender@localhost>\r\nTo: <user@localhost>\r\nFrom: \
<user@localhost>\r\nCc: \"Alias\" <cc@localhost>\r\n\
Bcc: <bcc@localhost>\r\nReply-To: <reply@localhost>\r\n\
Reply-To: <reply@localhost>\r\n\
MIME-Version: 1.0\r\nMessage-ID: \
<{}.lettre@localhost>\r\n\r\nHello World!\r\n",
date_now.rfc822z(),

View File

@@ -83,6 +83,56 @@ fn main() {
}
```
You can specify custom TLS settings:
```rust,no_run
extern crate native_tls;
extern crate lettre;
extern crate lettre_email;
use native_tls::TlsConnector;
use native_tls::{Protocol};
use lettre::smtp::authentication::{Credentials, Mechanism};
use lettre::{EmailTransport, SimpleSendableEmail, ClientTlsParameters, ClientSecurity};
use lettre::smtp::ConnectionReuseParameters;
use lettre::smtp::{SmtpTransportBuilder};
use lettre_email::EmailBuilder;
fn main() {
let email = SimpleSendableEmail::new(
"user@localhost".to_string(),
&["root@localhost".to_string()],
"message_id".to_string(),
"Hello world".to_string(),
).unwrap();
let mut tls_builder = TlsConnector::builder().unwrap();
tls_builder.supported_protocols(&[Protocol::Tlsv10]).unwrap();
let tls_parameters =
ClientTlsParameters::new(
"smtp.example.com".to_string(),
tls_builder.build().unwrap()
);
let mut mailer = SmtpTransportBuilder::new(
("smtp.example.com", 465), ClientSecurity::Wrapper(tls_parameters)
)
.expect("Failed to create transport")
.authentication_mechanism(Mechanism::Login)
.credentials(Credentials::new(
"example_username".to_string(), "example_password".to_string()
))
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited)
.build();
let result = mailer.send(&email);
assert!(result.is_ok());
mailer.close();
}
```
#### Lower level
You can also send commands, here is a simple email transaction without