Remove last panics

This commit is contained in:
Alexis Mousset
2015-07-23 00:48:37 +02:00
parent c2506b47fc
commit 8d60068831
6 changed files with 74 additions and 62 deletions

View File

@@ -12,7 +12,7 @@ use smtp::email::EmailBuilder;
fn main() {
env_logger::init().unwrap();
let sender = Arc::new(Mutex::new(SenderBuilder::localhost().hello_name("localhost")
let sender = Arc::new(Mutex::new(SenderBuilder::localhost().unwrap().hello_name("localhost")
.enable_connection_reuse(true).build()));
let mut threads = Vec::new();

View File

@@ -46,7 +46,6 @@ pub struct Client<S: Write + Read = SmtpStream> {
stream: Option<BufStream<S>>,
/// Socket we are connecting to
server_addr: SocketAddr,
}
macro_rules! return_err (
@@ -59,10 +58,15 @@ impl<S: Write + Read = SmtpStream> Client<S> {
/// Creates a new SMTP client
///
/// It does not connects to the server, but only creates the `Client`
pub fn new<A: ToSocketAddrs>(addr: A) -> Client<S> {
Client{
pub fn new<A: ToSocketAddrs>(addr: A) -> Result<Client<S>, Error> {
let mut addresses = try!(addr.to_socket_addrs());
match addresses.next() {
Some(addr) => Ok(Client {
stream: None,
server_addr: addr.to_socket_addrs().ok().expect("could not parse server address").next().unwrap(),
server_addr: addr,
}),
None => Err(From::from("Could nor resolve hostname")),
}
}
}

View File

@@ -185,13 +185,13 @@ impl EmailBuilder {
/// Email sendable by an SMTP client
pub trait SendableEmail {
/// From address
fn from_address(&self) -> String;
fn from_address(&self) -> Option<String>;
/// To addresses
fn to_addresses(&self) -> Vec<String>;
fn to_addresses(&self) -> Option<Vec<String>>;
/// Message content
fn message(&self) -> String;
fn message(&self) -> Option<String>;
/// Message ID
fn message_id(&self) -> String;
fn message_id(&self) -> Option<String>;
}
/// Minimal email structure
@@ -216,46 +216,47 @@ impl SimpleSendableEmail {
}
impl SendableEmail for SimpleSendableEmail {
fn from_address(&self) -> String {
self.from.clone()
fn from_address(&self) -> Option<String> {
Some(self.from.clone())
}
fn to_addresses(&self) -> Vec<String> {
self.to.clone()
fn to_addresses(&self) -> Option<Vec<String>> {
Some(self.to.clone())
}
fn message(&self) -> String {
self.message.clone()
fn message(&self) -> Option<String> {
Some(self.message.clone())
}
fn message_id(&self) -> String {
format!("<{}@rust-smtp>", Uuid::new_v4())
fn message_id(&self) -> Option<String> {
Some(format!("<{}@rust-smtp>", Uuid::new_v4()))
}
}
impl SendableEmail for Email {
/// Return the to addresses, and fails if it is not set
fn to_addresses(&self) -> Vec<String> {
fn to_addresses(&self) -> Option<Vec<String>> {
if self.to.is_empty() {
panic!("The To field is empty")
None
} else {
Some(self.to.clone())
}
self.to.clone()
}
/// Return the from address, and fails if it is not set
fn from_address(&self) -> String {
fn from_address(&self) -> Option<String> {
match self.from {
Some(ref from_address) => from_address.clone(),
None => panic!("The From field is empty"),
Some(ref from_address) => Some(from_address.clone()),
None => None,
}
}
fn message(&self) -> String {
format!("{}", self)
fn message(&self) -> Option<String> {
Some(format!("{}", self))
}
fn message_id(&self) -> String {
format!("{}", self.message_id)
fn message_id(&self) -> Option<String> {
Some(format!("{}", self.message_id))
}
}
@@ -295,7 +296,7 @@ mod test {
format!("{}", email),
format!("Message-ID: <{}@rust-smtp>\r\nTo: to@example.com\r\n\r\nbody\r\n", current_message)
);
assert_eq!(current_message.to_string(), email.message_id());
assert_eq!(current_message.to_string(), email.message_id().unwrap());
}
#[test]
@@ -317,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(), date_now.rfc822())
email.message_id().unwrap(), date_now.rfc822())
);
}
@@ -338,15 +339,15 @@ mod test {
.build();
assert_eq!(
email.from_address(),
email.from_address().unwrap(),
"sender@localhost".to_string()
);
assert_eq!(
email.to_addresses(),
email.to_addresses().unwrap(),
vec!["user@localhost".to_string(), "cc@localhost".to_string()]
);
assert_eq!(
email.message(),
email.message().unwrap(),
format!("{}", email)
);
}

View File

@@ -77,11 +77,11 @@ impl ServerInfo {
for line in response.message() {
let splitted : Vec<&str> = line.split_whitespace().collect();
let _ = match (splitted[0], splitted.len()) {
("8BITMIME", 1) => {features.insert(Extension::EightBitMime);},
("SMTPUTF8", 1) => {features.insert(Extension::SmtpUtfEight);},
("STARTTLS", 1) => {features.insert(Extension::StartTls);},
("AUTH", _) => {
let _ = match splitted[0] {
"8BITMIME" => {features.insert(Extension::EightBitMime);},
"SMTPUTF8" => {features.insert(Extension::SmtpUtfEight);},
"STARTTLS" => {features.insert(Extension::StartTls);},
"AUTH" => {
for &mecanism in &splitted[1..] {
match mecanism {
"PLAIN" => {features.insert(Extension::Authentication(Mecanism::Plain));},
@@ -90,7 +90,7 @@ impl ServerInfo {
}
}
},
(_, _) => (),
_ => (),
};
}

View File

@@ -1,13 +1,14 @@
//! # Rust SMTP client
//!
//! This client should tend to follow [RFC 5321](https://tools.ietf.org/html/rfc5321), but is still
//! a work in progress. It is designed to efficiently send emails from a rust application to a
//! relay email server.
//! a work in progress. It is designed to efficiently send emails from an application to a
//! relay email server, as it relies as much as possible on the relay server for sanity and RFC compliance
//! checks.
//!
//! It implements the following extensions:
//!
//! * 8BITMIME ([RFC 6152](https://tools.ietf.org/html/rfc6152))
//! * AUTH ([RFC 4954](http://tools.ietf.org/html/rfc4954))
//! * AUTH ([RFC 4954](http://tools.ietf.org/html/rfc4954)) with PLAIN and CRAM-MD5 mecanisms
//!
//! It will eventually implement the following extensions:
//!
@@ -16,7 +17,7 @@
//!
//! ## Architecture
//!
//! This client is divided into three parts:
//! This client is divided into three main parts:
//!
//! * client: a low level SMTP client providing all SMTP commands
//! * sender: a high level SMTP client providing an easy method to send emails
@@ -43,7 +44,7 @@
//! .build();
//!
//! // Open a local connection on port 25
//! let mut sender = SenderBuilder::localhost().build();
//! let mut sender = SenderBuilder::localhost().unwrap().build();
//! // Send the email
//! let result = sender.send(email);
//!
@@ -70,7 +71,7 @@
//! let email = builder.build();
//!
//! // Connect to a remote server on a custom port
//! let mut sender = SenderBuilder::new(("server.tld", 10025))
//! let mut sender = SenderBuilder::new(("server.tld", 10025)).unwrap()
//! // Set the name sent during EHLO/HELO, default is `localhost`
//! .hello_name("my.hostname.tld")
//! // Add credentials for authentication
@@ -104,7 +105,7 @@
//! "Hello world !"
//! );
//!
//! let mut sender = SenderBuilder::localhost().build();
//! let mut sender = SenderBuilder::localhost().unwrap().build();
//! let result = sender.send(email);
//! assert!(result.is_ok());
//! ```
@@ -119,7 +120,7 @@
//! use smtp::SMTP_PORT;
//! use std::net::TcpStream;
//!
//! let mut email_client: Client<SmtpStream> = Client::new(("localhost", SMTP_PORT));
//! let mut email_client: Client<SmtpStream> = Client::new(("localhost", SMTP_PORT)).unwrap();
//! let _ = email_client.connect();
//! let _ = email_client.ehlo("my_hostname");
//! let _ = email_client.mail("user@example.com", None);

View File

@@ -30,18 +30,24 @@ pub struct SenderBuilder {
/// Builder for the SMTP Sender
impl SenderBuilder {
/// Creates a new local SMTP client
pub fn new<A: ToSocketAddrs>(addr: A) -> SenderBuilder {
SenderBuilder {
server_addr: addr.to_socket_addrs().ok().expect("could not parse server address").next().unwrap(),
pub fn new<A: ToSocketAddrs>(addr: A) -> Result<SenderBuilder, Error> {
let mut addresses = try!(addr.to_socket_addrs());
match addresses.next() {
Some(addr) => Ok(SenderBuilder {
server_addr: addr,
credentials: None,
connection_reuse_count_limit: 100,
enable_connection_reuse: false,
hello_name: "localhost".to_string(),
}),
None => Err(From::from("Could nor resolve hostname")),
}
}
/// Creates a new local SMTP client to port 25
pub fn localhost() -> SenderBuilder {
pub fn localhost() -> Result<SenderBuilder, Error> {
SenderBuilder::new(("localhost", SMTP_PORT))
}
@@ -119,7 +125,7 @@ impl Sender {
///
/// It does not connects to the server, but only creates the `Sender`
pub fn new(builder: SenderBuilder) -> Sender {
let client: Client<SmtpStream> = Client::new(builder.server_addr);
let client: Client<SmtpStream> = Client::new(builder.server_addr).unwrap();
Sender{
client: client,
server_info: None,
@@ -201,10 +207,10 @@ impl Sender {
}
}
let current_message = email.message_id();
let from_address = email.from_address();
let to_addresses = email.to_addresses();
let message = email.message();
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"));
// Mail
let mail_options = match self.server_info.as_ref().unwrap().supports_feature(&Extension::EightBitMime) {