Compare commits

...

8 Commits

Author SHA1 Message Date
Alexis Mousset
a1bf0170db Version 0.2.0 2015-10-06 18:42:35 +02:00
Alexis Mousset
5bedba4b24 Use Tm::rfc822z to support local timezones (workaround for time crate incomplete feature) 2015-10-06 18:42:23 +02:00
Alexis Mousset
813f09a314 v0.1.2 2015-08-02 22:05:55 +02:00
Alexis Mousset
6a6023431b Add test cases for authentication 2015-08-02 21:24:24 +02:00
Alexis Mousset
7f6aa0ffae Document authentication mecanism configuration 2015-08-02 19:23:29 +02:00
Alexis Mousset
1830f084c0 Let the user configure the authentication mecanisms 2015-08-02 19:12:59 +02:00
Alexis Mousset
49a995f68d Merge branch 'master' of github.com:amousset/rust-smtp 2015-07-23 01:01:43 +02:00
Alexis Mousset
9c34b5a055 Fix badges formatting 2015-07-23 00:53:10 +02:00
7 changed files with 39 additions and 22 deletions

View File

@@ -1,7 +1,7 @@
[package]
name = "smtp"
version = "0.1.1"
version = "0.2.0"
description = "Simple SMTP client"
readme = "README.md"
documentation = "http://amousset.me/rust-smtp/smtp/"

View File

