Remove last panics
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
55
src/email.rs
55
src/email.rs
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
},
|
||||
(_, _) => (),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
17
src/lib.rs
17
src/lib.rs
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user