Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
813f09a314 | ||
|
|
6a6023431b | ||
|
|
7f6aa0ffae | ||
|
|
1830f084c0 | ||
|
|
49a995f68d | ||
|
|
2fd5147a0f | ||
|
|
9c34b5a055 |
@@ -1,14 +1,13 @@
|
||||
[package]
|
||||
|
||||
name = "smtp"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
description = "Simple SMTP client"
|
||||
readme = "README.md"
|
||||
documentation = "http://amousset.github.io/rust-smtp/smtp/"
|
||||
documentation = "http://amousset.me/rust-smtp/smtp/"
|
||||
repository = "https://github.com/amousset/rust-smtp"
|
||||
homepage = "https://github.com/amousset/rust-smtp"
|
||||
license = "MIT/Apache-2.0"
|
||||
authors = ["Alexis Mousset <contact@amousset.me>"]
|
||||
license = "MIT"
|
||||
authors = ["Alexis Mousset <alexis.mousset@gmx.fr>"]
|
||||
keywords = ["email", "smtp", "mailer"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
rust-smtp [](https://travis-ci.org/amousset/rust-smtp) [](https://coveralls.io/github/amousset/rust-smtp?branch=master) [](https://crates.io/crates/smtp)[](./LICENSE)
|
||||
rust-smtp [](https://travis-ci.org/amousset/rust-smtp) [](https://coveralls.io/github/amousset/rust-smtp?branch=master) [](https://crates.io/crates/smtp) [](./LICENSE)
|
||||
=========
|
||||
|
||||
This library implements a simple SMTP client.
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
//!
|
||||
|
||||
@@ -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)"));
|
||||
|
||||
@@ -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,26 +200,28 @@ 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");
|
||||
}
|
||||
}
|
||||
|
||||
let current_message = try!(email.message_id().ok_or("Missing Message-ID"));
|
||||
let from_address = try!(email.from_address().ok_or("Missing Message-ID"));
|
||||
let to_addresses = try!(email.to_addresses().ok_or("Missing Message-ID"));
|
||||
let message = try!(email.message().ok_or("Missing Message-ID"));
|
||||
let from_address = try!(email.from_address().ok_or("Missing From address"));
|
||||
let to_addresses = try!(email.to_addresses().ok_or("Missing To address"));
|
||||
let message = try!(email.message().ok_or("Missing message"));
|
||||
|
||||
// Mail
|
||||
let mail_options = match self.server_info.as_ref().unwrap().supports_feature(&Extension::EightBitMime) {
|
||||
|
||||
Reference in New Issue
Block a user