Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4efb560bc8 | ||
|
|
500c4fb39d | ||
|
|
d488910010 | ||
|
|
4155e44dbd | ||
|
|
401118ee68 | ||
|
|
e6dd9d5a46 | ||
|
|
c8187c4a7c | ||
|
|
8f211c88a8 | ||
|
|
62df24c5b1 | ||
|
|
7ac43b73c3 | ||
|
|
3c91c065d6 | ||
|
|
9e30e7185e | ||
|
|
4da9e16bfc | ||
|
|
2977eb0509 | ||
|
|
2884da8f90 | ||
|
|
31a7504d54 | ||
|
|
9a93feea96 | ||
|
|
f102f321d3 | ||
|
|
1ba47e473c | ||
|
|
3acf21a316 | ||
|
|
544894def9 | ||
|
|
f74fb4f89c | ||
|
|
085998c730 | ||
|
|
d3d7c4b44e |
@@ -1,10 +1,10 @@
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
install:
|
||||
- ps: Start-FileDownload 'http://slproweb.com/download/Win64OpenSSL-1_0_2d.exe'
|
||||
- ps: Start-Process "Win64OpenSSL-1_0_2d.exe" -ArgumentList "/silent /verysilent /sp- /suppressmsgboxes" -Wait
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" -FileName "rust-nightly.exe"
|
||||
- ps: .\rust-nightly.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
|
||||
- ps: $env:PATH="$env:PATH;C:\rust\bin"
|
||||
@@ -12,4 +12,4 @@ install:
|
||||
- cargo -vV
|
||||
build: false
|
||||
test_script:
|
||||
- cargo test --verbose --no-default-features
|
||||
- env OPENSSL_LIB_DIR=C:/OpenSSL-Win64 OPENSSL_INCLUDE_DIR=C:/OpenSSL-Win64/include cargo build --verbose
|
||||
|
||||
37
.travis.yml
37
.travis.yml
@@ -1,20 +1,43 @@
|
||||
language: rust
|
||||
sudo: required
|
||||
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
pip: true
|
||||
directories:
|
||||
- target/debug/deps
|
||||
- target/debug/build
|
||||
- target/release/deps
|
||||
- target/release/build
|
||||
|
||||
install: pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- postfix
|
||||
- libcurl4-openssl-dev
|
||||
- libelf-dev
|
||||
- libdw-dev
|
||||
|
||||
before_script:
|
||||
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
||||
- smtp-sink 2525 1000&
|
||||
|
||||
script:
|
||||
- |
|
||||
travis-cargo build &&
|
||||
travis-cargo test &&
|
||||
travis-cargo doc
|
||||
- travis-cargo build
|
||||
- travis-cargo test
|
||||
- travis-cargo doc
|
||||
|
||||
after_success:
|
||||
- travis-cargo --only nightly bench
|
||||
- travis-cargo --only stable doc-upload
|
||||
- travis-cargo --only stable coveralls
|
||||
- travis-cargo --only stable coveralls --no-sudo
|
||||
|
||||
env:
|
||||
global:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
|
||||
name = "lettre"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
description = "Email client"
|
||||
readme = "README.md"
|
||||
documentation = "http://lettre.github.io/lettre/"
|
||||
|
||||
@@ -11,9 +11,14 @@ To use this library, add the following to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
lettre = "0.4"
|
||||
lettre = "0.5"
|
||||
```
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
The tests require a mail server listening locally on port 25.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
||||
47
benches/transport_smtp.rs
Normal file
47
benches/transport_smtp.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate lettre;
|
||||
extern crate test;
|
||||
|
||||
use lettre::transport::smtp::SmtpTransportBuilder;
|
||||
use lettre::transport::EmailTransport;
|
||||
use lettre::mailer::Mailer;
|
||||
use lettre::email::EmailBuilder;
|
||||
|
||||
#[bench]
|
||||
fn bench_simple_send(b: &mut test::Bencher) {
|
||||
let sender = SmtpTransportBuilder::new("127.0.0.1:2525").unwrap().build();
|
||||
let mut mailer = Mailer::new(sender);
|
||||
b.iter(|| {
|
||||
let email = EmailBuilder::new()
|
||||
.to("root@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = mailer.send(email);
|
||||
assert!(result.is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_reuse_send(b: &mut test::Bencher) {
|
||||
let sender = SmtpTransportBuilder::new("127.0.0.1:2525")
|
||||
.unwrap()
|
||||
.connection_reuse(true)
|
||||
.build();
|
||||
let mut mailer = Mailer::new(sender);
|
||||
b.iter(|| {
|
||||
let email = EmailBuilder::new()
|
||||
.to("root@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = mailer.send(email);
|
||||
assert!(result.is_ok());
|
||||
});
|
||||
mailer.close()
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
extern crate lettre;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
use lettre::transport::smtp::SmtpTransportBuilder;
|
||||
use lettre::transport::EmailTransport;
|
||||
use lettre::mailer::Mailer;
|
||||
use lettre::email::EmailBuilder;
|
||||
|
||||
fn main() {
|
||||
env_logger::init().unwrap();
|
||||
|
||||
let sender = SmtpTransportBuilder::localhost().unwrap().hello_name("localhost")
|
||||
.connection_reuse(true).build();
|
||||
let mailer = Arc::new(Mutex::new(Mailer::new(sender)));
|
||||
|
||||
let mut threads = Vec::new();
|
||||
for _ in 1..5 {
|
||||
|
||||
let th_mailer = mailer.clone();
|
||||
threads.push(thread::spawn(move || {
|
||||
|
||||
let email = EmailBuilder::new()
|
||||
.to("user@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build().unwrap();
|
||||
|
||||
let _ = th_mailer.lock().unwrap().send(email);
|
||||
}));
|
||||
}
|
||||
|
||||
for thread in threads {
|
||||
let _ = thread.join();
|
||||
}
|
||||
|
||||
let email = EmailBuilder::new()
|
||||
.to("user@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello Bis")
|
||||
.build().unwrap();
|
||||
|
||||
let mut mailer = mailer.lock().unwrap();
|
||||
let result = mailer.send(email);
|
||||
mailer.close();
|
||||
|
||||
match result {
|
||||
Ok(..) => info!("Email sent successfully"),
|
||||
Err(error) => error!("{:?}", error),
|
||||
}
|
||||
}
|
||||
20
examples/transport_file.rs
Normal file
20
examples/transport_file.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
extern crate lettre;
|
||||
|
||||
use lettre::transport::file::FileEmailTransport;
|
||||
use lettre::transport::EmailTransport;
|
||||
use lettre::email::EmailBuilder;
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut sender = FileEmailTransport::new("/tmp/");
|
||||
let email = EmailBuilder::new()
|
||||
.to("root@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = sender.send(email);
|
||||
println!("{:?}", result);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
@@ -165,10 +165,10 @@ impl EmailBuilder {
|
||||
/// Build the Email
|
||||
pub fn build(mut self) -> Result<Email, &'static str> {
|
||||
if self.from.is_none() {
|
||||
return Err("No from address")
|
||||
return Err("No from address");
|
||||
}
|
||||
if self.to.is_empty() {
|
||||
return Err("No to address")
|
||||
return Err("No to address");
|
||||
}
|
||||
|
||||
if !self.date_issued {
|
||||
|
||||
41
src/lib.rs
41
src/lib.rs
@@ -1,14 +1,18 @@
|
||||
//! # Rust email 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 an application to a
|
||||
//! relay email server, as it relies as much as possible on the relay server for sanity and RFC
|
||||
//! 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 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)) with PLAIN and CRAM-MD5 mecanisms
|
||||
//! * AUTH ([RFC 4954](http://tools.ietf.org/html/rfc4954)) with PLAIN and
|
||||
//! CRAM-MD5 mecanisms
|
||||
//! * STARTTLS ([RFC 2487](http://tools.ietf.org/html/rfc2487))
|
||||
//! * SMTPUTF8 ([RFC 6531](http://tools.ietf.org/html/rfc6531))
|
||||
//!
|
||||
@@ -26,11 +30,10 @@
|
||||
//!
|
||||
//! This is the most basic example of usage:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! ```rust
|
||||
//! use lettre::transport::smtp::{SmtpTransport, SmtpTransportBuilder};
|
||||
//! use lettre::email::EmailBuilder;
|
||||
//! use lettre::transport::EmailTransport;
|
||||
//! use lettre::mailer::Mailer;
|
||||
//!
|
||||
//! // Create an email
|
||||
//! let email = EmailBuilder::new()
|
||||
@@ -43,7 +46,8 @@
|
||||
//! .build().unwrap();
|
||||
//!
|
||||
//! // Open a local connection on port 25
|
||||
//! let mut mailer = Mailer::new(SmtpTransportBuilder::localhost().unwrap().build());
|
||||
//! let mut mailer =
|
||||
//! SmtpTransportBuilder::localhost().unwrap().build();
|
||||
//! // Send the email
|
||||
//! let result = mailer.send(email);
|
||||
//!
|
||||
@@ -54,11 +58,11 @@
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use lettre::email::EmailBuilder;
|
||||
//! use lettre::transport::smtp::{SecurityLevel, SmtpTransport, SmtpTransportBuilder};
|
||||
//! use lettre::transport::smtp::{SecurityLevel, SmtpTransport,
|
||||
//! SmtpTransportBuilder};
|
||||
//! use lettre::transport::smtp::authentication::Mecanism;
|
||||
//! use lettre::transport::smtp::SUBMISSION_PORT;
|
||||
//! use lettre::transport::EmailTransport;
|
||||
//! use lettre::mailer::Mailer;
|
||||
//!
|
||||
//! let mut builder = EmailBuilder::new();
|
||||
//! builder = builder.to(("user@example.org", "Alias name"));
|
||||
@@ -74,7 +78,8 @@
|
||||
//! let email = builder.build().unwrap();
|
||||
//!
|
||||
//! // Connect to a remote server on a custom port
|
||||
//! let mut mailer = Mailer::new(SmtpTransportBuilder::new(("server.tld", SUBMISSION_PORT)).unwrap()
|
||||
//! let mut mailer = SmtpTransportBuilder::new(("server.tld",
|
||||
//! SUBMISSION_PORT)).unwrap()
|
||||
//! // Set the name sent during EHLO/HELO, default is `localhost`
|
||||
//! .hello_name("my.hostname.tld")
|
||||
//! // Add credentials for authentication
|
||||
@@ -87,7 +92,7 @@
|
||||
//! // Configure accepted authetication mecanisms
|
||||
//! .authentication_mecanisms(vec![Mecanism::CramMd5])
|
||||
//! // Enable connection reuse
|
||||
//! .connection_reuse(true).build());
|
||||
//! .connection_reuse(true).build();
|
||||
//!
|
||||
//! let result_1 = mailer.send(email.clone());
|
||||
//! assert!(result_1.is_ok());
|
||||
@@ -104,11 +109,10 @@
|
||||
//!
|
||||
//! If you just want to send an email without using `Email` to provide headers:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! ```rust
|
||||
//! use lettre::email::SimpleSendableEmail;
|
||||
//! use lettre::transport::smtp::{SmtpTransport, SmtpTransportBuilder};
|
||||
//! use lettre::transport::EmailTransport;
|
||||
//! use lettre::mailer::Mailer;
|
||||
//!
|
||||
//! // Create a minimal email
|
||||
//! let email = SimpleSendableEmail::new(
|
||||
@@ -117,16 +121,18 @@
|
||||
//! "Hello world !"
|
||||
//! );
|
||||
//!
|
||||
//! let mut mailer = Mailer::new(SmtpTransportBuilder::localhost().unwrap().build());
|
||||
//! let mut mailer =
|
||||
//! SmtpTransportBuilder::localhost().unwrap().build();
|
||||
//! let result = mailer.send(email);
|
||||
//! assert!(result.is_ok());
|
||||
//! ```
|
||||
//!
|
||||
//! ### Lower level
|
||||
//!
|
||||
//! You can also send commands, here is a simple email transaction without error handling:
|
||||
//! You can also send commands, here is a simple email transaction without
|
||||
//! error handling:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! ```rust
|
||||
//! use lettre::transport::smtp::SMTP_PORT;
|
||||
//! use lettre::transport::smtp::client::Client;
|
||||
//! use lettre::transport::smtp::client::net::NetworkStream;
|
||||
@@ -145,7 +151,7 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustc_serialize as serialize;
|
||||
extern crate rustc_serialize;
|
||||
extern crate crypto;
|
||||
extern crate time;
|
||||
extern crate uuid;
|
||||
@@ -155,4 +161,3 @@ extern crate openssl;
|
||||
|
||||
pub mod transport;
|
||||
pub mod email;
|
||||
pub mod mailer;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
//! TODO
|
||||
|
||||
use transport::EmailTransport;
|
||||
use email::SendableEmail;
|
||||
use transport::error::EmailResult;
|
||||
|
||||
/// TODO
|
||||
pub struct Mailer<T: EmailTransport> {
|
||||
transport: T,
|
||||
}
|
||||
|
||||
impl<T: EmailTransport> Mailer<T> {
|
||||
/// TODO
|
||||
pub fn new(transport: T) -> Mailer<T> {
|
||||
Mailer { transport: transport }
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn send<S: SendableEmail>(&mut self, email: S) -> EmailResult {
|
||||
self.transport.send(email.to_addresses(),
|
||||
email.from_address(),
|
||||
email.message(),
|
||||
email.message_id())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn close(&mut self) {
|
||||
self.transport.close()
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ use std::fmt::{Display, Formatter};
|
||||
use std::fmt;
|
||||
|
||||
use transport::smtp::response::{Severity, Response};
|
||||
use serialize::base64::FromBase64Error;
|
||||
use rustc_serialize::base64::FromBase64Error;
|
||||
use self::Error::*;
|
||||
|
||||
/// An enum of all error kinds.
|
||||
@@ -83,8 +83,3 @@ impl From<&'static str> for Error {
|
||||
|
||||
/// SMTP result type
|
||||
pub type EmailResult = Result<Response, Error>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// TODO
|
||||
}
|
||||
|
||||
53
src/transport/file/mod.rs
Normal file
53
src/transport/file/mod.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
//! TODO
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
|
||||
use transport::error::EmailResult;
|
||||
use transport::smtp::response::Response;
|
||||
use transport::EmailTransport;
|
||||
use transport::smtp::response::{Code, Category, Severity};
|
||||
use email::SendableEmail;
|
||||
|
||||
|
||||
/// TODO
|
||||
pub struct FileEmailTransport {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl FileEmailTransport {
|
||||
/// Creates a new transport to the given directory
|
||||
pub fn new<P: AsRef<Path>>(path: P) -> FileEmailTransport {
|
||||
let mut path_buf = PathBuf::new();
|
||||
path_buf.push(path);
|
||||
FileEmailTransport { path: path_buf }
|
||||
}
|
||||
}
|
||||
|
||||
impl EmailTransport for FileEmailTransport {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
|
||||
let mut file = self.path.clone();
|
||||
file.push(format!("{}.txt", email.message_id()));
|
||||
|
||||
let mut f = try!(File::create(file.as_path()));
|
||||
|
||||
let log_line = format!("{}: from=<{}> to=<{}>\n",
|
||||
email.message_id(),
|
||||
email.from_address(),
|
||||
email.to_addresses().join("> to=<"));
|
||||
|
||||
try!(f.write_all(log_line.as_bytes()));
|
||||
try!(f.write_all(format!("{}", email.message()).as_bytes()));
|
||||
|
||||
info!("{} status=<written>", log_line);
|
||||
|
||||
Ok(Response::new(Code::new(Severity::PositiveCompletion, Category::MailSystem, 0),
|
||||
vec![format!("Ok: email written to {}",
|
||||
file.to_str().unwrap_or("non-UTF-8 path"))]))
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
()
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,16 @@
|
||||
//! TODO
|
||||
//! Represents an Email transport
|
||||
pub mod smtp;
|
||||
pub mod stub;
|
||||
pub mod error;
|
||||
pub mod stub;
|
||||
pub mod file;
|
||||
|
||||
use transport::error::EmailResult;
|
||||
use email::SendableEmail;
|
||||
|
||||
/// Transport method for emails
|
||||
pub trait EmailTransport {
|
||||
/// Sends the email
|
||||
fn send(&mut self,
|
||||
to_addresses: Vec<String>,
|
||||
from_address: String,
|
||||
message: String,
|
||||
message_id: String)
|
||||
-> EmailResult;
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult;
|
||||
/// Close the transport explicitely
|
||||
fn close(&mut self);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fmt;
|
||||
|
||||
use serialize::base64::{self, ToBase64, FromBase64};
|
||||
use serialize::hex::ToHex;
|
||||
use rustc_serialize::base64::{self, ToBase64, FromBase64};
|
||||
use rustc_serialize::hex::ToHex;
|
||||
use crypto::hmac::Hmac;
|
||||
use crypto::md5::Md5;
|
||||
use crypto::mac::Mac;
|
||||
|
||||
@@ -27,8 +27,8 @@ fn escape_dot(string: &str) -> String {
|
||||
} else {
|
||||
string.to_string()
|
||||
}
|
||||
.replace("\r.", "\r..")
|
||||
.replace("\n.", "\n..")
|
||||
.replace("\r.", "\r..")
|
||||
.replace("\n.", "\n..")
|
||||
}
|
||||
|
||||
/// Returns the string replacing all the CRLF with "\<CRLF\>"
|
||||
@@ -80,7 +80,6 @@ impl<S: Connector + Write + Read + Debug + Clone = NetworkStream> Client<S> {
|
||||
|
||||
/// Upgrades the underlying connection to SSL/TLS
|
||||
pub fn upgrade_tls_stream(&mut self, ssl_context: &SslContext) -> io::Result<()> {
|
||||
//let current_stream = self.stream.clone();
|
||||
if self.stream.is_some() {
|
||||
self.stream.as_mut().unwrap().get_mut().upgrade_tls(ssl_context)
|
||||
} else {
|
||||
|
||||
@@ -5,12 +5,12 @@ use std::net::{SocketAddr, ToSocketAddrs};
|
||||
|
||||
use openssl::ssl::{SslMethod, SslContext};
|
||||
|
||||
use email::SendableEmail;
|
||||
use transport::smtp::extension::{Extension, ServerInfo};
|
||||
use transport::error::{EmailResult, Error};
|
||||
use transport::smtp::client::Client;
|
||||
use transport::smtp::authentication::Mecanism;
|
||||
use transport::EmailTransport;
|
||||
use email::SendableEmail;
|
||||
|
||||
pub mod extension;
|
||||
pub mod authentication;
|
||||
@@ -18,7 +18,8 @@ pub mod response;
|
||||
pub mod client;
|
||||
|
||||
// Registrated port numbers:
|
||||
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
|
||||
// https://www.iana.
|
||||
// org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
|
||||
|
||||
/// Default smtp port
|
||||
pub static SMTP_PORT: u16 = 25;
|
||||
@@ -244,12 +245,14 @@ impl SmtpTransport {
|
||||
|
||||
impl EmailTransport for SmtpTransport {
|
||||
/// Sends an email
|
||||
fn send(&mut self,
|
||||
to_addresses: Vec<String>,
|
||||
from_address: String,
|
||||
message: String,
|
||||
message_id: String)
|
||||
-> EmailResult {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
|
||||
|
||||
// Extract email information
|
||||
let message_id = email.message_id();
|
||||
let from_address = email.from_address();
|
||||
let to_addresses = email.to_addresses();
|
||||
let message = email.message();
|
||||
|
||||
// Check if the connection is still available
|
||||
if self.state.connection_reuse_count > 0 {
|
||||
if !self.client.is_connected() {
|
||||
@@ -257,7 +260,8 @@ impl EmailTransport for SmtpTransport {
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a usable connection, test if the server answers and hello has been sent
|
||||
// If there is a usable connection, test if the server answers and hello has
|
||||
// been sent
|
||||
if self.state.connection_reuse_count == 0 {
|
||||
try!(self.client.connect(&self.client_info.server_addr));
|
||||
|
||||
@@ -305,13 +309,13 @@ impl EmailTransport for SmtpTransport {
|
||||
|
||||
// Mail
|
||||
let mail_options = match (self.server_info
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.supports_feature(&Extension::EightBitMime),
|
||||
self.server_info
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.supports_feature(&Extension::EightBitMime)) {
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.supports_feature(&Extension::EightBitMime),
|
||||
self.server_info
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.supports_feature(&Extension::SmtpUtfEight)) {
|
||||
(true, true) => Some("BODY=8BITMIME SMTPUTF8"),
|
||||
(true, false) => Some("BODY=8BITMIME"),
|
||||
(false, _) => None,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//! SMTP response, containing a mandatory return code and an optional text message
|
||||
//! SMTP response, containing a mandatory return code and an optional text
|
||||
//! message
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
//! TODO
|
||||
//! This transport is a stub that only logs the message, and always returns
|
||||
//! succes
|
||||
|
||||
use transport::error::EmailResult;
|
||||
use transport::smtp::response::Response;
|
||||
use transport::EmailTransport;
|
||||
use transport::smtp::response::{Code, Category, Severity};
|
||||
use email::SendableEmail;
|
||||
|
||||
/// TODO
|
||||
/// This transport does nothing exept logging the message enveloppe
|
||||
pub struct StubEmailTransport;
|
||||
|
||||
impl EmailTransport for StubEmailTransport {
|
||||
fn send(&mut self,
|
||||
to_addresses: Vec<String>,
|
||||
from_address: String,
|
||||
message: String,
|
||||
message_id: String)
|
||||
-> EmailResult {
|
||||
fn send<T: SendableEmail>(&mut self, email: T) -> EmailResult {
|
||||
|
||||
let _ = message;
|
||||
info!("message '{}': from '{}' to '{:?}'",
|
||||
message_id,
|
||||
from_address,
|
||||
to_addresses);
|
||||
info!("{}: from=<{}> to=<{:?}>",
|
||||
email.message_id(),
|
||||
email.from_address(),
|
||||
email.to_addresses());
|
||||
Ok(Response::new(Code::new(Severity::PositiveCompletion, Category::MailSystem, 0),
|
||||
vec!["Ok: email logged".to_string()]))
|
||||
}
|
||||
|
||||
17
tests/lib.rs
17
tests/lib.rs
@@ -1,14 +1,5 @@
|
||||
// Copyright 2014 Alexis Mousset. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
extern crate lettre;
|
||||
|
||||
#[test]
|
||||
|
||||
fn foo() {
|
||||
assert!(true);
|
||||
}
|
||||
mod transport_smtp;
|
||||
mod transport_stub;
|
||||
mod transport_file;
|
||||
|
||||
34
tests/transport_file.rs
Normal file
34
tests/transport_file.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
extern crate lettre;
|
||||
|
||||
use std::env::temp_dir;
|
||||
use std::fs::File;
|
||||
use std::fs::remove_file;
|
||||
use std::io::Read;
|
||||
|
||||
use lettre::transport::file::FileEmailTransport;
|
||||
use lettre::transport::EmailTransport;
|
||||
use lettre::email::{SendableEmail, EmailBuilder};
|
||||
|
||||
#[test]
|
||||
fn file_transport() {
|
||||
let mut sender = FileEmailTransport::new(temp_dir());
|
||||
let email = EmailBuilder::new()
|
||||
.to("root@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = sender.send(email.clone());
|
||||
assert!(result.is_ok());
|
||||
|
||||
let message_id = email.message_id();
|
||||
let file = format!("{}/{}.txt", temp_dir().to_str().unwrap(), message_id);
|
||||
let mut f = File::open(file.clone()).unwrap();
|
||||
let mut buffer = String::new();
|
||||
let _ = f.read_to_string(&mut buffer);
|
||||
|
||||
assert_eq!(buffer, format!("{}: from=<user@localhost> to=<root@localhost>\n{}", message_id, email.message()));
|
||||
|
||||
remove_file(file).unwrap();
|
||||
}
|
||||
19
tests/transport_smtp.rs
Normal file
19
tests/transport_smtp.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
extern crate lettre;
|
||||
|
||||
use lettre::transport::smtp::SmtpTransportBuilder;
|
||||
use lettre::transport::EmailTransport;
|
||||
use lettre::email::EmailBuilder;
|
||||
|
||||
#[test]
|
||||
fn simple_sender() {
|
||||
let mut sender = SmtpTransportBuilder::localhost().unwrap().build();
|
||||
let email = EmailBuilder::new()
|
||||
.to("root@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = sender.send(email);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
19
tests/transport_stub.rs
Normal file
19
tests/transport_stub.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
extern crate lettre;
|
||||
|
||||
use lettre::transport::stub::StubEmailTransport;
|
||||
use lettre::transport::EmailTransport;
|
||||
use lettre::email::EmailBuilder;
|
||||
|
||||
#[test]
|
||||
fn stub_transport() {
|
||||
let mut sender = StubEmailTransport;
|
||||
let email = EmailBuilder::new()
|
||||
.to("root@localhost")
|
||||
.from("user@localhost")
|
||||
.body("Hello World!")
|
||||
.subject("Hello")
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = sender.send(email);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
Reference in New Issue
Block a user