@@ -1,4 +1,4 @@
rust-smtp [![Build Status](https://travis-ci.org/amousset/rust-smtp.svg?branch=master)](https://travis-ci.org/amousset/rust-smtp) [![Coverage Status](https://coveralls.io/repos/github/amousset/rust-smtp/badge.svg?branch=master)](https://coveralls.io/github/amousset/rust-smtp?branch=master) [![](https://meritbadge.herokuapp.com/smtp)](https://crates.io/crates/smtp)[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
rust-smtp [![Build Status](https://travis-ci.org/amousset/rust-smtp.svg?branch=master)](https://travis-ci.org/amousset/rust-smtp) [![Coverage Status](https://coveralls.io/repos/github/amousset/rust-smtp/badge.svg?branch=master)](https://coveralls.io/github/amousset/rust-smtp?branch=master) [![Crate](https://meritbadge.herokuapp.com/smtp)](https://crates.io/crates/smtp) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
=========
This library implements a simple SMTP client.
@@ -11,7 +11,7 @@ To use this library, add the following to your `Cargo.toml`:
```toml
[dependencies]
smtp = "0.1"
smtp = "0.2"
```
License

View File

@@ -81,6 +81,7 @@ mod test {
let mecanism = Mecanism::Plain;
assert_eq!(mecanism.response("username", "password", None).unwrap(), "AHVzZXJuYW1lAHBhc3N3b3Jk");
assert!(mecanism.response("username", "password", Some("test")).is_err());
}
#[test]
@@ -90,5 +91,7 @@ mod test {
assert_eq!(mecanism.response("alice", "wonderland",
Some("PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==")).unwrap(),
"YWxpY2UgNjRiMmE0M2MxZjZlZDY4MDZhOTgwOTE0ZTIzZTc1ZjA=");
assert!(mecanism.response("alice", "wonderland", Some("tést")).is_err());
assert!(mecanism.response("alice", "wonderland", None).is_err());
}
}

View File

@@ -166,7 +166,7 @@ impl EmailBuilder {
/// Adds a `Date` header with the given date
pub fn date(mut self, date: &Tm) -> EmailBuilder {
self.insert_header(("Date", Tm::rfc822(date).to_string().as_ref()));
self.insert_header(("Date", Tm::rfc822z(date).to_string().as_ref()));
self.date_issued = true;
self
}
@@ -174,7 +174,7 @@ impl EmailBuilder {
/// Build the Email
pub fn build(mut self) -> Email {
if !self.date_issued {
self.insert_header(("Date", Tm::rfc822(&now()).to_string().as_ref()));
self.insert_header(("Date", Tm::rfc822z(&now()).to_string().as_ref()));
}
self.content.message.update_headers();
self.content
@@ -318,7 +318,7 @@ mod test {
assert_eq!(
format!("{}", email),
format!("Message-ID: <{}@rust-smtp>\r\nTo: <user@localhost>\r\nFrom: <user@localhost>\r\nCc: \"Alias\" <cc@localhost>\r\nReply-To: <reply@localhost>\r\nSender: <sender@localhost>\r\nDate: {}\r\nSubject: Hello\r\nX-test: value\r\n\r\nHello World!\r\n",
email.message_id().unwrap(), date_now.rfc822())
email.message_id().unwrap(), date_now.rfc822z())
);
}

View File

@@ -56,6 +56,7 @@
//! ```rust,no_run
//! use smtp::sender::{Sender, SenderBuilder};
//! use smtp::email::EmailBuilder;
//! use smtp::authentication::Mecanism;
//!
//! let mut builder = EmailBuilder::new();
//! builder = builder.to(("user@example.org", "Alias name"));
@@ -76,6 +77,8 @@
//! .hello_name("my.hostname.tld")
//! // Add credentials for authentication
//! .credentials("username", "password")
//! // Configure accepted authetication mecanisms
//! .authentication_mecanisms(vec![Mecanism::CramMd5])
//! // Enable connection reuse
//! .enable_connection_reuse(true).build();
//!

View File

@@ -2,7 +2,7 @@
use std::str::FromStr;
use std::fmt::{Display, Formatter, Result};
use std::result::Result as RResult;
use std::result;
use self::Severity::*;
use self::Category::*;
@@ -23,7 +23,7 @@ pub enum Severity {
impl FromStr for Severity {
type Err = Error;
fn from_str(s: &str) -> RResult<Severity, Error> {
fn from_str(s: &str) -> result::Result<Severity, Error> {
match s {
"2" => Ok(PositiveCompletion),
"3" => Ok(PositiveIntermediate),
@@ -66,7 +66,7 @@ pub enum Category {
impl FromStr for Category {
type Err = Error;
fn from_str(s: &str) -> RResult<Category, Error> {
fn from_str(s: &str) -> result::Result<Category, Error> {
match s {
"0" => Ok(Syntax),
"1" => Ok(Information),
@@ -109,7 +109,7 @@ impl FromStr for Code {
type Err = Error;
#[inline]
fn from_str(s: &str) -> RResult<Code, Error> {
fn from_str(s: &str) -> result::Result<Code, Error> {
if s.len() == 3 {
match (s[0..1].parse::<Severity>(), s[1..2].parse::<Category>(), s[2..3].parse::<u8>()) {
(Ok(severity), Ok(category), Ok(detail)) => Ok(Code {severity: severity, category: category, detail: detail}),
@@ -157,7 +157,7 @@ impl ResponseParser {
}
/// Parses a line and return a `bool` indicating if there are more lines to come
pub fn read_line(&mut self, line: &str) -> RResult<bool, Error> {
pub fn read_line(&mut self, line: &str) -> result::Result<bool, Error> {
if line.len() < 3 {
return Err(Error::ResponseParsingError("Wrong code length (should be 3 digit)"));

View File

@@ -25,6 +25,8 @@ pub struct SenderBuilder {
credentials: Option<(String, String)>,
/// Socket we are connecting to
server_addr: SocketAddr,
/// List of authentication mecanism, sorted by priority
authentication_mecanisms: Vec<Mecanism>,
}
/// Builder for the SMTP Sender
@@ -41,6 +43,7 @@ impl SenderBuilder {
connection_reuse_count_limit: 100,
enable_connection_reuse: false,
hello_name: "localhost".to_string(),
authentication_mecanisms: vec![Mecanism::CramMd5, Mecanism::Plain],
}),
None => Err(From::from("Could nor resolve hostname")),
}
@@ -75,6 +78,12 @@ impl SenderBuilder {
self
}
/// Set the authentication mecanisms
pub fn authentication_mecanisms(mut self, mecanisms: Vec<Mecanism>) -> SenderBuilder {
self.authentication_mecanisms = mecanisms;
self
}
/// Build the SMTP client
///
/// It does not connects to the server, but only creates the `Sender`
@@ -191,18 +200,20 @@ impl Sender {
debug!("server {}", self.server_info.as_ref().unwrap());
}
// TODO: Use PLAIN AUTH in encrypted connections, CRAM-MD5 otherwise
if self.client_info.credentials.is_some() && self.state.connection_reuse_count == 0 {
let (username, password) = self.client_info.credentials.clone().unwrap();
if self.server_info.as_ref().unwrap().supports_auth_mecanism(Mecanism::CramMd5) {
let result = self.client.auth(Mecanism::CramMd5, &username, &password);
let mut found = false;
for mecanism in self.client_info.authentication_mecanisms.clone() {
if self.server_info.as_ref().unwrap().supports_auth_mecanism(mecanism) {
found = true;
let result = self.client.auth(mecanism, &username, &password);
try_smtp!(result, self);
} else if self.server_info.as_ref().unwrap().supports_auth_mecanism(Mecanism::Plain) {
let result = self.client.auth(Mecanism::Plain, &username, &password);
try_smtp!(result, self);
} else {
}
}
if !found {
debug!("No supported authentication mecanisms available");
}
}