Merge pull request #128 from amousset/split-crates-transport
Split crates
This commit is contained in:
25
.travis.yml
25
.travis.yml
@@ -4,6 +4,7 @@ rust:
|
|||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
|
- 1.13.0
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
@@ -12,39 +13,25 @@ matrix:
|
|||||||
sudo: required
|
sudo: required
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
apt: true
|
|
||||||
pip: true
|
|
||||||
directories:
|
directories:
|
||||||
- target/debug/deps
|
- target/debug/deps
|
||||||
- target/debug/build
|
- target/debug/build
|
||||||
- target/release/deps
|
- target/release/deps
|
||||||
- target/release/build
|
- target/release/build
|
||||||
|
|
||||||
install:
|
|
||||||
- pip install 'travis-cargo<0.2' --user
|
|
||||||
- export PATH=$HOME/.local/bin:$PATH
|
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- postfix
|
- postfix
|
||||||
- libcurl4-openssl-dev
|
|
||||||
- libelf-dev
|
|
||||||
- libdw-dev
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- smtp-sink 2525 1000&
|
- smtp-sink 2525 1000&
|
||||||
- sudo chgrp -R postdrop /var/spool/postfix/maildrop
|
- sudo chgrp -R postdrop /var/spool/postfix/maildrop
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- travis-cargo build
|
- |
|
||||||
- travis-cargo test
|
cd lettre && cargo build && cargo test
|
||||||
- travis-cargo doc
|
cd ../lettre_email && cargo build && cargo test
|
||||||
|
|
||||||
after_success:
|
|
||||||
- ./.travis/doc.sh
|
|
||||||
- ./.travis/coverage.sh
|
|
||||||
- travis-cargo --only nightly bench
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -o errexit
|
|
||||||
|
|
||||||
if [ "$TRAVIS_RUST_VERSION" != "stable" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
cargo test --no-run
|
|
||||||
|
|
||||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz
|
|
||||||
tar xzf master.tar.gz
|
|
||||||
mkdir kcov-master/build
|
|
||||||
cd kcov-master/build
|
|
||||||
cmake ..
|
|
||||||
make
|
|
||||||
make install DESTDIR=../tmp
|
|
||||||
cd ../..
|
|
||||||
ls target/debug
|
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo target/kcov target/debug/lettre-*
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -o errexit
|
|
||||||
|
|
||||||
if [ "$TRAVIS_RUST_VERSION" != "stable" ] || [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
cargo clean
|
|
||||||
cargo doc --no-deps
|
|
||||||
|
|
||||||
git clone --branch gh-pages "https://$GH_TOKEN@github.com/${TRAVIS_REPO_SLUG}.git" deploy_docs
|
|
||||||
cd deploy_docs
|
|
||||||
|
|
||||||
git config user.email "contact@amousset.me"
|
|
||||||
git config user.name "Alexis Mousset"
|
|
||||||
|
|
||||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
|
||||||
rm -rf master
|
|
||||||
mv ../target/doc ./master
|
|
||||||
echo "<meta http-equiv=refresh content=0;url=lettre/index.html>" > ./master/index.html
|
|
||||||
elif [ "$TRAVIS_TAG" != "" ]; then
|
|
||||||
rm -rf $TRAVIS_TAG
|
|
||||||
mv ../target/doc ./$TRAVIS_TAG
|
|
||||||
echo "<meta http-equiv=refresh content=0;url=lettre/index.html>" > ./$TRAVIS_TAG/index.html
|
|
||||||
|
|
||||||
latest=$(echo * | tr " " "\n" | sort -V -r | head -n1)
|
|
||||||
if [ "$TRAVIS_TAG" == "$latest" ]; then
|
|
||||||
|
|
||||||
echo "<meta http-equiv=refresh content=0;url=$latest/lettre/index.html>" > index.html
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
git add -A .
|
|
||||||
git commit -m "Rebuild pages at ${TRAVIS_COMMIT}"
|
|
||||||
git push --quiet origin gh-pages
|
|
||||||
34
Cargo.toml
34
Cargo.toml
@@ -1,29 +1,5 @@
|
|||||||
[package]
|
[workspace]
|
||||||
|
members = [
|
||||||
name = "lettre"
|
"lettre",
|
||||||
version = "0.6.2"
|
"lettre_email",
|
||||||
description = "Email client"
|
]
|
||||||
readme = "README.md"
|
|
||||||
documentation = "https://docs.rs/lettre/"
|
|
||||||
repository = "https://github.com/lettre/lettre"
|
|
||||||
license = "MIT"
|
|
||||||
authors = ["Alexis Mousset <contact@amousset.me>"]
|
|
||||||
keywords = ["email", "smtp", "mailer"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bufstream = "^0.1"
|
|
||||||
email = "^0.0"
|
|
||||||
log = "^0.3"
|
|
||||||
mime = "^0.2"
|
|
||||||
openssl = "^0.9"
|
|
||||||
base64 = "~0.5.0"
|
|
||||||
hex = "^0.2.0"
|
|
||||||
rust-crypto = "^0.2"
|
|
||||||
time = "^0.1"
|
|
||||||
uuid = { version = ">=0.4, <0.6", features = ["v4"] }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
env_logger = "^0.4"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
unstable = []
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate lettre;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use lettre::transport::smtp::SmtpTransportBuilder;
|
|
||||||
use lettre::transport::EmailTransport;
|
|
||||||
use lettre::email::EmailBuilder;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_simple_send(b: &mut test::Bencher) {
|
|
||||||
let mut sender = SmtpTransportBuilder::new("127.0.0.1:2525").unwrap().build();
|
|
||||||
b.iter(|| {
|
|
||||||
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());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_reuse_send(b: &mut test::Bencher) {
|
|
||||||
let mut sender = SmtpTransportBuilder::new("127.0.0.1:2525")
|
|
||||||
.unwrap()
|
|
||||||
.connection_reuse(true)
|
|
||||||
.build();
|
|
||||||
b.iter(|| {
|
|
||||||
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());
|
|
||||||
});
|
|
||||||
sender.close()
|
|
||||||
}
|
|
||||||
29
lettre/Cargo.toml
Normal file
29
lettre/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
[package]
|
||||||
|
|
||||||
|
name = "lettre"
|
||||||
|
version = "0.7.0"
|
||||||
|
description = "Email client"
|
||||||
|
readme = "README.md"
|
||||||
|
documentation = "https://docs.rs/lettre/"
|
||||||
|
repository = "https://github.com/lettre/lettre"
|
||||||
|
license = "MIT"
|
||||||
|
authors = ["Alexis Mousset <contact@amousset.me>"]
|
||||||
|
categories = ["email"]
|
||||||
|
keywords = ["email", "smtp", "mailer"]
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
travis-ci = { repository = "lettre/lettre" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bufstream = "^0.1"
|
||||||
|
log = "^0.3"
|
||||||
|
openssl = "^0.9"
|
||||||
|
base64 = "^0.5"
|
||||||
|
hex = "^0.2"
|
||||||
|
rust-crypto = "^0.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
env_logger = "^0.4"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
unstable = []
|
||||||
1
lettre/LICENSE
Symbolic link
1
lettre/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../LICENSE
|
||||||
1
lettre/README.md
Symbolic link
1
lettre/README.md
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../README.md
|
||||||
37
lettre/benches/transport_smtp.rs
Normal file
37
lettre/benches/transport_smtp.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate lettre;
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
use lettre::smtp::SmtpTransportBuilder;
|
||||||
|
use lettre::{EmailTransport, SimpleSendableEmail};
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_simple_send(b: &mut test::Bencher) {
|
||||||
|
let mut sender = SmtpTransportBuilder::new("127.0.0.1:2525").unwrap().build();
|
||||||
|
b.iter(|| {
|
||||||
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
|
vec!["root@localhost"],
|
||||||
|
"id",
|
||||||
|
"Hello world");
|
||||||
|
let result = sender.send(email);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_reuse_send(b: &mut test::Bencher) {
|
||||||
|
let mut sender = SmtpTransportBuilder::new("127.0.0.1:2525")
|
||||||
|
.unwrap()
|
||||||
|
.connection_reuse(true)
|
||||||
|
.build();
|
||||||
|
b.iter(|| {
|
||||||
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
|
vec!["root@localhost"],
|
||||||
|
"file_id",
|
||||||
|
"Hello file");
|
||||||
|
let result = sender.send(email);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
});
|
||||||
|
sender.close()
|
||||||
|
}
|
||||||
24
lettre/examples/smtp.rs
Normal file
24
lettre/examples/smtp.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
extern crate lettre;
|
||||||
|
|
||||||
|
use lettre::{EmailTransport, SimpleSendableEmail};
|
||||||
|
use lettre::smtp::SmtpTransportBuilder;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
|
vec!["root@localhost"],
|
||||||
|
"file_id",
|
||||||
|
"Hello file");
|
||||||
|
|
||||||
|
// Open a local connection on port 25
|
||||||
|
let mut mailer = SmtpTransportBuilder::localhost().unwrap().build();
|
||||||
|
// Send the email
|
||||||
|
let result = mailer.send(email);
|
||||||
|
|
||||||
|
if result.is_ok() {
|
||||||
|
println!("Email sent");
|
||||||
|
} else {
|
||||||
|
println!("Could not send email: {:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
1
lettre/rustfmt.toml
Symbolic link
1
lettre/rustfmt.toml
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../rustfmt.toml
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
//! This transport creates a file for each email, containing the envelope information and the email
|
//! This transport creates a file for each email, containing the envelope information and the email
|
||||||
//! itself.
|
//! itself.
|
||||||
|
|
||||||
use email::SendableEmail;
|
use EmailTransport;
|
||||||
|
use SendableEmail;
|
||||||
|
use file::error::FileResult;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use transport::EmailTransport;
|
|
||||||
use transport::file::error::FileResult;
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ impl EmailTransport<FileResult> for FileEmailTransport {
|
|||||||
|
|
||||||
let log_line = format!("{}: from=<{}> to=<{}>\n",
|
let log_line = format!("{}: from=<{}> to=<{}>\n",
|
||||||
email.message_id(),
|
email.message_id(),
|
||||||
email.envelope().from,
|
email.from(),
|
||||||
email.envelope().to.join("> to=<"));
|
email.to().join("> to=<"));
|
||||||
|
|
||||||
try!(f.write_all(log_line.as_bytes()));
|
try!(f.write_all(log_line.as_bytes()));
|
||||||
try!(f.write_all(email.message().as_bytes()));
|
try!(f.write_all(email.message().as_bytes()));
|
||||||
@@ -2,64 +2,8 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Overview
|
//! ## Overview
|
||||||
//!
|
//!
|
||||||
//! This mailer is divided into:
|
//! This mailer contains the available transports for your emails. To be sendable, the
|
||||||
//!
|
//! emails have to implement `SendableEmail`.
|
||||||
//! * An `email` part: builds the email message
|
|
||||||
//! * A `transport` part: contains the available transports for your emails. To be sendable, the
|
|
||||||
//! emails have to implement `SendableEmail`.
|
|
||||||
//!
|
|
||||||
//! ## Creating messages
|
|
||||||
//!
|
|
||||||
//! The `email` part builds email messages. For now, it does not support attachments.
|
|
||||||
//! An email is built using an `EmailBuilder`. The simplest email could be:
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! use lettre::email::EmailBuilder;
|
|
||||||
//!
|
|
||||||
//! // Create an email
|
|
||||||
//! let email = EmailBuilder::new()
|
|
||||||
//! // Addresses can be specified by the tuple (email, alias)
|
|
||||||
//! .to(("user@example.org", "Firstname Lastname"))
|
|
||||||
//! // ... or by an address only
|
|
||||||
//! .from("user@example.com")
|
|
||||||
//! .subject("Hi, Hello world")
|
|
||||||
//! .text("Hello world.")
|
|
||||||
//! .build();
|
|
||||||
//!
|
|
||||||
//! assert!(email.is_ok());
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! When the `build` method is called, the `EmailBuilder` will add the missing headers (like
|
|
||||||
//! `Message-ID` or `Date`) and check for missing necessary ones (like `From` or `To`). It will
|
|
||||||
//! then generate an `Email` that can be sent.
|
|
||||||
//!
|
|
||||||
//! The `text()` method will create a plain text email, while the `html()` method will create an
|
|
||||||
//! HTML email. You can use the `alternative()` method to provide both versions, using plain text
|
|
||||||
//! as fallback for the HTML version.
|
|
||||||
//!
|
|
||||||
//! Below is a more complete example, not using method chaining:
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! use lettre::email::EmailBuilder;
|
|
||||||
//!
|
|
||||||
//! let mut builder = EmailBuilder::new();
|
|
||||||
//! builder.add_to(("user@example.org", "Alias name"));
|
|
||||||
//! builder.add_cc(("user@example.net", "Alias name"));
|
|
||||||
//! builder.add_from("no-reply@example.com");
|
|
||||||
//! builder.add_from("no-reply@example.eu");
|
|
||||||
//! builder.set_sender("no-reply@example.com");
|
|
||||||
//! builder.set_subject("Hello world");
|
|
||||||
//! builder.set_alternative("<h2>Hi, Hello world.</h2>", "Hi, Hello world.");
|
|
||||||
//! builder.add_reply_to("contact@example.com");
|
|
||||||
//! builder.add_header(("X-Custom-Header", "my header"));
|
|
||||||
//!
|
|
||||||
//! let email = builder.build();
|
|
||||||
//! assert!(email.is_ok());
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! See the `EmailBuilder` documentation for a complete list of methods.
|
|
||||||
//!
|
|
||||||
//! ## Sending messages
|
|
||||||
//!
|
//!
|
||||||
//! The following sections describe the available transport methods to handle emails.
|
//! The following sections describe the available transport methods to handle emails.
|
||||||
//!
|
//!
|
||||||
@@ -93,18 +37,16 @@
|
|||||||
//! This is the most basic example of usage:
|
//! This is the most basic example of usage:
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use lettre::transport::smtp::SmtpTransportBuilder;
|
//! use lettre::{SimpleSendableEmail, EmailTransport};
|
||||||
//! use lettre::email::EmailBuilder;
|
//! use lettre::smtp::SmtpTransportBuilder;
|
||||||
//! use lettre::transport::EmailTransport;
|
//! use lettre::smtp::SecurityLevel;
|
||||||
//! use lettre::transport::smtp::SecurityLevel;
|
|
||||||
//!
|
//!
|
||||||
//! let email = EmailBuilder::new()
|
//! let email = SimpleSendableEmail::new(
|
||||||
//! .to("root@localhost")
|
//! "user@localhost",
|
||||||
//! .from("user@localhost")
|
//! vec!["root@localhost"],
|
||||||
//! .body("Hello World!")
|
//! "message_id",
|
||||||
//! .subject("Hello")
|
//! "Hello world"
|
||||||
//! .build()
|
//! );
|
||||||
//! .unwrap();
|
|
||||||
//!
|
//!
|
||||||
//! // Open a local connection on port 25
|
//! // Open a local connection on port 25
|
||||||
//! let mut mailer =
|
//! let mut mailer =
|
||||||
@@ -118,20 +60,18 @@
|
|||||||
//! #### Complete example
|
//! #### Complete example
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use lettre::email::EmailBuilder;
|
//! use lettre::smtp::{SecurityLevel, SmtpTransport,
|
||||||
//! use lettre::transport::smtp::{SecurityLevel, SmtpTransport,
|
|
||||||
//! SmtpTransportBuilder};
|
//! SmtpTransportBuilder};
|
||||||
//! use lettre::transport::smtp::authentication::Mechanism;
|
//! use lettre::smtp::authentication::Mechanism;
|
||||||
//! use lettre::transport::smtp::SUBMISSION_PORT;
|
//! use lettre::smtp::SUBMISSION_PORT;
|
||||||
//! use lettre::transport::EmailTransport;
|
//! use lettre::{SimpleSendableEmail, EmailTransport};
|
||||||
//!
|
//!
|
||||||
//! let email = EmailBuilder::new()
|
//! let email = SimpleSendableEmail::new(
|
||||||
//! .to("root@localhost")
|
//! "user@localhost",
|
||||||
//! .from("user@localhost")
|
//! vec!["root@localhost"],
|
||||||
//! .body("Hello World!")
|
//! "message_id",
|
||||||
//! .subject("Hello")
|
//! "Hello world"
|
||||||
//! .build()
|
//! );
|
||||||
//! .unwrap();
|
|
||||||
//!
|
//!
|
||||||
//! // Connect to a remote server on a custom port
|
//! // Connect to a remote server on a custom port
|
||||||
//! let mut mailer = SmtpTransportBuilder::new(("server.tld",
|
//! let mut mailer = SmtpTransportBuilder::new(("server.tld",
|
||||||
@@ -167,9 +107,9 @@
|
|||||||
//! error handling:
|
//! error handling:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use lettre::transport::smtp::SMTP_PORT;
|
//! use lettre::smtp::SMTP_PORT;
|
||||||
//! use lettre::transport::smtp::client::Client;
|
//! use lettre::smtp::client::Client;
|
||||||
//! use lettre::transport::smtp::client::net::NetworkStream;
|
//! use lettre::smtp::client::net::NetworkStream;
|
||||||
//!
|
//!
|
||||||
//! let mut email_client: Client<NetworkStream> = Client::new();
|
//! let mut email_client: Client<NetworkStream> = Client::new();
|
||||||
//! let _ = email_client.connect(&("localhost", SMTP_PORT), None);
|
//! let _ = email_client.connect(&("localhost", SMTP_PORT), None);
|
||||||
@@ -186,17 +126,15 @@
|
|||||||
//! The sendmail transport sends the email using the local sendmail command.
|
//! The sendmail transport sends the email using the local sendmail command.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use lettre::transport::sendmail::SendmailTransport;
|
//! use lettre::sendmail::SendmailTransport;
|
||||||
//! use lettre::transport::EmailTransport;
|
//! use lettre::{SimpleSendableEmail, EmailTransport};
|
||||||
//! use lettre::email::EmailBuilder;
|
|
||||||
//!
|
//!
|
||||||
//! let email = EmailBuilder::new()
|
//! let email = SimpleSendableEmail::new(
|
||||||
//! .to("root@localhost")
|
//! "user@localhost",
|
||||||
//! .from("user@localhost")
|
//! vec!["root@localhost"],
|
||||||
//! .body("Hello World!")
|
//! "message_id",
|
||||||
//! .subject("Hello")
|
//! "Hello world"
|
||||||
//! .build()
|
//! );
|
||||||
//! .unwrap();
|
|
||||||
//!
|
//!
|
||||||
//! let mut sender = SendmailTransport::new();
|
//! let mut sender = SendmailTransport::new();
|
||||||
//! let result = sender.send(email);
|
//! let result = sender.send(email);
|
||||||
@@ -209,17 +147,15 @@
|
|||||||
//! testing purposes.
|
//! testing purposes.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use lettre::transport::stub::StubEmailTransport;
|
//! use lettre::stub::StubEmailTransport;
|
||||||
//! use lettre::transport::EmailTransport;
|
//! use lettre::{SimpleSendableEmail, EmailTransport};
|
||||||
//! use lettre::email::EmailBuilder;
|
|
||||||
//!
|
//!
|
||||||
//! let email = EmailBuilder::new()
|
//! let email = SimpleSendableEmail::new(
|
||||||
//! .to("root@localhost")
|
//! "user@localhost",
|
||||||
//! .from("user@localhost")
|
//! vec!["root@localhost"],
|
||||||
//! .body("Hello World!")
|
//! "message_id",
|
||||||
//! .subject("Hello")
|
//! "Hello world"
|
||||||
//! .build()
|
//! );
|
||||||
//! .unwrap();
|
|
||||||
//!
|
//!
|
||||||
//! let mut sender = StubEmailTransport;
|
//! let mut sender = StubEmailTransport;
|
||||||
//! let result = sender.send(email);
|
//! let result = sender.send(email);
|
||||||
@@ -241,19 +177,17 @@
|
|||||||
//! ```rust
|
//! ```rust
|
||||||
//! use std::env::temp_dir;
|
//! use std::env::temp_dir;
|
||||||
//!
|
//!
|
||||||
//! use lettre::transport::file::FileEmailTransport;
|
//! use lettre::file::FileEmailTransport;
|
||||||
//! use lettre::transport::EmailTransport;
|
//! use lettre::{SimpleSendableEmail, EmailTransport};
|
||||||
//! use lettre::email::{EmailBuilder, SendableEmail};
|
|
||||||
//!
|
//!
|
||||||
//! // Write to the local temp directory
|
//! // Write to the local temp directory
|
||||||
//! let mut sender = FileEmailTransport::new(temp_dir());
|
//! let mut sender = FileEmailTransport::new(temp_dir());
|
||||||
//! let email = EmailBuilder::new()
|
//! let email = SimpleSendableEmail::new(
|
||||||
//! .to("root@localhost")
|
//! "user@localhost",
|
||||||
//! .from("user@localhost")
|
//! vec!["root@localhost"],
|
||||||
//! .body("Hello World!")
|
//! "message_id",
|
||||||
//! .subject("Hello")
|
//! "Hello world"
|
||||||
//! .build()
|
//! );
|
||||||
//! .unwrap();
|
|
||||||
//!
|
//!
|
||||||
//! let result = sender.send(email);
|
//! let result = sender.send(email);
|
||||||
//! assert!(result.is_ok());
|
//! assert!(result.is_ok());
|
||||||
@@ -275,16 +209,80 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
|
||||||
extern crate mime;
|
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
extern crate hex;
|
extern crate hex;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
extern crate time;
|
|
||||||
extern crate uuid;
|
|
||||||
extern crate email as email_format;
|
|
||||||
extern crate bufstream;
|
extern crate bufstream;
|
||||||
extern crate openssl;
|
extern crate openssl;
|
||||||
|
|
||||||
pub mod transport;
|
pub mod smtp;
|
||||||
pub mod email;
|
pub mod sendmail;
|
||||||
|
pub mod stub;
|
||||||
|
pub mod file;
|
||||||
|
|
||||||
|
/// Email sendable by an SMTP client
|
||||||
|
pub trait SendableEmail {
|
||||||
|
/// To
|
||||||
|
fn to(&self) -> Vec<String>;
|
||||||
|
/// From
|
||||||
|
fn from(&self) -> String;
|
||||||
|
/// Message ID, used for logging
|
||||||
|
fn message_id(&self) -> String;
|
||||||
|
/// Message content
|
||||||
|
fn message(self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transport method for emails
|
||||||
|
pub trait EmailTransport<U> {
|
||||||
|
/// Sends the email
|
||||||
|
fn send<T: SendableEmail>(&mut self, email: T) -> U;
|
||||||
|
/// Close the transport explicitly
|
||||||
|
fn close(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Minimal email structure
|
||||||
|
#[derive(Debug,Clone)]
|
||||||
|
pub struct SimpleSendableEmail {
|
||||||
|
/// To
|
||||||
|
to: Vec<String>,
|
||||||
|
/// From
|
||||||
|
from: String,
|
||||||
|
/// Message ID
|
||||||
|
message_id: String,
|
||||||
|
/// Message content
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleSendableEmail {
|
||||||
|
/// Returns a new email
|
||||||
|
pub fn new(from_address: &str,
|
||||||
|
to_addresses: Vec<&str>,
|
||||||
|
message_id: &str,
|
||||||
|
message: &str)
|
||||||
|
-> SimpleSendableEmail {
|
||||||
|
SimpleSendableEmail {
|
||||||
|
from: from_address.to_string(),
|
||||||
|
to: to_addresses.iter().map(|s| s.to_string()).collect(),
|
||||||
|
message_id: message_id.to_string(),
|
||||||
|
message: message.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SendableEmail for SimpleSendableEmail {
|
||||||
|
fn to(&self) -> Vec<String> {
|
||||||
|
self.to.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from(&self) -> String {
|
||||||
|
self.from.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message_id(&self) -> String {
|
||||||
|
self.message_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message(self) -> String {
|
||||||
|
self.message
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
//! This transport uilizes the sendmail executable for each email.
|
//! This transport uilizes the sendmail executable for each email.
|
||||||
|
|
||||||
use email::SendableEmail;
|
|
||||||
|
use EmailTransport;
|
||||||
|
use SendableEmail;
|
||||||
|
use sendmail::error::SendmailResult;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
use transport::EmailTransport;
|
|
||||||
use transport::sendmail::error::SendmailResult;
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
/// Sends an email using the `sendmail` command
|
/// Sends an email using the `sendmail` command
|
||||||
@@ -31,10 +31,7 @@ impl EmailTransport<SendmailResult> for SendmailTransport {
|
|||||||
fn send<T: SendableEmail>(&mut self, email: T) -> SendmailResult {
|
fn send<T: SendableEmail>(&mut self, email: T) -> SendmailResult {
|
||||||
// Spawn the sendmail command
|
// Spawn the sendmail command
|
||||||
let mut process = try!(Command::new(&self.command)
|
let mut process = try!(Command::new(&self.command)
|
||||||
.args(&["-i",
|
.args(&["-i", "-f", &email.from(), &email.to().join(" ")])
|
||||||
"-f",
|
|
||||||
&email.envelope().from,
|
|
||||||
&email.envelope().to.join(" ")])
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn());
|
.spawn());
|
||||||
@@ -4,10 +4,10 @@ use crypto::hmac::Hmac;
|
|||||||
use crypto::mac::Mac;
|
use crypto::mac::Mac;
|
||||||
use crypto::md5::Md5;
|
use crypto::md5::Md5;
|
||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
|
use smtp::NUL;
|
||||||
|
use smtp::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use transport::smtp::NUL;
|
|
||||||
use transport::smtp::error::Error;
|
|
||||||
|
|
||||||
/// Represents authentication mechanisms
|
/// Represents authentication mechanisms
|
||||||
#[derive(PartialEq,Eq,Copy,Clone,Hash,Debug)]
|
#[derive(PartialEq,Eq,Copy,Clone,Hash,Debug)]
|
||||||
@@ -26,13 +26,11 @@ pub enum Mechanism {
|
|||||||
|
|
||||||
impl Display for Mechanism {
|
impl Display for Mechanism {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f,
|
write!(f, "{}", match *self {
|
||||||
"{}",
|
Mechanism::Plain => "PLAIN",
|
||||||
match *self {
|
Mechanism::Login => "LOGIN",
|
||||||
Mechanism::Plain => "PLAIN",
|
Mechanism::CramMd5 => "CRAM-MD5",
|
||||||
Mechanism::Login => "LOGIN",
|
})
|
||||||
Mechanism::CramMd5 => "CRAM-MD5",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
//! SMTP client
|
//! SMTP client
|
||||||
|
|
||||||
use bufstream::BufStream;
|
|
||||||
use openssl::ssl::SslContext;
|
|
||||||
|
|
||||||
use base64;
|
use base64;
|
||||||
|
use bufstream::BufStream;
|
||||||
|
use openssl::ssl::SslContext;
|
||||||
|
use smtp::{CRLF, MESSAGE_ENDING};
|
||||||
|
use smtp::authentication::Mechanism;
|
||||||
|
use smtp::client::net::{Connector, NetworkStream, Timeout};
|
||||||
|
use smtp::error::{Error, SmtpResult};
|
||||||
|
use smtp::response::ResponseParser;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{BufRead, Read, Write};
|
use std::io::{BufRead, Read, Write};
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use transport::smtp::{CRLF, MESSAGE_ENDING};
|
|
||||||
use transport::smtp::authentication::Mechanism;
|
|
||||||
use transport::smtp::client::net::{Connector, NetworkStream, Timeout};
|
|
||||||
use transport::smtp::error::{Error, SmtpResult};
|
|
||||||
use transport::smtp::response::ResponseParser;
|
|
||||||
|
|
||||||
pub mod net;
|
pub mod net;
|
||||||
|
|
||||||
@@ -203,8 +203,12 @@ impl<S: Connector + Timeout + Write + Read + Debug> Client<S> {
|
|||||||
|
|
||||||
if mechanism.supports_initial_response() {
|
if mechanism.supports_initial_response() {
|
||||||
self.command(&format!("AUTH {} {}",
|
self.command(&format!("AUTH {} {}",
|
||||||
mechanism,
|
mechanism,
|
||||||
base64::encode_config(try!(mechanism.response(username, password, None)).as_bytes(), base64::STANDARD)))
|
base64::encode_config(try!(mechanism.response(username,
|
||||||
|
password,
|
||||||
|
None))
|
||||||
|
.as_bytes(),
|
||||||
|
base64::STANDARD)))
|
||||||
} else {
|
} else {
|
||||||
let encoded_challenge = match try!(self.command(&format!("AUTH {}", mechanism)))
|
let encoded_challenge = match try!(self.command(&format!("AUTH {}", mechanism)))
|
||||||
.first_word() {
|
.first_word() {
|
||||||
@@ -232,7 +236,8 @@ impl<S: Connector + Timeout + Write + Read + Debug> Client<S> {
|
|||||||
let response = try!(self.command(&base64::encode_config(&try!(mechanism.response(username,
|
let response = try!(self.command(&base64::encode_config(&try!(mechanism.response(username,
|
||||||
password,
|
password,
|
||||||
Some(&decoded_challenge)))
|
Some(&decoded_challenge)))
|
||||||
.as_bytes(), base64::STANDARD)));
|
.as_bytes(),
|
||||||
|
base64::STANDARD)));
|
||||||
|
|
||||||
if !response.has_code(334) {
|
if !response.has_code(334) {
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
use self::Error::*;
|
use self::Error::*;
|
||||||
use base64::DecodeError;
|
use base64::DecodeError;
|
||||||
|
use smtp::response::{Response, Severity};
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
use transport::smtp::response::{Response, Severity};
|
|
||||||
|
|
||||||
/// An enum of all error kinds.
|
/// An enum of all error kinds.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
//! ESMTP features
|
//! ESMTP features
|
||||||
|
|
||||||
|
use smtp::authentication::Mechanism;
|
||||||
|
use smtp::error::Error;
|
||||||
|
use smtp::response::Response;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use transport::smtp::authentication::Mechanism;
|
|
||||||
use transport::smtp::error::Error;
|
|
||||||
use transport::smtp::response::Response;
|
|
||||||
|
|
||||||
/// Supported ESMTP keywords
|
/// Supported ESMTP keywords
|
||||||
#[derive(PartialEq,Eq,Hash,Clone,Debug)]
|
#[derive(PartialEq,Eq,Hash,Clone,Debug)]
|
||||||
@@ -53,13 +53,10 @@ pub struct ServerInfo {
|
|||||||
|
|
||||||
impl Display for ServerInfo {
|
impl Display for ServerInfo {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f,
|
write!(f, "{} with {}", self.name, match self.features.is_empty() {
|
||||||
"{} with {}",
|
true => "no supported features".to_string(),
|
||||||
self.name,
|
false => format!("{:?}", self.features),
|
||||||
match self.features.is_empty() {
|
})
|
||||||
true => "no supported features".to_string(),
|
|
||||||
false => format!("{:?}", self.features),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,9 +122,9 @@ impl ServerInfo {
|
|||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::{Extension, ServerInfo};
|
use super::{Extension, ServerInfo};
|
||||||
|
use smtp::authentication::Mechanism;
|
||||||
|
use smtp::response::{Category, Code, Response, Severity};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use transport::smtp::authentication::Mechanism;
|
|
||||||
use transport::smtp::response::{Category, Code, Response, Severity};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extension_fmt() {
|
fn test_extension_fmt() {
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
//! This transport sends emails using the SMTP protocol
|
//! This transport sends emails using the SMTP protocol
|
||||||
|
|
||||||
use email::SendableEmail;
|
use EmailTransport;
|
||||||
|
use SendableEmail;
|
||||||
use openssl::ssl::{SslContext, SslMethod};
|
use openssl::ssl::{SslContext, SslMethod};
|
||||||
|
use smtp::authentication::Mechanism;
|
||||||
|
use smtp::client::Client;
|
||||||
|
use smtp::error::{Error, SmtpResult};
|
||||||
|
use smtp::extension::{Extension, ServerInfo};
|
||||||
use std::net::{SocketAddr, ToSocketAddrs};
|
use std::net::{SocketAddr, ToSocketAddrs};
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use transport::EmailTransport;
|
|
||||||
use transport::smtp::authentication::Mechanism;
|
|
||||||
use transport::smtp::client::Client;
|
|
||||||
use transport::smtp::error::{Error, SmtpResult};
|
|
||||||
use transport::smtp::extension::{Extension, ServerInfo};
|
|
||||||
|
|
||||||
pub mod extension;
|
pub mod extension;
|
||||||
pub mod authentication;
|
pub mod authentication;
|
||||||
@@ -318,7 +318,9 @@ impl EmailTransport<SmtpResult> for SmtpTransport {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.supports_feature(&Extension::StartTls)) {
|
.supports_feature(&Extension::StartTls)) {
|
||||||
(&SecurityLevel::AlwaysEncrypt, false) => return Err(From::from("Could not encrypt connection, aborting")),
|
(&SecurityLevel::AlwaysEncrypt, false) => {
|
||||||
|
return Err(From::from("Could not encrypt connection, aborting"))
|
||||||
|
}
|
||||||
(&SecurityLevel::Opportunistic, false) => (),
|
(&SecurityLevel::Opportunistic, false) => (),
|
||||||
(&SecurityLevel::NeverEncrypt, _) => (),
|
(&SecurityLevel::NeverEncrypt, _) => (),
|
||||||
(&SecurityLevel::EncryptedWrapper, _) => (),
|
(&SecurityLevel::EncryptedWrapper, _) => (),
|
||||||
@@ -387,13 +389,13 @@ impl EmailTransport<SmtpResult> for SmtpTransport {
|
|||||||
(false, _) => None,
|
(false, _) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
try_smtp!(self.client.mail(&email.envelope().from, mail_options), self);
|
try_smtp!(self.client.mail(&email.from(), mail_options), self);
|
||||||
|
|
||||||
// Log the mail command
|
// Log the mail command
|
||||||
info!("{}: from=<{}>", message_id, email.envelope().from);
|
info!("{}: from=<{}>", message_id, email.from());
|
||||||
|
|
||||||
// Recipient
|
// Recipient
|
||||||
for to_address in &email.envelope().to {
|
for to_address in &email.to() {
|
||||||
try_smtp!(self.client.rcpt(&to_address), self);
|
try_smtp!(self.client.rcpt(&to_address), self);
|
||||||
// Log the rcpt command
|
// Log the rcpt command
|
||||||
info!("{}: to=<{}>", message_id, to_address);
|
info!("{}: to=<{}>", message_id, to_address);
|
||||||
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
use self::Category::*;
|
use self::Category::*;
|
||||||
use self::Severity::*;
|
use self::Severity::*;
|
||||||
|
use smtp::error::{Error, SmtpResult};
|
||||||
use std::fmt::{Display, Formatter, Result};
|
use std::fmt::{Display, Formatter, Result};
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use transport::smtp::error::{Error, SmtpResult};
|
|
||||||
|
|
||||||
/// First digit indicates severity
|
/// First digit indicates severity
|
||||||
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
|
#[derive(PartialEq,Eq,Copy,Clone,Debug)]
|
||||||
@@ -36,14 +36,12 @@ impl FromStr for Severity {
|
|||||||
|
|
||||||
impl Display for Severity {
|
impl Display for Severity {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
write!(f,
|
write!(f, "{}", match *self {
|
||||||
"{}",
|
PositiveCompletion => 2,
|
||||||
match *self {
|
PositiveIntermediate => 3,
|
||||||
PositiveCompletion => 2,
|
TransientNegativeCompletion => 4,
|
||||||
PositiveIntermediate => 3,
|
PermanentNegativeCompletion => 5,
|
||||||
TransientNegativeCompletion => 4,
|
})
|
||||||
PermanentNegativeCompletion => 5,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,16 +79,14 @@ impl FromStr for Category {
|
|||||||
|
|
||||||
impl Display for Category {
|
impl Display for Category {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
write!(f,
|
write!(f, "{}", match *self {
|
||||||
"{}",
|
Syntax => 0,
|
||||||
match *self {
|
Information => 1,
|
||||||
Syntax => 0,
|
Connections => 2,
|
||||||
Information => 1,
|
Unspecified3 => 3,
|
||||||
Connections => 2,
|
Unspecified4 => 4,
|
||||||
Unspecified3 => 3,
|
MailSystem => 5,
|
||||||
Unspecified4 => 4,
|
})
|
||||||
MailSystem => 5,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
//! This transport is a stub that only logs the message, and always returns
|
//! This transport is a stub that only logs the message, and always returns
|
||||||
//! success
|
//! success
|
||||||
|
|
||||||
use email::SendableEmail;
|
use EmailTransport;
|
||||||
use transport::EmailTransport;
|
use SendableEmail;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ impl EmailTransport<StubResult> for StubEmailTransport {
|
|||||||
|
|
||||||
info!("{}: from=<{}> to=<{:?}>",
|
info!("{}: from=<{}> to=<{:?}>",
|
||||||
email.message_id(),
|
email.message_id(),
|
||||||
email.envelope().from,
|
email.from(),
|
||||||
email.envelope().to);
|
email.to());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
extern crate lettre;
|
extern crate lettre;
|
||||||
|
|
||||||
use lettre::email::{EmailBuilder, SendableEmail};
|
use lettre::{EmailTransport, SendableEmail, SimpleSendableEmail};
|
||||||
use lettre::transport::EmailTransport;
|
|
||||||
|
|
||||||
use lettre::transport::file::FileEmailTransport;
|
use lettre::file::FileEmailTransport;
|
||||||
use std::env::temp_dir;
|
use std::env::temp_dir;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs::remove_file;
|
use std::fs::remove_file;
|
||||||
@@ -12,13 +11,10 @@ use std::io::Read;
|
|||||||
#[test]
|
#[test]
|
||||||
fn file_transport() {
|
fn file_transport() {
|
||||||
let mut sender = FileEmailTransport::new(temp_dir());
|
let mut sender = FileEmailTransport::new(temp_dir());
|
||||||
let email = EmailBuilder::new()
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
.to("root@localhost")
|
vec!["root@localhost"],
|
||||||
.from("user@localhost")
|
"file_id",
|
||||||
.body("Hello World!")
|
"Hello file");
|
||||||
.subject("Hello file")
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
let result = sender.send(email.clone());
|
let result = sender.send(email.clone());
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
17
lettre/tests/transport_sendmail.rs
Normal file
17
lettre/tests/transport_sendmail.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
extern crate lettre;
|
||||||
|
|
||||||
|
use lettre::{EmailTransport, SimpleSendableEmail};
|
||||||
|
use lettre::sendmail::SendmailTransport;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sendmail_transport_simple() {
|
||||||
|
let mut sender = SendmailTransport::new();
|
||||||
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
|
vec!["root@localhost"],
|
||||||
|
"sendmail_id",
|
||||||
|
"Hello sendmail");
|
||||||
|
|
||||||
|
let result = sender.send(email);
|
||||||
|
println!("{:?}", result);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
20
lettre/tests/transport_smtp.rs
Normal file
20
lettre/tests/transport_smtp.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
extern crate lettre;
|
||||||
|
|
||||||
|
use lettre::{EmailTransport, SimpleSendableEmail};
|
||||||
|
use lettre::smtp::SecurityLevel;
|
||||||
|
use lettre::smtp::SmtpTransportBuilder;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smtp_transport_simple() {
|
||||||
|
let mut sender = SmtpTransportBuilder::new("127.0.0.1:2525")
|
||||||
|
.unwrap()
|
||||||
|
.security_level(SecurityLevel::Opportunistic)
|
||||||
|
.build();
|
||||||
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
|
vec!["root@localhost"],
|
||||||
|
"smtp_id",
|
||||||
|
"Hello smtp");
|
||||||
|
|
||||||
|
let result = sender.send(email);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
16
lettre/tests/transport_stub.rs
Normal file
16
lettre/tests/transport_stub.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
extern crate lettre;
|
||||||
|
|
||||||
|
use lettre::{EmailTransport, SimpleSendableEmail};
|
||||||
|
use lettre::stub::StubEmailTransport;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stub_transport() {
|
||||||
|
let mut sender = StubEmailTransport;
|
||||||
|
let email = SimpleSendableEmail::new("user@localhost",
|
||||||
|
vec!["root@localhost"],
|
||||||
|
"stub_id",
|
||||||
|
"Hello stub");
|
||||||
|
|
||||||
|
let result = sender.send(email);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
39
lettre_email/CHANGELOG.md
Normal file
39
lettre_email/CHANGELOG.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
### v0.6.2 (2017-02-18)
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
* **all**
|
||||||
|
* Update uuid crate to 0.4
|
||||||
|
* Update env-logger crate to 0.4
|
||||||
|
* Update openssl crate to 0.9
|
||||||
|
|
||||||
|
### v0.6.1 (2016-10-19)
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
* **documentation**
|
||||||
|
* #91: Build seperate docs for each release
|
||||||
|
* #96: Add complete documentation information to README
|
||||||
|
|
||||||
|
#### Bugfixes
|
||||||
|
|
||||||
|
* **email**
|
||||||
|
* #85: Use address-list for "To", "From" etc.
|
||||||
|
|
||||||
|
* **tests**
|
||||||
|
* #93: Force building tests before coverage computing
|
||||||
|
|
||||||
|
### v0.6.0 (2016-05-05)
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
* **email**
|
||||||
|
* multipart support
|
||||||
|
* add non-consuming methods for Email builders
|
||||||
|
|
||||||
|
#### Beaking Change
|
||||||
|
|
||||||
|
* **email**
|
||||||
|
* `add_header` does not return the builder anymore,
|
||||||
|
for consistency with other methods. Use the `header`
|
||||||
|
method instead
|
||||||
22
lettre_email/Cargo.toml
Normal file
22
lettre_email/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
|
||||||
|
name = "lettre_email"
|
||||||
|
version = "0.7.0"
|
||||||
|
description = "Email builder"
|
||||||
|
readme = "README.md"
|
||||||
|
documentation = "https://docs.rs/lettre_email/"
|
||||||
|
repository = "https://github.com/lettre/lettre"
|
||||||
|
license = "MIT"
|
||||||
|
authors = ["Alexis Mousset <contact@amousset.me>"]
|
||||||
|
categories = ["email"]
|
||||||
|
keywords = ["email", "mailer"]
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
travis-ci = { repository = "lettre/lettre_email" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
email = "^0.0"
|
||||||
|
mime = "^0.2"
|
||||||
|
time = "^0.1"
|
||||||
|
uuid = { version = ">=0.4, <0.6", features = ["v4"] }
|
||||||
|
lettre = { path = "../lettre" }
|
||||||
1
lettre_email/LICENSE
Symbolic link
1
lettre_email/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../LICENSE
|
||||||
1
lettre_email/README.md
Symbolic link
1
lettre_email/README.md
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../README.md
|
||||||
31
lettre_email/examples/smtp.rs
Normal file
31
lettre_email/examples/smtp.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
extern crate lettre;
|
||||||
|
extern crate lettre_email;
|
||||||
|
|
||||||
|
use lettre_email::email::EmailBuilder;
|
||||||
|
use lettre::EmailTransport;
|
||||||
|
use lettre::smtp::SmtpTransportBuilder;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let email = EmailBuilder::new()
|
||||||
|
// Addresses can be specified by the tuple (email, alias)
|
||||||
|
.to(("user@example.org", "Firstname Lastname"))
|
||||||
|
// ... or by an address only
|
||||||
|
.from("user@example.com")
|
||||||
|
.subject("Hi, Hello world")
|
||||||
|
.text("Hello world.")
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Open a local connection on port 25
|
||||||
|
let mut mailer = SmtpTransportBuilder::localhost().unwrap().build();
|
||||||
|
// Send the email
|
||||||
|
let result = mailer.send(email);
|
||||||
|
|
||||||
|
if result.is_ok() {
|
||||||
|
println!("Email sent");
|
||||||
|
} else {
|
||||||
|
println!("Could not send email: {:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
1
lettre_email/rustfmt.toml
Symbolic link
1
lettre_email/rustfmt.toml
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../rustfmt.toml
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
//! Simple email representation
|
//! Simple email representation
|
||||||
|
|
||||||
pub mod error;
|
use error::Error;
|
||||||
|
|
||||||
use email::error::Error;
|
|
||||||
use email_format::{Address, Header, Mailbox, MimeMessage, MimeMultipartType};
|
use email_format::{Address, Header, Mailbox, MimeMessage, MimeMultipartType};
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use time::{Tm, now};
|
use time::{Tm, now};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use lettre::SendableEmail;
|
||||||
|
|
||||||
/// Converts an address or an address with an alias to a `Header`
|
/// Converts an address or an address with an alias to a `Header`
|
||||||
pub trait IntoHeader {
|
pub trait IntoHeader {
|
||||||
@@ -638,8 +637,7 @@ impl EmailBuilder {
|
|||||||
}
|
}
|
||||||
// Add the sender header, if any.
|
// Add the sender header, if any.
|
||||||
if let Some(ref v) = self.sender_header {
|
if let Some(ref v) = self.sender_header {
|
||||||
self.message
|
self.message.add_header(("Sender", v.to_string().as_ref()));
|
||||||
.add_header(("Sender", v.to_string().as_ref()));
|
|
||||||
}
|
}
|
||||||
// Calculate the envelope
|
// Calculate the envelope
|
||||||
let envelope = match self.envelope {
|
let envelope = match self.envelope {
|
||||||
@@ -732,58 +730,13 @@ impl EmailBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Email sendable by an SMTP client
|
|
||||||
pub trait SendableEmail {
|
|
||||||
/// Envelope
|
|
||||||
fn envelope(&self) -> &Envelope;
|
|
||||||
/// Message ID
|
|
||||||
fn message_id(&self) -> String;
|
|
||||||
/// Message content
|
|
||||||
fn message(self) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Minimal email structure
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SimpleSendableEmail {
|
|
||||||
/// Message envelope
|
|
||||||
envelope: Envelope,
|
|
||||||
/// Message content
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SimpleSendableEmail {
|
|
||||||
/// Returns a new email
|
|
||||||
pub fn new(from_address: String,
|
|
||||||
to_addresses: Vec<String>,
|
|
||||||
message: String)
|
|
||||||
-> SimpleSendableEmail {
|
|
||||||
SimpleSendableEmail {
|
|
||||||
envelope: Envelope {
|
|
||||||
from: from_address,
|
|
||||||
to: to_addresses,
|
|
||||||
},
|
|
||||||
message: message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendableEmail for SimpleSendableEmail {
|
|
||||||
fn envelope(&self) -> &Envelope {
|
|
||||||
&self.envelope
|
|
||||||
}
|
|
||||||
|
|
||||||
fn message_id(&self) -> String {
|
|
||||||
format!("{}", Uuid::new_v4())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn message(self) -> String {
|
|
||||||
self.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SendableEmail for Email {
|
impl SendableEmail for Email {
|
||||||
fn envelope(&self) -> &Envelope {
|
fn to(&self) -> Vec<String> {
|
||||||
&self.envelope
|
self.envelope.to.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from(&self) -> String {
|
||||||
|
self.envelope.from.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn message_id(&self) -> String {
|
fn message_id(&self) -> String {
|
||||||
@@ -823,7 +776,8 @@ pub trait ExtractableEmail {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::{Email, EmailBuilder, Envelope, IntoEmail, SendableEmail, SimpleEmail};
|
use lettre::SendableEmail;
|
||||||
|
use super::{Email, EmailBuilder, Envelope, IntoEmail, SimpleEmail};
|
||||||
use email_format::{Header, MimeMessage};
|
use email_format::{Header, MimeMessage};
|
||||||
use time::now;
|
use time::now;
|
||||||
|
|
||||||
@@ -959,8 +913,8 @@ mod test {
|
|||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(email.envelope().from, "sender@localhost".to_string());
|
assert_eq!(email.from(), "sender@localhost".to_string());
|
||||||
assert_eq!(email.envelope().to,
|
assert_eq!(email.to(),
|
||||||
vec!["user@localhost".to_string(),
|
vec!["user@localhost".to_string(),
|
||||||
"cc@localhost".to_string(),
|
"cc@localhost".to_string(),
|
||||||
"bcc@localhost".to_string()]);
|
"bcc@localhost".to_string()]);
|
||||||
65
lettre_email/src/lib.rs
Normal file
65
lettre_email/src/lib.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
//! Lettre is a mailer written in Rust. It provides a simple email builder and several transports.
|
||||||
|
//!
|
||||||
|
//! ## Overview
|
||||||
|
//!
|
||||||
|
//! The `email` part builds email messages. For now, it does not support attachments.
|
||||||
|
//! An email is built using an `EmailBuilder`. The simplest email could be:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use lettre_email::email::EmailBuilder;
|
||||||
|
//!
|
||||||
|
//! // Create an email
|
||||||
|
//! let email = EmailBuilder::new()
|
||||||
|
//! // Addresses can be specified by the tuple (email, alias)
|
||||||
|
//! .to(("user@example.org", "Firstname Lastname"))
|
||||||
|
//! // ... or by an address only
|
||||||
|
//! .from("user@example.com")
|
||||||
|
//! .subject("Hi, Hello world")
|
||||||
|
//! .text("Hello world.")
|
||||||
|
//! .build();
|
||||||
|
//!
|
||||||
|
//! assert!(email.is_ok());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! When the `build` method is called, the `EmailBuilder` will add the missing headers (like
|
||||||
|
//! `Message-ID` or `Date`) and check for missing necessary ones (like `From` or `To`). It will
|
||||||
|
//! then generate an `Email` that can be sent.
|
||||||
|
//!
|
||||||
|
//! The `text()` method will create a plain text email, while the `html()` method will create an
|
||||||
|
//! HTML email. You can use the `alternative()` method to provide both versions, using plain text
|
||||||
|
//! as fallback for the HTML version.
|
||||||
|
//!
|
||||||
|
//! Below is a more complete example, not using method chaining:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use lettre_email::email::EmailBuilder;
|
||||||
|
//!
|
||||||
|
//! let mut builder = EmailBuilder::new();
|
||||||
|
//! builder.add_to(("user@example.org", "Alias name"));
|
||||||
|
//! builder.add_cc(("user@example.net", "Alias name"));
|
||||||
|
//! builder.add_from("no-reply@example.com");
|
||||||
|
//! builder.add_from("no-reply@example.eu");
|
||||||
|
//! builder.set_sender("no-reply@example.com");
|
||||||
|
//! builder.set_subject("Hello world");
|
||||||
|
//! builder.set_alternative("<h2>Hi, Hello world.</h2>", "Hi, Hello world.");
|
||||||
|
//! builder.add_reply_to("contact@example.com");
|
||||||
|
//! builder.add_header(("X-Custom-Header", "my header"));
|
||||||
|
//!
|
||||||
|
//! let email = builder.build();
|
||||||
|
//! assert!(email.is_ok());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! See the `EmailBuilder` documentation for a complete list of methods.
|
||||||
|
//!
|
||||||
|
|
||||||
|
#![deny(missing_docs, unsafe_code, unstable_features, warnings, missing_debug_implementations)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate mime;
|
||||||
|
extern crate time;
|
||||||
|
extern crate uuid;
|
||||||
|
extern crate email as email_format;
|
||||||
|
extern crate lettre;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
pub mod email;
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
reorder_imports = true
|
|
||||||
reorder_imported_names = true
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//! Represents an Email transport
|
|
||||||
|
|
||||||
pub mod smtp;
|
|
||||||
pub mod sendmail;
|
|
||||||
pub mod stub;
|
|
||||||
pub mod file;
|
|
||||||
|
|
||||||
use email::SendableEmail;
|
|
||||||
|
|
||||||
/// Transport method for emails
|
|
||||||
pub trait EmailTransport<U> {
|
|
||||||
/// Sends the email
|
|
||||||
fn send<T: SendableEmail>(&mut self, email: T) -> U;
|
|
||||||
/// Close the transport explicitly
|
|
||||||
fn close(&mut self);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
extern crate lettre;
|
|
||||||
|
|
||||||
use lettre::email::EmailBuilder;
|
|
||||||
use lettre::transport::EmailTransport;
|
|
||||||
use lettre::transport::sendmail::SendmailTransport;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sendmail_transport_simple() {
|
|
||||||
let mut sender = SendmailTransport::new();
|
|
||||||
let email = EmailBuilder::new()
|
|
||||||
.to("root@localhost")
|
|
||||||
.from("user@localhost")
|
|
||||||
.body("Hello World!")
|
|
||||||
.subject("Hello sendmail")
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
let result = sender.send(email);
|
|
||||||
println!("{:?}", result);
|
|
||||||
assert!(result.is_ok());
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
extern crate lettre;
|
|
||||||
|
|
||||||
use lettre::email::EmailBuilder;
|
|
||||||
use lettre::transport::EmailTransport;
|
|
||||||
use lettre::transport::smtp::SecurityLevel;
|
|
||||||
use lettre::transport::smtp::SmtpTransportBuilder;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smtp_transport_simple() {
|
|
||||||
let mut sender = SmtpTransportBuilder::new("127.0.0.1:2525")
|
|
||||||
.unwrap()
|
|
||||||
.security_level(SecurityLevel::Opportunistic)
|
|
||||||
.build();
|
|
||||||
let email = EmailBuilder::new()
|
|
||||||
.to("root@localhost")
|
|
||||||
.from("user@localhost")
|
|
||||||
.body("Hello World!")
|
|
||||||
.subject("Hello smtp")
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
let result = sender.send(email);
|
|
||||||
assert!(result.is_ok());
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
extern crate lettre;
|
|
||||||
|
|
||||||
use lettre::email::EmailBuilder;
|
|
||||||
use lettre::transport::EmailTransport;
|
|
||||||
use lettre::transport::stub::StubEmailTransport;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn stub_transport() {
|
|
||||||
let mut sender = StubEmailTransport;
|
|
||||||
let email = EmailBuilder::new()
|
|
||||||
.to("root@localhost")
|
|
||||||
.from("user@localhost")
|
|
||||||
.body("Hello World!")
|
|
||||||
.subject("Hello stub")
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
let result = sender.send(email);
|
|
||||||
assert!(result.is_ok());
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user