Add some configuration management

This commit is contained in:
Alexis Mousset
2014-12-15 23:51:52 +01:00
parent 1449d85035
commit 57b533c59a
4 changed files with 79 additions and 43 deletions

View File

@@ -35,11 +35,8 @@ fn sendmail(source_address: &str, recipient_addresses: &[&str], message: &str, s
email.subject(subject);
email.date_now();
let mut client =
Client::new(
(server, port),
Some(my_hostname),
);
let mut client = Client::new((server, port));
client.set_hello_name(my_hostname);
client.send(email)
}

View File

@@ -32,6 +32,23 @@ pub mod server_info;
pub mod connecter;
pub mod stream;
/// Represents the configuration of a client
#[deriving(Clone)]
pub struct Configuration {
/// Maximum connection reuse
///
/// Zero means no limitation
pub connection_reuse_count_limit: uint,
/// Enable connection reuse
pub enable_connection_reuse: bool,
/// Maximum recipients
pub destination_recipient_limit: uint,
/// Maximum line length
pub line_length_limit: uint,
/// Name sent during HELO or EHLO
pub hello_name: String,
}
/// Structure that implements the SMTP client
pub struct Client<S = TcpStream> {
/// TCP stream between client and server
@@ -39,8 +56,6 @@ pub struct Client<S = TcpStream> {
stream: Option<S>,
/// Socket we are connecting to
server_addr: SocketAddr,
/// Our hostname for HELO/EHLO commands
my_hostname: String,
/// Information about the server
/// Value is None before HELO/EHLO
server_info: Option<ServerInfo>,
@@ -49,9 +64,11 @@ pub struct Client<S = TcpStream> {
/// Panic state
panic: bool,
/// Connection reuse counter
connection_reuse: uint,
connection_reuse_count: uint,
/// Current message id
current_message: Option<Uuid>,
/// Configuration of the client
configuration: Configuration,
}
macro_rules! try_smtp (
@@ -87,16 +104,22 @@ impl<S = TcpStream> Client<S> {
/// Creates a new SMTP client
///
/// It does not connects to the server, but only create the `Client`
pub fn new<A: ToSocketAddr>(addr: A, my_hostname: Option<&str>) -> Client<S> {
pub fn new<A: ToSocketAddr>(addr: A) -> Client<S> {
Client{
stream: None,
server_addr: addr.to_socket_addr().unwrap(),
my_hostname: my_hostname.unwrap_or("localhost").to_string(),
server_info: None,
state: TransactionState::new(),
panic: false,
connection_reuse: 0,
connection_reuse_count: 0,
current_message: None,
configuration: Configuration {
connection_reuse_count_limit: 100,
enable_connection_reuse: false,
line_length_limit: 998,
destination_recipient_limit: 100,
hello_name: "localhost".to_string(),
}
}
}
@@ -104,7 +127,27 @@ impl<S = TcpStream> Client<S> {
///
/// It does not connects to the server, but only create the `Client`
pub fn localhost() -> Client<S> {
Client::new(("localhost", SMTP_PORT), Some("localhost"))
Client::new(("localhost", SMTP_PORT))
}
/// Set the name used during HELO or EHLO
pub fn set_hello_name(&mut self, name: &str) {
self.configuration.hello_name = name.to_string()
}
/// Set the maximum number of emails sent using one connection
pub fn set_enable_connection_reuse(&mut self, enable: bool) {
self.configuration.enable_connection_reuse = enable
}
/// Set the maximum number of emails sent using one connection
pub fn set_connection_reuse_count_limit(&mut self, count: uint) {
self.configuration.connection_reuse_count_limit = count
}
/// Set the client configuration
pub fn set_configuration(&mut self, configuration: Configuration) {
self.configuration = configuration
}
}
@@ -124,26 +167,17 @@ impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
self.state = TransactionState::new();
self.server_info = None;
self.panic = false;
self.connection_reuse = 0;
self.connection_reuse_count = 0;
self.current_message = None;
}
/// Sends an email
///
/// This method sends a message and closes the SMTP transaction
pub fn send<T: SendableEmail>(&mut self, email: T) -> SmtpResult {
let result = self.send_only(email);
self.close();
result
}
pub fn send<T: SendableEmail>(&mut self, mut email: T) -> SmtpResult {
let max_reuse_reached = self.connection_reuse_count == self.configuration.connection_reuse_count_limit;
/// Sends an email
///
/// This method sends a message and lets the connection opened. It has to be closed with the
/// `close` method after.
pub fn send_only<T: SendableEmail>(&mut self, mut email: T) -> SmtpResult {
// Connect to the server if needed
if self.noop().is_err() {
if max_reuse_reached || self.noop().is_err() {
self.reset();
try!(self.connect());
@@ -165,7 +199,8 @@ impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
}
self.current_message = Some(Uuid::new_v4());
email.set_message_id(format!("<{}@{}>", self.current_message.as_ref().unwrap(), self.my_hostname));
email.set_message_id(format!("<{}@{}>", self.current_message.as_ref().unwrap(),
self.configuration.hello_name.clone()));
let from_address = email.from_address();
let to_addresses = email.to_addresses();
@@ -185,7 +220,13 @@ impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
try_smtp!(self.data() self);
// Message content
self.message(message.as_slice())
let result = self.message(message.as_slice());
if !self.configuration.enable_connection_reuse {
self.close();
}
result
}
/// Connects to the configured server
@@ -257,7 +298,7 @@ impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
/// Send a HELO command and fills `server_info`
pub fn helo(&mut self) -> SmtpResult {
let hostname = self.my_hostname.clone();
let hostname = self.configuration.hello_name.clone();
let result = try!(self.command(Command::Hello(hostname)));
self.server_info = Some(
ServerInfo{
@@ -270,7 +311,7 @@ impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
/// Sends a EHLO command and fills `server_info`
pub fn ehlo(&mut self) -> SmtpResult {
let hostname = self.my_hostname.clone();
let hostname = self.configuration.hello_name.clone();
let result = try!(self.command(Command::ExtendedHello(hostname)));
self.server_info = Some(
ServerInfo{
@@ -369,10 +410,10 @@ impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
if result.is_ok() {
// Increment the connection reuse counter
self.connection_reuse = self.connection_reuse + 1;
self.connection_reuse_count = self.connection_reuse_count + 1;
// Log the message
info!("{}: conn_use={}, status=sent ({})", self.current_message.as_ref().unwrap(),
self.connection_reuse, result.as_ref().ok().unwrap());
self.connection_reuse_count, result.as_ref().ok().unwrap());
}
self.current_message = None;

View File

@@ -22,9 +22,6 @@ pub static SMTPS_PORT: Port = 465;
/// Default submission port
pub static SUBMISSION_PORT: Port = 587;
// Maximum length of an SMTP command line
//pub static MAX_SMTP_LINE_LENGTH: uint = 1034;
/// The word separator for SMTP transactions
pub static SP: &'static str = " ";

View File

@@ -44,7 +44,6 @@
//! let mut client = Client::localhost();
//! // Send the email
//! let result = client.send(email);
//! client.close();
//!
//! assert!(result.is_ok());
//! ```
@@ -73,15 +72,19 @@
//!
//! let mut client = Client::new(
//! ("server.tld", 10025), // remote server and custom port
//! Some("my.hostname.tld"), // my hostname
//! );
//! // Set the name sent during EHLO/HELO, default is `localhost`
//! client.set_hello_name("my.hostname.tld");
//! // Enable connection reuse
//! client.set_enable_connection_reuse(true);
//!
//! let result_1 = client.send_only(email.clone());
//! let result_1 = client.send(email.clone());
//! assert!(result_1.is_ok());
//! let result_2 = client.send_only(email);
//! let result_2 = client.send(email);
//! assert!(result_2.is_ok());
//! // Explicitely close the SMTP transaction
//! client.close()
//!
//! // Explicitely close the SMTP transaction as we enabled connection reuse
//! client.close();
//! ```
//!
//! ### Using the client directly
@@ -102,7 +105,6 @@
//!
//! let mut client = Client::new(
//! "localhost", // server socket
//! Some("my.hostname.tld"), // my hostname (default is localhost)
//! );
//! let result = client.send(email);
//! assert!(result.is_ok());
@@ -119,7 +121,6 @@
//!
//! let mut email_client = Client::new(
//! ("localhost", SMTP_PORT), // server socket
//! Some("my.hostname.tld"), // my hostname (default is localhost)
//! );
//! let _ = email_client.connect();
//! let _ = email_client.ehlo();