Compare commits

...

83 Commits

Author SHA1 Message Date
Alexis Mousset
73d823c8ca Merge pull request #255 from amousset/prepare-0.8.1
Prepare 0.8.1
2018-04-11 23:36:46 +02:00
Alexis Mousset
d45ee40f4a fix(all): No cache on build folders 2018-04-11 23:28:03 +02:00
Alexis Mousset
e295c5db5e Prepare 0.8.1 release 2018-04-11 22:54:29 +02:00
Alexis Mousset
a3d6722e7e Merge pull request #253 from Eijebong/skeptic
tests: Replace skeptic by some custom logic code and rustdoc calls
2018-04-11 22:09:52 +02:00
Bastien Orivel
fd56ec8877 test(lettre_email): Replace skeptic by some custom rustdoc invocations 2018-04-11 22:00:52 +02:00
Bastien Orivel
81bad13175 test(lettre): Replace skeptic by some custom rustdoc invocations
Unfortunately skeptic pulls all its dependencies in projects using
lettre (see https://github.com/budziq/rust-skeptic/issues/60).
2018-04-11 22:00:20 +02:00
Alexis Mousset
27c8e206cf Merge pull request #252 from amousset/add-changelog-sections
docs(all): Add changelog sections for style and docs
2018-04-08 15:14:45 +02:00
Alexis Mousset
b4d03ead8c docs(all): Add changelog sections for style and docs 2018-04-08 14:56:19 +02:00
Alexis Mousset
d692a9488f Merge pull request #251 from amousset/avoid-empty-format-strings
style(transport-smtp): Avoid useless empty format strings
2018-04-08 14:46:47 +02:00
Alexis Mousset
f3271715ec style(transport-smtp): Avoid useless empty format strings 2018-04-08 14:31:50 +02:00
Alexis Mousset
ee51cf7454 Merge pull request #250 from amousset/formal-changelog
Use clog to generate changelogs
2018-04-08 14:23:23 +02:00
Alexis Mousset
8981a7758c docs(all): Use clog to generate changelogs
Changelog will be unique, and generated from commit
messages using clog-cli.
Commit message should follow guidelines in CONTRIBUTING.md,
and GitCop has been (re)enabled.

Fixes #233.
2018-04-08 13:58:09 +02:00
Alexis Mousset
b91cb0770d Update contact email 2018-04-01 19:41:51 +02:00
Alexis Mousset
0cff889ace Merge pull request #247 from amousset/improve-readme
Add lettre.at link to README
2018-04-01 19:37:23 +02:00
Alexis Mousset
d00568cbd6 Add lettre.at link to README 2018-04-01 19:36:55 +02:00
Alexis Mousset
32cace1252 Merge pull request #246 from amousset/fix-base-url
Fix site base url
2018-04-01 19:29:32 +02:00
Alexis Mousset
a86cc3328e Fix site base url 2018-04-01 19:28:54 +02:00
Alexis Mousset
b51b2843f4 Create CNAME 2018-04-01 17:58:49 +02:00
Alexis Mousset
91a17ae281 Merge pull request #243 from amousset/prepare-0-8
Prepare 0.8 release
2018-03-31 21:11:13 +02:00
Alexis Mousset
bd752daf85 Prepare 0.8 release 2018-03-31 20:38:40 +02:00
Alexis Mousset
ed01efd890 Merge pull request #242 from amousset/more-lints
feat(all): Add more compiler lints
2018-03-31 20:00:12 +02:00
Alexis Mousset
088db45e41 feat(all): Add more compiler lints 2018-03-31 19:36:51 +02:00
Alexis Mousset
955a453df9 Merge pull request #241 from amousset/add-serde-impls
feat(transport): Add serde derive when possible
2018-03-31 17:49:14 +02:00
Alexis Mousset
71eda4b174 feat(transport): Add serde derive when possible 2018-03-31 17:30:36 +02:00
Alexis Mousset
d283254b1a Merge pull request #239 from amousset/move-envelope-lettre
feat(all): Move Envelope from lettre_email to lettre
2018-03-31 16:38:40 +02:00
Alexis Mousset
f3f963c6a5 feat(all): Move Envelope from lettre_email to lettre 2018-03-31 16:25:33 +02:00
Alexis Mousset
bef45c48f7 Merge pull request #237 from amousset/fix-style
style(all): rustfmt and clippy
2018-03-20 11:03:40 +01:00
Alexis Mousset
e024806402 style(all): rustfmt and clippy 2018-03-20 10:44:41 +01:00
Alexis Mousset
d7a8574464 Merge pull request #236 from amousset/prepare-0-8
Prepare changelog for 0.8
2018-03-11 15:39:54 +01:00
Alexis Mousset
9b22f5867e Prepare changelog for 0.8 2018-03-11 15:25:26 +01:00
Alexis Mousset
17abeb3957 Merge pull request #235 from amousset/html-utf8
fix(builder): Specify utf-8 charset for html
2018-03-11 10:49:50 +01:00
Alexis Mousset
e6a5c158da fix(builder): Specify utf-8 charset for html 2018-03-11 10:36:58 +01:00
Alexis Mousset
f4fc427a03 Merge pull request #234 from amousset/fix-attachment-multipart
fix(builder): Use parts for text and html methods to fix attachment i…
2018-03-11 01:19:24 +01:00
Alexis Mousset
662072e692 fix(builder): Use parts for text and html methods to fix attachment inclusion 2018-03-10 21:16:01 +01:00
Alexis Mousset
4f16d9ee69 Merge pull request #231 from amousset/clippy-redundant-field-name
style(all): Run stable rustfmt and remove redundant field names in st…
2018-03-03 07:52:27 +01:00
Alexis Mousset
9d68629bb6 style(all): Run stable rustfmt and remove redundant field names in structs 2018-03-03 00:28:45 +01:00
Alexis Mousset
96e4f845ec Merge pull request #230 from amousset/missing-bcc
fix(builder): Add bcc headers in builder
2018-03-01 07:38:12 +01:00
Alexis Mousset
4dc95281ad fix(builder): Add bcc headers in builder 2018-03-01 00:33:17 +01:00
Alexis Mousset
f3311456ad Merge pull request #228 from SpiderPigSpy/master
feat(email): Support binary file as attachment
2018-02-25 21:52:59 +01:00
Alex
98a250f015 feat(email): Support binary file as attachment
A pretty easy fix by using base64 encoding
worked pretty well in my project
934fb660b7/src/bot/email.rs

Closes issue
https://github.com/lettre/lettre/issues/224
2018-02-25 21:59:54 +03:00
Alexis Mousset
f2f2f98905 Merge pull request #227 from amousset/clippt-fix
feat(all): Apply clippy advice
2018-02-21 00:01:19 +01:00
Alexis Mousset
53e79d9620 feat(all): Apply clippy advice 2018-02-20 23:47:53 +01:00
Alexis Mousset
4f11ae61ef Merge pull request #225 from amousset/update-depends
feat(all): Update uuid to 0.6
2018-02-17 10:19:45 +01:00
Alexis Mousset
9344ff7e5c feat(all): Update uuid to 0.6 2018-02-17 09:53:58 +01:00
Alexis Mousset
36d20bc7b6 Merge pull request #223 from amousset/update-ci-conf
feat(all): Do not install OpenSSL for Windows tests
2018-01-27 16:20:20 +01:00
Alexis Mousset
620c3e96dc feat(all): Do not install OpenSSL for Windows tests 2018-01-27 16:08:05 +01:00
Alexis Mousset
7cab860cde Merge pull request #222 from amousset/prepare-doc-0-8
feat(all): Move doc to website and test it
2018-01-27 15:55:53 +01:00
Alexis Mousset
f10e4e81d0 feat(all): Move doc to website and test it 2018-01-27 15:44:18 +01:00
Alexis Mousset
5face8614b Merge pull request #220 from amousset/update-env-logger-0-5
feat(all): Update env_logger to 0.5
2018-01-18 09:02:20 +01:00
Alexis Mousset
480ed11785 feat(all): Update env_logger to 0.5 2018-01-18 00:14:14 +01:00
Alexis Mousset
a082da6ea4 Merge pull request #219 from amousset/fix-doc
fix(all): Fix documentation issues
2018-01-15 19:59:25 +01:00
Alexis Mousset
2a847c1b3b fix(all): Fix documentation issues 2018-01-15 19:50:47 +01:00
Alexis Mousset
f6c07f0720 Merge pull request #216 from amousset/update-log-04
feat(transport): Update log to 0.4
2017-12-28 21:01:51 +01:00
Alexis Mousset
bff687f55c feat(transport): Update log to 0.4 2017-12-28 20:17:22 +01:00
Alexis Mousset
66cd6fe3ac Merge pull request #215 from amousset/update-base64
feat(transport): Update base64 to 0.9
2017-12-23 08:24:59 +01:00
Alexis Mousset
bc4714a2c8 feat(transport): Update base64 to 0.9 2017-12-23 08:12:35 +01:00
Alexis Mousset
547be305c5 Merge pull request #214 from amousset/detail-type-enum
feat(transport-smtp): Make detail in response an enum
2017-12-10 19:12:07 +01:00
Alexis Mousset
ba719f7255 feat(transport-smtp): Make detail in response an enum 2017-12-10 18:56:35 +01:00
Alexis Mousset
4005fc88bc Merge pull request #212 from amousset/update-readme
feat(All): Update README and add CoC
2017-12-06 01:26:02 +01:00
Alexis Mousset
173f8aa2dd Merge branch 'master' into update-readme 2017-12-06 01:09:40 +01:00
Alexis Mousset
aa9e9dd96e feat(All): Update README and add CoC 2017-12-06 01:08:33 +01:00
Alexis Mousset
dd6601b9e5 Merge pull request #211 from lettre/add-code-of-conduct-1
Add a code of conduct
2017-12-06 01:03:51 +01:00
Alexis Mousset
78d8f9afb7 Add a code of conduct 2017-12-06 00:52:34 +01:00
Alexis Mousset
487bee0769 Merge pull request #210 from amousset/transport-public-methods
feat(transport-smtp): get_ehlo and reset in SmtpTransport should not …
2017-12-05 23:56:01 +01:00
Alexis Mousset
ab35bac204 feat(transport-smtp): get_ehlo and reset in SmtpTransport should not be public 2017-12-05 23:41:57 +01:00
Alexis Mousset
30ea70edab Merge pull request #209 from amousset/cleanup
Change rustfmt style
2017-11-25 12:02:09 +01:00
Alexis Mousset
eb4e7f9829 Change rustfmt style 2017-11-25 11:55:05 +01:00
Alexis Mousset
104935b443 Merge pull request #208 from amousset/use-hostname-clientid
feat(transport-smtp): Use hostname as clientid when available
2017-11-19 22:33:17 +01:00
Alexis Mousset
1936211f8e feat(transport-smtp): Use hostname as clientid when available 2017-11-19 22:21:13 +01:00
Alexis Mousset
87d0dbdf70 Merge pull request #207 from amousset/code-cleanup
feat(all): Add html_root_url
2017-11-19 14:59:38 +01:00
Alexis Mousset
7bc28caf27 feat(all): Add html_root_url 2017-11-19 14:54:04 +01:00
Alexis Mousset
7498bed378 Merge pull request #205 from amousset/update-openssl-windows-tests
fix(all): Update openssl for windows tests
2017-11-19 11:08:39 +01:00
Alexis Mousset
d2475ae1aa fix(all): Update openssl for windows tests 2017-11-19 11:00:25 +01:00
Alexis Mousset
12174676d3 Merge pull request #204 from amousset/improve-response-parsing
feat(transport-smtp): Add tests for response parsing and clean from_str
2017-11-19 01:44:26 +01:00
Alexis Mousset
1850d56ec1 feat(transport-smtp): Add tests for response parsing and clean from_str 2017-11-19 01:36:34 +01:00
Alexis Mousset
92134e22a4 Merge pull request #203 from amousset/response-parsing-with-nom
feat(transport): Use nom for parsing smtp responses
2017-11-19 01:11:12 +01:00
Alexis Mousset
01fde07a48 feat(transport): Use nom for parsing smtp responses 2017-11-19 00:42:07 +01:00
Alexis Mousset
16223ee9c3 Merge pull request #202 from amousset/update-dependencies
Update dependencies and improve style
2017-11-18 19:45:30 +01:00
Alexis Mousset
b010126c19 Update dependencies and improve style 2017-11-18 19:39:57 +01:00
Alexis Mousset
166178b011 Merge pull request #197 from jacobbudin/website-hugo-theme
fix(doc): Update Hugo theme
2017-10-16 23:02:35 +02:00
Jacob Budin
aecbce50e3 fix(doc): Update Hugo theme
Updated Hugo Learn Theme and regenerated web docs.
2017-10-15 18:17:26 -04:00
Alexis Mousset
cc324b4705 Merge pull request #196 from amousset/master
Add a version to lettre dependency in lettre_email
2017-10-08 17:59:02 +02:00
Alexis Mousset
2785f14f31 Add a version to lettre dependency in lettre_email 2017-10-08 17:41:01 +02:00
249 changed files with 22605 additions and 7370 deletions

View File

@@ -1,12 +1,7 @@
environment:
matrix:
- TARGET: x86_64-pc-windows-msvc
BITS: 64
OPENSSL_VERSION: 1_1_0f
OPENSSL_DIR: C:\OpenSSL
install:
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe"
- Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y --default-host %TARGET%
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin

7
.clog.toml Normal file
View File

@@ -0,0 +1,7 @@
[clog]
repository = "https://github.com/lettre/lettre"
changelog = "CHANGELOG.md"
[sections]
Style = ["style"]
Documentation = ["docs"]

4
.gitignore vendored
View File

@@ -1,4 +1,6 @@
.vscode/
.project
.project/
.idea/
lettre.iml
target/
/Cargo.lock

View File

@@ -12,13 +12,6 @@ matrix:
sudo: required
cache:
directories:
- target/debug/deps
- target/debug/build
- target/release/deps
- target/release/build
addons:
apt:
packages:
@@ -29,10 +22,5 @@ before_script:
- sudo chgrp -R postdrop /var/spool/postfix/maildrop
script:
- cargo test --verbose --manifest-path lettre/Cargo.toml --no-default-features
- cargo test --verbose --manifest-path lettre/Cargo.toml
- cargo test --verbose --manifest-path lettre_email/Cargo.toml
- cargo test --verbose --all
env:
global:
secure: "MaZ3TzuaAHuxmxQkfJdqRfkh7/ieScJRk0T/2yjysZhDMTYyRmp5wh/zkfW1ADuG0uc4Pqsxrsh1J9SVO7O0U5NJA8NKZi/pgiL+FHh0g4YtlHxy2xmFNB5am3Kyc+E7B4XylwTbA9S8ublVM0nvX7yX/a5fbwEUInVk2bA8fpc="

97
CHANGELOG.md Normal file
View File

@@ -0,0 +1,97 @@
<a name="v0.8.1"></a>
### v0.8.1 (2018-04-11)
#### Fix
* **all:**
* Replace skeptic by some custom rustdoc invocations ([81bad131](https://github.com/lettre/lettre/commit/81bad1317519d330c46ea02f2b7a266b97cc00dd))
#### Documentation
* **all:**
* Add changelog sections for style and docs ([b4d03ead](https://github.com/lettre/lettre/commit/b4d03ead8cce04e0c3d65a30e7a07acca9530f30))
* Use clog to generate changelogs ([8981a775](https://github.com/lettre/lettre/commit/8981a7758c89be69974ef204c4390744aea94e4f), closes [#233](https://github.com/lettre/lettre/issues/233))
#### Style
* **transport-smtp:** Avoid useless empty format strings ([f3271715](https://github.com/lettre/lettre/commit/f3271715ecaf2793c9064462184867e4f22b0ead))
<a name="v0.8.0"></a>
### v0.8.0 (2018-03-31)
#### Added
* Support binary files as attachment
* Move doc to a dedicated website
* Add tests for the doc using skeptic
* Added a code of conduct
* Use hostname as `ClientId` when available
#### Changed
* Detail in SMTP Response is now an enum
* Use nom for parsing smtp responses
* `Envelope` was moved from `lettre_email` to `lettre`
* `EmailAddress::new()` now returns a `Result`
* `SendableEmail` replaces `from` and `to` by `envelope` that returns an `Envelope`
* `File` transport storage format has changed
#### Fixed
* Add missing "Bcc" headers when building the email
* Specify utf-8 charset for html
* Use parts for text and html methods to work with attachments
#### Removed
* `get_ehlo` and `reset` in SmtpTransport are now private
<a name="v0.7.0"></a>
### v0.7.0 (2017-10-08)
#### Added
* Allow validating server certificate
* Initial (incomplete) attachments support
#### Changed
* Split into the *lettre* and *lettre_email* crates
* A lot of small improvements
* Use *tls-native* instead of *openssl* in smtp transport
<a name="v0.6.2"></a>
### v0.6.2 (2017-02-18)
#### Changed
* Update env-logger crate to 0.4
* Update openssl crate to 0.9
* Update uuid crate to 0.4
<a name="v0.6.1"></a>
### v0.6.1 (2016-10-19)
#### Changes
* **documentation**
* #91: Build seperate docs for each release
* #96: Add complete documentation information to README
#### Fixed
* #85: Use address-list for "To", "From" etc.
* #93: Force building tests before coverage computing
<a name="v0.6.0"></a>
### v0.6.0 (2016-05-05)
#### Changes
* multipart support
* add non-consuming methods for Email builders
* `add_header` does not return the builder anymore,
for consistency with other methods. Use the `header`
method instead

46
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@lettre.at. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -22,10 +22,7 @@ Any line of the commit message cannot be longer 72 characters.
fix: A bug fix
docs: Documentation only changes
style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
refactor: A code change that neither fixes a bug or adds a feature
perf: A code change that improves performance
test: Adding missing tests
chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
**scope** is the lettre part that is being touched. Examples:

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 Alexis Mousset
Copyright (c) 2014-2018 Alexis Mousset
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@@ -1,4 +1,5 @@
# lettre
[![Build Status](https://travis-ci.org/lettre/lettre.svg?branch=master)](https://travis-ci.org/lettre/lettre)
[![Build status](https://ci.appveyor.com/api/projects/status/mpwglemugjtkps2d/branch/master?svg=true)](https://ci.appveyor.com/project/amousset/lettre/branch/master)
[![Crate](https://img.shields.io/crates/v/lettre.svg)](https://crates.io/crates/lettre)
@@ -6,7 +7,7 @@
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![Gitter](https://badges.gitter.im/lettre/lettre.svg)](https://gitter.im/lettre/lettre?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
This is an email library written in Rust.
An email library written in Rust.
## Features
@@ -17,16 +18,49 @@ Lettre provides the following features:
* Secure delivery with SMTP using encryption and authentication
* Easy email builders
## Example
```rust,no_run
extern crate lettre;
extern crate lettre_email;
extern crate mime;
use lettre::{EmailTransport, SmtpTransport};
use lettre_email::EmailBuilder;
use std::path::Path;
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.")
.attachment(Path::new("Cargo.toml"), None, &mime::TEXT_PLAIN).unwrap()
.build()
.unwrap();
// Open a local connection on port 25
let mut mailer = SmtpTransport::builder_unencrypted_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());
}
```
## Documentation
Released versions:
* [latest](https://docs.rs/lettre/)
* [v0.7.0](https://docs.rs/lettre/0.7.0/lettre/)
* [v0.6.2](https://docs.rs/lettre/0.6.2/lettre/)
* [v0.6.1](https://docs.rs/lettre/0.6.1/lettre/)
* [v0.6.0](https://docs.rs/lettre/0.6.0/lettre/)
* [v0.5.1](https://docs.rs/lettre/0.5.1/lettre/)
* [User documentation](http://docs.lettre.at/)
* [API reference](https://docs.rs/lettre/)
## Install
@@ -35,12 +69,18 @@ To use this library, add the following to your `Cargo.toml`:
```toml
[dependencies]
lettre = "0.7"
lettre = "0.8"
lettre_email = "0.8"
```
## Testing
The tests require an open mail server listening locally on port 2525 and the `sendmail` command.
The `lettre` tests require an open mail server listening locally on port 2525 and the `sendmail` command.
## Code of conduct
Anyone who interacts with Lettre in any space, including but not limited to
this GitHub repository, must follow our [code of conduct](https://github.com/lettre/lettre/blob/master/CODE_OF_CONDUCT.md).
## License

View File

@@ -4,19 +4,21 @@
<head>
<meta charset="utf-8"> <meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>404 Page not found</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<style type="text/css">
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/horsey.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<style type="text/css">
:root #header + #content > #left > #rlblock_left {
display: none !important;
}
@@ -30,7 +32,8 @@
ul {
list-style-type: none;
}
</style>
</style>
</head>
<body>
@@ -41,13 +44,13 @@
<div id="overlay"></div>
<div id="chapter">
<div id="body-inner">
<h1>Error </h1>
<h1>Error</h1>
<p>
</p>
<p>Woops. Looks like this page doesn't exist.</p>
<p>Woops. Looks like this page doesn&#39;t exist ¯\_(ツ)_/¯.</p>
<p></p>
<p><a href="https://lettre.github.io/lettre/">Go to homepage</a></p>
<p><img src="https://lettre.github.io/lettre//images/gopher-404.jpg" style="width:50%"></img></p>
<p><a href="http://docs.lettre.at/">Go to homepage</a></p>
<p><img src="http://docs.lettre.at//images/gopher-404.jpg" style="width:50%"></img></p>
</div>
</div>

1
docs/CNAME Normal file
View File

@@ -0,0 +1 @@
docs.lettre.at

593
docs/categories/index.html Normal file
View File

@@ -0,0 +1,593 @@
<!DOCTYPE html>
<html lang="en" class="js csstransforms3d">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Categories :: Lettre site</title>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/categories/">
<nav id="sidebar" class="">
<div id="header-wrapper">
<div id="header">
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
<div class="highlightable">
<ul class="topics">
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<ul>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
</a>
<ul>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
</section>
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="sticky-spacer">
<div id="top-bar">
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
Categories
</span>
</div>
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Categories</h1>
<footer class=" footline" >
</footer>
</div>
</div>
<div id="navigation">
<a class="nav nav-next" href="/getting-started/" title="Getting started" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -2,12 +2,12 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Categories on Lettre site</title>
<link>https://lettre.github.io/lettre/categories/</link>
<link>http://docs.lettre.at/categories/</link>
<description>Recent content in Categories on Lettre site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://lettre.github.io/lettre/categories/index.xml" rel="self" type="application/rss+xml" />
<atom:link href="http://docs.lettre.at/categories/index.xml" rel="self" type="application/rss+xml" />
</channel>

View File

@@ -0,0 +1,731 @@
<!DOCTYPE html>
<html lang="en" class="js csstransforms3d">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Email creation :: Lettre site</title>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/creating-messages/email/">
<nav id="sidebar" class="">
<div id="header-wrapper">
<div id="header">
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
<div class="highlightable">
<ul class="topics">
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<ul>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
parent
">
<a href="/creating-messages/">
Creating messages
</a>
<ul>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item active">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item active">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
</section>
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/creating-messages/email.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/creating-messages/'>Creating messages</a> > Email creation
</span>
</div>
<div class="progress">
<div class="wrapper">
<nav id="TableOfContents">
<ul>
<li>
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#simple-example">Simple example</a></li>
<li><a href="#complete-example">Complete example</a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</nav>
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Email creation</h1>
<h4 id="simple-example">Simple example</h4>
<p>The <code>email</code> part builds email messages. For now, it does not support attachments.
An email is built using an <code>EmailBuilder</code>. The simplest email could be:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">crate</span> lettre_email;
<span style="color:#66d9ef">use</span> lettre_email::EmailBuilder;
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
<span style="color:#75715e">// Create an email
</span><span style="color:#75715e"></span> <span style="color:#66d9ef">let</span> email <span style="color:#f92672">=</span> EmailBuilder::new()
<span style="color:#75715e">// Addresses can be specified by the tuple (email, alias)
</span><span style="color:#75715e"></span> .to((<span style="color:#e6db74">&#34;user@example.org&#34;</span>, <span style="color:#e6db74">&#34;Firstname Lastname&#34;</span>))
<span style="color:#75715e">// ... or by an address only
</span><span style="color:#75715e"></span> .from(<span style="color:#e6db74">&#34;user@example.com&#34;</span>)
.subject(<span style="color:#e6db74">&#34;Hi, Hello world&#34;</span>)
.text(<span style="color:#e6db74">&#34;Hello world.&#34;</span>)
.build();
assert<span style="color:#f92672">!</span>(email.is_ok());
}</code></pre></div>
<p>When the <code>build</code> method is called, the <code>EmailBuilder</code> will add the missing headers (like
<code>Message-ID</code> or <code>Date</code>) and check for missing necessary ones (like <code>From</code> or <code>To</code>). It will
then generate an <code>Email</code> that can be sent.</p>
<p>The <code>text()</code> method will create a plain text email, while the <code>html()</code> method will create an
HTML email. You can use the <code>alternative()</code> method to provide both versions, using plain text
as fallback for the HTML version.</p>
<h4 id="complete-example">Complete example</h4>
<p>Below is a more complete example, not using method chaining:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">crate</span> lettre_email;
<span style="color:#66d9ef">use</span> lettre_email::EmailBuilder;
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> builder <span style="color:#f92672">=</span> EmailBuilder::new();
builder.add_to((<span style="color:#e6db74">&#34;user@example.org&#34;</span>, <span style="color:#e6db74">&#34;Alias name&#34;</span>));
builder.add_cc((<span style="color:#e6db74">&#34;user@example.net&#34;</span>, <span style="color:#e6db74">&#34;Alias name&#34;</span>));
builder.add_from(<span style="color:#e6db74">&#34;no-reply@example.com&#34;</span>);
builder.add_from(<span style="color:#e6db74">&#34;no-reply@example.eu&#34;</span>);
builder.set_sender(<span style="color:#e6db74">&#34;no-reply@example.com&#34;</span>);
builder.set_subject(<span style="color:#e6db74">&#34;Hello world&#34;</span>);
builder.set_alternative(<span style="color:#e6db74">&#34;&lt;h2&gt;Hi, Hello world.&lt;/h2&gt;&#34;</span>, <span style="color:#e6db74">&#34;Hi, Hello world.&#34;</span>);
builder.add_reply_to(<span style="color:#e6db74">&#34;contact@example.com&#34;</span>);
builder.add_header((<span style="color:#e6db74">&#34;X-Custom-Header&#34;</span>, <span style="color:#e6db74">&#34;my header&#34;</span>));
<span style="color:#66d9ef">let</span> email <span style="color:#f92672">=</span> builder.build();
assert<span style="color:#f92672">!</span>(email.is_ok());
}</code></pre></div>
<p>See the <code>EmailBuilder</code> documentation for a complete list of methods.</p>
<footer class=" footline" >
</footer>
</div>
</div>
<div id="navigation">
<a class="nav nav-prev" href="/creating-messages/" title="Creating messages"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/" title="Sending messages" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -1,57 +1,67 @@
<!DOCTYPE html>
<html lang="en" class="js csstransforms3d">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Creating messages :: Lettre site</title>
<title>Creating messages</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/creating-messages/">
<body class="" data-url="/creating-messages/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -62,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -126,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
parent
active
">
<a href="/creating-messages/">
Creating messages
</a>
<li class="dd-item active parent" data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -214,93 +309,98 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/creating-messages/_index.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > Creating messages
<div class="padding highlightable">
<div id="top-bar">
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<div class="progress">
<div class="wrapper">
<nav id="TableOfContents">
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#creating-messages">Creating messages</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
</div>
</div>
<span itemprop="title"> Creating messages</span>
</div>
</div>
<div id="chapter">
<div id="body-inner">
<div id="body-inner">
<h1>Creating messages</h1>
<h3 id="creating-messages">Creating messages</h3>
<p>This section explains how to create emails.</p>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -313,12 +413,6 @@
<a class="nav nav-prev" href="/lettre/getting-started/intro/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/sending-messages/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -338,26 +432,200 @@
<a class="nav nav-prev" href="/getting-started/intro/" title="Introduction"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/creating-messages/email/" title="Email creation" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -2,14 +2,24 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Creating messages on Lettre site</title>
<link>https://lettre.github.io/lettre/creating-messages/</link>
<link>http://docs.lettre.at/creating-messages/</link>
<description>Recent content in Creating messages on Lettre site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sun, 21 May 2017 23:46:01 +0200</lastBuildDate>
<atom:link href="https://lettre.github.io/lettre/creating-messages/index.xml" rel="self" type="application/rss+xml" />
<atom:link href="http://docs.lettre.at/creating-messages/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Email creation</title>
<link>http://docs.lettre.at/creating-messages/email/</link>
<pubDate>Sun, 21 Jan 2018 23:46:17 +0200</pubDate>
<guid>http://docs.lettre.at/creating-messages/email/</guid>
<description>Simple example 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:
extern crate lettre_email; use lettre_email::EmailBuilder; fn main() { // Create an email let email = EmailBuilder::new() // Addresses can be specified by the tuple (email, alias) .to((&amp;#34;user@example.org&amp;#34;, &amp;#34;Firstname Lastname&amp;#34;)) // ... or by an address only .from(&amp;#34;user@example.com&amp;#34;) .subject(&amp;#34;Hi, Hello world&amp;#34;) .</description>
</item>
</channel>
</rss>

View File

@@ -0,0 +1,47 @@
.autocomplete-suggestions {
text-align: left;
cursor: default;
border: 1px solid #ccc;
border-top: 0;
background: #fff;
box-shadow: -1px 1px 3px rgba(0,0,0,.1);
/* core styles should not be changed */
position: absolute;
display: none;
z-index: 9999;
max-height: 254px;
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
}
.autocomplete-suggestion {
position: relative;
cursor: pointer;
padding: 7px;
line-height: 23px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #333;
}
.autocomplete-suggestion b {
font-weight: normal;
color: #1f8dd6;
}
.autocomplete-suggestion.selected {
background: #333;
color: #fff;
}
.autocomplete-suggestion:hover {
background: #444;
color: #fff;
}
.autocomplete-suggestion > .context {
font-size: 12px;
}

File diff suppressed because one or more lines are too long

View File

@@ -172,7 +172,6 @@ h2 {
font-size: 2.5rem;
line-height: 110% !important;
margin: 2.5rem 0 1.5rem 0;
text-transform: capitalize;
}
h3 {
@@ -210,3 +209,44 @@ figcaption h4 {
text-align: center;
margin-top: -1.5em;
}
.select-style {
border: 0;
width: 150px;
border-radius: 0px;
overflow: hidden;
display: inline-flex;
}
.select-style svg {
fill: #ccc;
width: 14px;
height: 14px;
pointer-events: none;
margin: auto;
}
.select-style svg:hover {
fill: #e6e6e6;
}
.select-style select {
padding: 0;
width: 130%;
border: none;
box-shadow: none;
background: transparent;
background-image: none;
-webkit-appearance: none;
margin: auto;
margin-left: 0px;
margin-right: -20px;
}
.select-style select:focus {
outline: none;
}
.select-style :hover {
cursor: pointer;
}

104
docs/css/theme-blue.css Normal file
View File

@@ -0,0 +1,104 @@
:root{
--MAIN-TEXT-color:#323232; /* Color of text by default */
--MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */
--MAIN-LINK-color:#1C90F3; /* Color of links */
--MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */
--MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */
--MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */
--MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */
--MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */
--MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */
--MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */
--MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */
--MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */
--MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */
--MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */
--MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */
--MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */
--MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */
--MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */
}
body {
color: var(--MAIN-TEXT-color) !important;
}
textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
border-color: none;
box-shadow: none;
}
h2, h3, h4, h5 {
color: var(--MAIN-TITLES-TEXT-color) !important;
}
a {
color: var(--MAIN-LINK-color);
}
.anchor {
color: var(--MAIN-ANCHOR-color);
}
a:hover {
color: var(--MAIN-LINK-HOVER-color);
}
#sidebar ul li.visited > a .read-icon {
color: var(--MENU-VISITED-color);
}
#body a.highlight:after {
display: block;
content: "";
height: 1px;
width: 0%;
-webkit-transition: width 0.5s ease;
-moz-transition: width 0.5s ease;
-ms-transition: width 0.5s ease;
transition: width 0.5s ease;
background-color: var(--MAIN-HOVER-color);
}
#sidebar {
background-color: var(--MENU-SECTIONS-BG-color);
}
#sidebar #header-wrapper {
background: var(--MENU-HEADER-BG-color);
color: var(--MENU-SEARCH-BOX-color);
border-color: var(--MENU-HEADER-BORDER-color);
}
#sidebar .searchbox {
border-color: var(--MENU-SEARCH-BOX-color);
background: var(--MENU-SEARCH-BG-color);
}
#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
background: var(--MENU-SECTIONS-ACTIVE-BG-color);
}
#sidebar .searchbox * {
color: var(--MENU-SEARCH-BOX-ICONS-color);
}
#sidebar a {
color: var(--MENU-SECTIONS-LINK-color);
}
#sidebar a:hover {
color: var(--MENU-SECTIONS-LINK-HOVER-color);
}
#sidebar ul li.active > a {
background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
}
#sidebar hr {
border-color: var(--MENU-SECTION-HR-color);
}

104
docs/css/theme-green.css Normal file
View File

@@ -0,0 +1,104 @@
:root{
--MAIN-TEXT-color:#323232; /* Color of text by default */
--MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */
--MAIN-LINK-color:#599a3e; /* Color of links */
--MAIN-LINK-HOVER-color:#3f6d2c; /* Color of hovered links */
--MAIN-ANCHOR-color: #599a3e; /* color of anchors on titles */
--MENU-HEADER-BG-color:#74b559; /* Background color of menu header */
--MENU-HEADER-BORDER-color:#9cd484; /*Color of menu header border */
--MENU-SEARCH-BG-color:#599a3e; /* Search field background color (by default borders + icons) */
--MENU-SEARCH-BOX-color: #84c767; /* Override search field border color */
--MENU-SEARCH-BOX-ICONS-color: #c7f7c4; /* Override search field icons color */
--MENU-SECTIONS-ACTIVE-BG-color:#1b211c; /* Background color of the active section and its childs */
--MENU-SECTIONS-BG-color:#222723; /* Background color of other sections */
--MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */
--MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */
--MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */
--MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */
--MENU-VISITED-color: #599a3e; /* Color of 'page visited' icons in menu */
--MENU-SECTION-HR-color: #18211c; /* Color of <hr> separator in menu */
}
body {
color: var(--MAIN-TEXT-color) !important;
}
textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
border-color: none;
box-shadow: none;
}
h2, h3, h4, h5 {
color: var(--MAIN-TITLES-TEXT-color) !important;
}
a {
color: var(--MAIN-LINK-color);
}
.anchor {
color: var(--MAIN-ANCHOR-color);
}
a:hover {
color: var(--MAIN-LINK-HOVER-color);
}
#sidebar ul li.visited > a .read-icon {
color: var(--MENU-VISITED-color);
}
#body a.highlight:after {
display: block;
content: "";
height: 1px;
width: 0%;
-webkit-transition: width 0.5s ease;
-moz-transition: width 0.5s ease;
-ms-transition: width 0.5s ease;
transition: width 0.5s ease;
background-color: var(--MAIN-HOVER-color);
}
#sidebar {
background-color: var(--MENU-SECTIONS-BG-color);
}
#sidebar #header-wrapper {
background: var(--MENU-HEADER-BG-color);
color: var(--MENU-SEARCH-BOX-color);
border-color: var(--MENU-HEADER-BORDER-color);
}
#sidebar .searchbox {
border-color: var(--MENU-SEARCH-BOX-color);
background: var(--MENU-SEARCH-BG-color);
}
#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
background: var(--MENU-SECTIONS-ACTIVE-BG-color);
}
#sidebar .searchbox * {
color: var(--MENU-SEARCH-BOX-ICONS-color);
}
#sidebar a {
color: var(--MENU-SECTIONS-LINK-color);
}
#sidebar a:hover {
color: var(--MENU-SECTIONS-LINK-HOVER-color);
}
#sidebar ul li.active > a {
background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
}
#sidebar hr {
border-color: var(--MENU-SECTION-HR-color);
}

104
docs/css/theme-red.css Normal file
View File

@@ -0,0 +1,104 @@
:root{
--MAIN-TEXT-color:#323232; /* Color of text by default */
--MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */
--MAIN-LINK-color:#f31c1c; /* Color of links */
--MAIN-LINK-HOVER-color:#d01616; /* Color of hovered links */
--MAIN-ANCHOR-color: #f31c1c; /* color of anchors on titles */
--MENU-HEADER-BG-color:#dc1010; /* Background color of menu header */
--MENU-HEADER-BORDER-color:#e23131; /*Color of menu header border */
--MENU-SEARCH-BG-color:#b90000; /* Search field background color (by default borders + icons) */
--MENU-SEARCH-BOX-color: #ef2020; /* Override search field border color */
--MENU-SEARCH-BOX-ICONS-color: #fda1a1; /* Override search field icons color */
--MENU-SECTIONS-ACTIVE-BG-color:#2b2020; /* Background color of the active section and its childs */
--MENU-SECTIONS-BG-color:#312525; /* Background color of other sections */
--MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */
--MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */
--MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */
--MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */
--MENU-VISITED-color: #ff3333; /* Color of 'page visited' icons in menu */
--MENU-SECTION-HR-color: #2b2020; /* Color of <hr> separator in menu */
}
body {
color: var(--MAIN-TEXT-color) !important;
}
textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
border-color: none;
box-shadow: none;
}
h2, h3, h4, h5 {
color: var(--MAIN-TITLES-TEXT-color) !important;
}
a {
color: var(--MAIN-LINK-color);
}
.anchor {
color: var(--MAIN-ANCHOR-color);
}
a:hover {
color: var(--MAIN-LINK-HOVER-color);
}
#sidebar ul li.visited > a .read-icon {
color: var(--MENU-VISITED-color);
}
#body a.highlight:after {
display: block;
content: "";
height: 1px;
width: 0%;
-webkit-transition: width 0.5s ease;
-moz-transition: width 0.5s ease;
-ms-transition: width 0.5s ease;
transition: width 0.5s ease;
background-color: var(--MAIN-HOVER-color);
}
#sidebar {
background-color: var(--MENU-SECTIONS-BG-color);
}
#sidebar #header-wrapper {
background: var(--MENU-HEADER-BG-color);
color: var(--MENU-SEARCH-BOX-color);
border-color: var(--MENU-HEADER-BORDER-color);
}
#sidebar .searchbox {
border-color: var(--MENU-SEARCH-BOX-color);
background: var(--MENU-SEARCH-BG-color);
}
#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
background: var(--MENU-SECTIONS-ACTIVE-BG-color);
}
#sidebar .searchbox * {
color: var(--MENU-SEARCH-BOX-ICONS-color);
}
#sidebar a {
color: var(--MENU-SECTIONS-LINK-color);
}
#sidebar a:hover {
color: var(--MENU-SECTIONS-LINK-HOVER-color);
}
#sidebar ul li.active > a {
background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
}
#sidebar hr {
border-color: var(--MENU-SECTION-HR-color);
}

View File

@@ -59,6 +59,7 @@ a:hover {
}
pre {
position: relative;
color: #ffffff;
}
.bg {
background: #fff;
@@ -529,6 +530,94 @@ div.notices.tip p {
div.notices.tip p:first-child:after {
content: 'Tip';
}
/* attachments shortcode */
section.attachments {
margin: 2rem 0;
position: relative;
}
section.attachments label {
font-weight: 400;
padding-left: 0.5em;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin: 0;
}
section.attachments .attachments-files {
padding: 15px;
display: block;
font-size: 1rem;
margin-top: 0rem;
margin-bottom: 0rem;
color: #666;
}
section.attachments.orange label {
color: #fff;
background: #F0B37E;
}
section.attachments.orange .attachments-files {
background: #FFF2DB;
}
section.attachments.green label {
color: #fff;
background: rgba(92, 184, 92, 0.8);
}
section.attachments.green .attachments-files {
background: #E6F9E6;
}
section.attachments.blue label {
color: #fff;
background: #6AB0DE;
}
section.attachments.blue .attachments-files {
background: #E7F2FA;
}
section.attachments.grey label {
color: #fff;
background: #505d65;
}
section.attachments.grey .attachments-files {
background: #f4f4f4;
}
/* Children shortcode */
/* Children shortcode */
.children p {
font-size: small;
margin-top: 0px;
padding-top: 0px;
margin-bottom: 0px;
padding-bottom: 0px;
}
.children-li p {
font-size: small;
font-style: italic;
}
.children-h2 p, .children-h3 p {
font-size: small;
margin-top: 0px;
padding-top: 0px;
margin-bottom: 0px;
padding-bottom: 0px;
}
.children h3,.children h2 {
margin-bottom: 0px;
margin-top: 5px;
}
code, kbd, pre, samp {
font-family: "Consolas", menlo, monospace;
font-size: 92%;
@@ -812,6 +901,9 @@ td {
overflow: auto;
position: relative;
}
.hljs::selection, .hljs span::selection {
background: #b7b7b7;
}
.lightbox-active #body {
overflow: visible;
}
@@ -999,6 +1091,18 @@ pre .copy-to-clipboard:hover {
#sidebar ul.topics > li > a .read-icon {
margin-top: 9px;
}
#sidebar ul {
list-style: none;
padding: 0;
margin: 0;
}
#sidebar #shortcuts li {
padding: 2px 0;
list-style: none;
}
#sidebar ul li .read-icon {
display: none;
float: right;
@@ -1012,6 +1116,13 @@ pre .copy-to-clipboard:hover {
display: inline;
}
#sidebar #shortcuts h3 {
font-family: "Novacento Sans Wide", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif;
color: white ;
margin-top:1rem;
padding-left: 1rem;
}
#searchResults {
text-align: left;
}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,57 +1,67 @@
<!DOCTYPE html>
<html lang="en" class="js csstransforms3d">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Getting started :: Lettre site</title>
<title>Getting started</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/getting-started/">
<body class="" data-url="/getting-started/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -62,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
parent
active
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item active parent" data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -126,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -214,37 +309,82 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/getting-started/_index.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > Getting started
<div class="padding highlightable">
<div id="top-bar">
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<div class="progress">
<div class="wrapper">
<nav id="TableOfContents">
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#getting-started">Getting started</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
</div>
</div>
<span itemprop="title"> Getting started</span>
</div>
</div>
<div id="chapter">
<div id="body-inner">
<div id="body-inner">
<h1>Getting started</h1>
@@ -254,55 +394,13 @@
<p>This section explains how to manipulate emails you have created.</p>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -314,7 +412,6 @@
<a class="nav nav-next" href="/lettre/getting-started/intro/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -338,26 +435,194 @@
<a class="nav nav-prev" href="/" title="Lettre site"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/getting-started/intro/" title="Introduction" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -2,22 +2,22 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Getting started on Lettre site</title>
<link>https://lettre.github.io/lettre/getting-started/</link>
<link>http://docs.lettre.at/getting-started/</link>
<description>Recent content in Getting started on Lettre site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sun, 21 May 2017 23:46:01 +0200</lastBuildDate>
<atom:link href="https://lettre.github.io/lettre/getting-started/index.xml" rel="self" type="application/rss+xml" />
<atom:link href="http://docs.lettre.at/getting-started/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Introduction</title>
<link>https://lettre.github.io/lettre/getting-started/intro/</link>
<link>http://docs.lettre.at/getting-started/intro/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/getting-started/intro/</guid>
<description>This documentation is written for lettre 0.7. Please use https://docs.rs/lettre/0.6.2/lettre/ for lettre 0.6.
<guid>http://docs.lettre.at/getting-started/intro/</guid>
<description>This documentation is written for lettre 0.8. Please use https://docs.rs/lettre/0.7.0/lettre/ for lettre 0.7.
Lettre is an email library that allows creating and sending messages. It provides:
An easy to use email builder Pluggable email transports Unicode support (for emails and transports, including for sender et recipient addresses when compatible) Secure defaults (emails are only sent encrypted by default) </description>
</item>

View File

@@ -3,54 +3,65 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Introduction :: Lettre site</title>
<title>Introduction</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/getting-started/intro/">
<body class="" data-url="/getting-started/intro/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -61,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
parent
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item parent" data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item active" data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item active">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -125,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -213,63 +309,82 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="padding highlightable">
<div id="top-bar">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/getting-started/intro.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/getting-started/'>Getting started</a> > Introduction
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/getting-started/intro.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<span id="toc-menu"><a href=""><i class="fa fa-list-alt"></i></a></span>
<a href="/lettre/getting-started/" itemprop="url"><span itemprop="title">Getting started</span></a> <i class="fa fa-angle-right"></i>
<span itemprop="title"> Introduction</span>
</div>
<div class="progress">
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Introduction</h1>
<div class="notices note" ><p>This documentation is written for lettre 0.7.
Please use <a href="https://docs.rs/lettre/0.6.2/lettre/">https://docs.rs/lettre/0.6.2/lettre/</a> for lettre 0.6.</p>
<div id="body-inner">
<h1>Introduction</h1>
<div class="notices note" ><p>This documentation is written for lettre 0.8.
Please use <a href="https://docs.rs/lettre/0.7.0/lettre/">https://docs.rs/lettre/0.7.0/lettre/</a> for lettre 0.7.</p>
</div>
@@ -283,53 +398,14 @@ Please use <a href="https://docs.rs/lettre/0.6.2/lettre/">https://docs.rs/lettre
</ul>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -340,12 +416,6 @@ Please use <a href="https://docs.rs/lettre/0.6.2/lettre/">https://docs.rs/lettre
<a class="nav nav-prev" href="/lettre/getting-started/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/creating-messages/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -367,23 +437,197 @@ Please use <a href="https://docs.rs/lettre/0.6.2/lettre/">https://docs.rs/lettre
<a class="nav nav-prev" href="/getting-started/" title="Getting started"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/creating-messages/" title="Creating messages" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>

View File

@@ -1 +1 @@
<meta http-equiv="refresh" content="0; url=https://lettre.github.io/lettre//getting-started/intro/"/>
<meta http-equiv="refresh" content="0; url=http://docs.lettre.at//getting-started/intro/"/>

62
docs/index.json Normal file
View File

@@ -0,0 +1,62 @@
[
{
"uri": "/content/creating-messages/_index",
"title": "Creating messages",
"content": "\nCreating messages\n\nThis section explains how to create emails.",
"tags": []
},
{
"uri": "/content/creating-messages/email",
"title": "Email creation",
"content": "\nSimple example\n\nThe email part builds email messages. For now, it does not support attachments.\nAn email is built using an EmailBuilder. The simplest email could be:\n\nextern crate lettre_email;\n\nuse lettre_email::EmailBuilder;\n\nfn main() {\n // Create an email\n let email = EmailBuilder::new()\n // Addresses can be specified by the tuple (email, alias)\n .to((\"user@example.org\", \"Firstname Lastname\"))\n // ... or by an address only\n .from(\"user@example.com\")\n .subject(\"Hi, Hello world\")\n .text(\"Hello world.\")\n .build();\n \n assert!(email.is_ok());\n}\n\nWhen the build method is called, the EmailBuilder will add the missing headers (like\nMessage-ID or Date) and check for missing necessary ones (like From or To). It will\nthen generate an Email that can be sent.\n\nThe text() method will create a plain text email, while the html() method will create an\nHTML email. You can use the alternative() method to provide both versions, using plain text\nas fallback for the HTML version.\n\n Complete example\n\nBelow is a more complete example, not using method chaining:\n\nextern crate lettre_email;\n\nuse lettre_email::EmailBuilder;\n\nfn main() {\n let mut builder = EmailBuilder::new();\n builder.add_to((\"user@example.org\", \"Alias name\"));\n builder.add_cc((\"user@example.net\", \"Alias name\"));\n builder.add_from(\"no-reply@example.com\");\n builder.add_from(\"no-reply@example.eu\");\n builder.set_sender(\"no-reply@example.com\");\n builder.set_subject(\"Hello world\");\n builder.set_alternative(\"h2Hi, Hello world./h2\", \"Hi, Hello world.\");\n builder.addreplyto(\"contact@example.com\");\n builder.add_header((\"X-Custom-Header\", \"my header\"));\n \n let email = builder.build();\n assert!(email.is_ok());\n}\n\nSee the EmailBuilder documentation for a complete list of methods.\n\n",
"tags": []
},
{
"uri": "/content/getting-started/_index",
"title": "Getting started",
"content": "\nGetting started\n\nThis section explains how to manipulate emails you have created.",
"tags": []
},
{
"uri": "/content/getting-started/intro",
"title": "Introduction",
"content": "\n{{% notice note %}}\nThis documentation is written for lettre 0.8.\nPlease use https://docs.rs/lettre/0.7.0/lettre/ for lettre 0.7.\n{{% /notice%}}\n\nLettre is an email library that allows creating and sending messages. It provides:\n\nAn easy to use email builder\nPluggable email transports\nUnicode support (for emails and transports, including for sender et recipient addresses when compatible)\nSecure defaults (emails are only sent encrypted by default)\n",
"tags": []
},
{
"uri": "/content/sending-messages/_index",
"title": "Sending messages",
"content": "\nSending Messages\n\nThis section explains how to manipulate emails you have created.",
"tags": []
},
{
"uri": "/content/sending-messages/file",
"title": "File transport",
"content": "\nThe file transport writes the emails to the given directory. The name of the file will be\nmessage_id.txt.\nIt can be useful for testing purposes, or if you want to keep track of sent messages.\n\nextern crate lettre;\n\nuse std::env::temp_dir;\n\nuse lettre::file::FileEmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\nfn main() {\n // Write to the local temp directory\n let mut sender = FileEmailTransport::new(temp_dir());\n let email = SimpleSendableEmail::new(\n \"user@localhost\".to_string(),\n &[\"root@localhost\".to_string()],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n ).unwrap();\n \n let result = sender.send(&email);\n assert!(result.is_ok());\n}\n\nExample result in /tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.txt:\n\nb7c211bc-9811-45ce-8cd9-68eab575d695: from=user@localhost to=root@localhost\nTo: root@localhost\nFrom: user@localhost\nSubject: Hello\nDate: Sat, 31 Oct 2015 13:42:19 +0100\nMessage-ID: b7c211bc-9811-45ce-8cd9-68eab575d695.lettre@localhost\n\nHello World!\n",
"tags": []
},
{
"uri": "/content/sending-messages/intro",
"title": "Introduction",
"content": "\nThis mailer contains several different transports for your emails. To be sendable, the\nemails have to implement SendableEmail, which is the case for emails created with lettre_email.\n\nThe following transports are available:\n\nThe SmtpTransport uses the SMTP protocol to send the message over the network. It is\n the preferred way of sending emails.\nThe SendmailTransport uses the sendmail command to send messages. It is an alternative to\n the SMTP transport.\nThe FileTransport creates a file containing the email content to be sent. It can be used\n for debugging or if you want to keep all sent emails.\nThe StubTransport is useful for debugging, and only prints the content of the email in the\n logs.\n",
"tags": []
},
{
"uri": "/content/sending-messages/sendmail",
"title": "Sendmail transport",
"content": "\nThe sendmail transport sends the email using the local sendmail command.\n\nextern crate lettre;\n\nuse lettre::sendmail::SendmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\nfn main() {\n let email = SimpleSendableEmail::new(\n \"user@localhost\".to_string(),\n &[\"root@localhost\".to_string()],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n ).unwrap();\n \n let mut sender = SendmailTransport::new();\n let result = sender.send(&email);\n assert!(result.is_ok());\n}\n",
"tags": []
},
{
"uri": "/content/sending-messages/smtp",
"title": "SMTP transport",
"content": "\nThis transport uses the SMTP protocol to send emails over the network (locally or remotely).\n\nIt is designed to be:\n\nSecured: email are encrypted by default\nModern: Unicode support for email content and sender/recipient addresses when compatible\nFast: supports tcp connection reuse\n\nThis client is designed to send emails to a relay server, and should not be used to send\nemails directly to the destination.\n\nThe relay server can be the local email server, a specific host or a third-party service.\n\nSimple example\n\nThis is the most basic example of usage:\n\nextern crate lettre;\n\nuse lettre::{SimpleSendableEmail, EmailTransport, SmtpTransport};\n\nfn main() {\n let email = SimpleSendableEmail::new(\n \"user@localhost\".to_string(),\n &[\"root@localhost\".to_string()],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n ).unwrap();\n \n // Open a local connection on port 25\n let mut mailer =\n SmtpTransport::builderunencryptedlocalhost().unwrap().build();\n // Send the email\n let result = mailer.send(&email);\n \n assert!(result.is_ok());\n}\n\n Complete example\n\nextern crate lettre;\n\nuse lettre::smtp::authentication::{Credentials, Mechanism};\nuse lettre::{SimpleSendableEmail, EmailTransport, SmtpTransport};\nuse lettre::smtp::extension::ClientId;\nuse lettre::smtp::ConnectionReuseParameters;\n\nfn main() {\n let email = SimpleSendableEmail::new(\n \"user@localhost\".to_string(),\n &[\"root@localhost\".to_string()],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n ).unwrap();\n \n // Connect to a remote server on a custom port\n let mut mailer = SmtpTransport::simple_builder(\"server.tld\").unwrap()\n // Set the name sent during EHLO/HELO, default is localhost\n .helloname(ClientId::Domain(\"my.hostname.tld\".tostring()))\n // Add credentials for authentication\n .credentials(Credentials::new(\"username\".tostring(), \"password\".tostring()))\n // Enable SMTPUTF8 if the server supports it\n .smtp_utf8(true)\n // Configure expected authentication mechanism\n .authentication_mechanism(Mechanism::Plain)\n // Enable connection reuse\n .connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();\n \n let result_1 = mailer.send(&email);\n assert!(result1.isok());\n \n // The second email will use the same connection\n let result_2 = mailer.send(&email);\n assert!(result2.isok());\n \n // Explicitly close the SMTP transaction as we enabled connection reuse\n mailer.close();\n}\n\nLower level\n\nYou can also send commands, here is a simple email transaction without\nerror handling:\n\nextern crate lettre;\n\nuse lettre::EmailAddress;\nuse lettre::smtp::SMTP_PORT;\nuse lettre::smtp::client::Client;\nuse lettre::smtp::client::net::NetworkStream;\nuse lettre::smtp::extension::ClientId;\nuse lettre::smtp::commands::*;\n\nfn main() {\n let mut email_client: ClientNetworkStream = Client::new();\n let _ = emailclient.connect(&(\"localhost\", SMTPPORT), None);\n let _ = emailclient.command(EhloCommand::new(ClientId::new(\"myhostname\".to_string())));\n let _ = email_client.command(\n MailCommand::new(Some(EmailAddress::new(\"user@example.com\".to_string()).unwrap()), vec![])\n );\n let _ = email_client.command(\n RcptCommand::new(EmailAddress::new(\"user@example.org\".to_string()).unwrap(), vec![])\n );\n let _ = email_client.command(DataCommand);\n let _ = emailclient.message(Box::new(\"Test email\".asbytes()));\n let _ = email_client.command(QuitCommand);\n}\n\n",
"tags": []
},
{
"uri": "/content/sending-messages/stub",
"title": "Stub transport",
"content": "\nThe stub transport only logs message envelope and drops the content. It can be useful for\ntesting purposes.\n\nextern crate lettre;\n\nuse lettre::stub::StubEmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\nfn main() {\n let email = SimpleSendableEmail::new(\n \"user@localhost\".to_string(),\n &[\"root@localhost\".to_string()],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n ).unwrap();\n \n let mut sender = StubEmailTransport::new_positive();\n let result = sender.send(&email);\n assert!(result.is_ok());\n}\n\nWill log (when using a logger like env_logger):\n\nb7c211bc-9811-45ce-8cd9-68eab575d695: from=user@localhost to=root@localhost\n",
"tags": []
}
]

View File

@@ -2,78 +2,88 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Lettre site</title>
<link>https://lettre.github.io/lettre/</link>
<link>http://docs.lettre.at/</link>
<description>Recent content on Lettre site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sun, 21 May 2017 23:46:17 +0200</lastBuildDate>
<atom:link href="https://lettre.github.io/lettre/index.xml" rel="self" type="application/rss+xml" />
<atom:link href="http://docs.lettre.at/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Introduction</title>
<link>https://lettre.github.io/lettre/getting-started/intro/</link>
<link>http://docs.lettre.at/getting-started/intro/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/getting-started/intro/</guid>
<description>This documentation is written for lettre 0.7. Please use https://docs.rs/lettre/0.6.2/lettre/ for lettre 0.6.
<guid>http://docs.lettre.at/getting-started/intro/</guid>
<description>This documentation is written for lettre 0.8. Please use https://docs.rs/lettre/0.7.0/lettre/ for lettre 0.7.
Lettre is an email library that allows creating and sending messages. It provides:
An easy to use email builder Pluggable email transports Unicode support (for emails and transports, including for sender et recipient addresses when compatible) Secure defaults (emails are only sent encrypted by default) </description>
</item>
<item>
<title>Introduction</title>
<link>https://lettre.github.io/lettre/sending-messages/intro/</link>
<link>http://docs.lettre.at/sending-messages/intro/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/intro/</guid>
<guid>http://docs.lettre.at/sending-messages/intro/</guid>
<description>This mailer contains several different transports for your emails. To be sendable, the emails have to implement SendableEmail, which is the case for emails created with lettre_email.
The following transports are available:
The SmtpTransport uses the SMTP protocol to send the message over the network. It is the prefered way of sending emails. The SendmailTransport uses the sendmail command to send messages. It is an alternative to the SMTP transport.</description>
The SmtpTransport uses the SMTP protocol to send the message over the network. It is the preferred way of sending emails. The SendmailTransport uses the sendmail command to send messages. It is an alternative to the SMTP transport.</description>
</item>
<item>
<title>SMTP transport</title>
<link>https://lettre.github.io/lettre/sending-messages/smtp/</link>
<link>http://docs.lettre.at/sending-messages/smtp/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/smtp/</guid>
<guid>http://docs.lettre.at/sending-messages/smtp/</guid>
<description>This transport uses the SMTP protocol to send emails over the network (locally or remotely).
It is desinged to be:
Secured: email are encrypted by default Modern: Unicode support for email content and sender/recipient adresses when compatible Fast: supports tcp connection reuse This client is designed to send emails to a relay server, and should not be used to send emails directly to the destination.
It is designed to be:
Secured: email are encrypted by default Modern: Unicode support for email content and sender/recipient addresses when compatible Fast: supports tcp connection reuse This client is designed to send emails to a relay server, and should not be used to send emails directly to the destination.
The relay server can be the local email server, a specific host or a third-party service.</description>
</item>
<item>
<title>Sendmail transport</title>
<link>https://lettre.github.io/lettre/sending-messages/sendmail/</link>
<link>http://docs.lettre.at/sending-messages/sendmail/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/sendmail/</guid>
<guid>http://docs.lettre.at/sending-messages/sendmail/</guid>
<description>The sendmail transport sends the email using the local sendmail command.
use lettre::sendmail::SendmailTransport; use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress}; let email = SimpleSendableEmail::new( EmailAddress::new(&#34;user@localhost&#34;.to_string()), vec![EmailAddress::new(&#34;root@localhost&#34;.to_string())], &#34;message_id&#34;.to_string(), &#34;Hello world&#34;.to_string(), ); let mut sender = SendmailTransport::new(); let result = sender.send(&amp;email); assert!(result.is_ok()); </description>
extern crate lettre; use lettre::sendmail::SendmailTransport; use lettre::{SimpleSendableEmail, EmailTransport}; fn main() { let email = SimpleSendableEmail::new( &amp;#34;user@localhost&amp;#34;.to_string(), &amp;amp;[&amp;#34;root@localhost&amp;#34;.to_string()], &amp;#34;message_id&amp;#34;.to_string(), &amp;#34;Hello world&amp;#34;.to_string(), ).unwrap(); let mut sender = SendmailTransport::new(); let result = sender.send(&amp;amp;email); assert!(result.is_ok()); }</description>
</item>
<item>
<title>Email creation</title>
<link>http://docs.lettre.at/creating-messages/email/</link>
<pubDate>Sun, 21 Jan 2018 23:46:17 +0200</pubDate>
<guid>http://docs.lettre.at/creating-messages/email/</guid>
<description>Simple example 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:
extern crate lettre_email; use lettre_email::EmailBuilder; fn main() { // Create an email let email = EmailBuilder::new() // Addresses can be specified by the tuple (email, alias) .to((&amp;#34;user@example.org&amp;#34;, &amp;#34;Firstname Lastname&amp;#34;)) // ... or by an address only .from(&amp;#34;user@example.com&amp;#34;) .subject(&amp;#34;Hi, Hello world&amp;#34;) .</description>
</item>
<item>
<title>File transport</title>
<link>https://lettre.github.io/lettre/sending-messages/file/</link>
<link>http://docs.lettre.at/sending-messages/file/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/file/</guid>
<guid>http://docs.lettre.at/sending-messages/file/</guid>
<description>The file transport writes the emails to the given directory. The name of the file will be message_id.txt. It can be useful for testing purposes, or if you want to keep track of sent messages.
use std::env::temp_dir; use lettre::file::FileEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress}; // Write to the local temp directory let mut sender = FileEmailTransport::new(temp_dir()); let email = SimpleSendableEmail::new( EmailAddress::new(&#34;user@localhost&#34;.to_string()), vec![EmailAddress::new(&#34;root@localhost&#34;.to_string())], &#34;message_id&#34;.to_string(), &#34;Hello world&#34;.to_string(), ); let result = sender.send(&amp;email); assert!(result.is_ok()); Example result in /tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.</description>
extern crate lettre; use std::env::temp_dir; use lettre::file::FileEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport}; fn main() { // Write to the local temp directory let mut sender = FileEmailTransport::new(temp_dir()); let email = SimpleSendableEmail::new( &amp;#34;user@localhost&amp;#34;.to_string(), &amp;amp;[&amp;#34;root@localhost&amp;#34;.to_string()], &amp;#34;message_id&amp;#34;.to_string(), &amp;#34;Hello world&amp;#34;.to_string(), ).</description>
</item>
<item>
<title>Stub transport</title>
<link>https://lettre.github.io/lettre/sending-messages/stub/</link>
<link>http://docs.lettre.at/sending-messages/stub/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/stub/</guid>
<guid>http://docs.lettre.at/sending-messages/stub/</guid>
<description>The stub transport only logs message envelope and drops the content. It can be useful for testing purposes.
use lettre::stub::StubEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress}; let email = SimpleSendableEmail::new( EmailAddress::new(&#34;user@localhost&#34;.to_string()), vec![EmailAddress::new(&#34;root@localhost&#34;.to_string())], &#34;message_id&#34;.to_string(), &#34;Hello world&#34;.to_string(), ); let mut sender = StubEmailTransport::new_positive(); let result = sender.send(&amp;email); assert!(result.is_ok()); Will log (when using a logger like env_logger):
b7c211bc-9811-45ce-8cd9-68eab575d695: from= to= </description>
extern crate lettre; use lettre::stub::StubEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport}; fn main() { let email = SimpleSendableEmail::new( &amp;#34;user@localhost&amp;#34;.to_string(), &amp;amp;[&amp;#34;root@localhost&amp;#34;.to_string()], &amp;#34;message_id&amp;#34;.to_string(), &amp;#34;Hello world&amp;#34;.to_string(), ).unwrap(); let mut sender = StubEmailTransport::new_positive(); let result = sender.send(&amp;amp;email); assert!(result.is_ok()); } Will log (when using a logger like env_logger):
b7c211bc-9811-45ce-8cd9-68eab575d695: from=&amp;lt;user@localhost&amp;gt; to=&amp;lt;root@localhost&amp;gt;</description>
</item>
</channel>

223
docs/js/auto-complete.js Normal file
View File

@@ -0,0 +1,223 @@
/*
JavaScript autoComplete v1.0.4
Copyright (c) 2014 Simon Steinberger / Pixabay
GitHub: https://github.com/Pixabay/JavaScript-autoComplete
License: http://www.opensource.org/licenses/mit-license.php
*/
var autoComplete = (function(){
// "use strict";
function autoComplete(options){
if (!document.querySelector) return;
// helpers
function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); }
function addEvent(el, type, handler){
if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);
}
function removeEvent(el, type, handler){
// if (el.removeEventListener) not working in IE11
if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler);
}
function live(elClass, event, cb, context){
addEvent(context || document, event, function(e){
var found, el = e.target || e.srcElement;
while (el && !(found = hasClass(el, elClass))) el = el.parentElement;
if (found) cb.call(el, e);
});
}
var o = {
selector: 0,
source: 0,
minChars: 3,
delay: 150,
offsetLeft: 0,
offsetTop: 1,
cache: 1,
menuClass: '',
renderItem: function (item, search){
// escape special characters
search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi");
return '<div class="autocomplete-suggestion" data-val="' + item + '">' + item.replace(re, "<b>$1</b>") + '</div>';
},
onSelect: function(e, term, item){}
};
for (var k in options) { if (options.hasOwnProperty(k)) o[k] = options[k]; }
// init
var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector);
for (var i=0; i<elems.length; i++) {
var that = elems[i];
// create suggestions container "sc"
that.sc = document.createElement('div');
that.sc.className = 'autocomplete-suggestions '+o.menuClass;
that.autocompleteAttr = that.getAttribute('autocomplete');
that.setAttribute('autocomplete', 'off');
that.cache = {};
that.last_val = '';
that.updateSC = function(resize, next){
var rect = that.getBoundingClientRect();
that.sc.style.left = Math.round(rect.left + (window.pageXOffset || document.documentElement.scrollLeft) + o.offsetLeft) + 'px';
that.sc.style.top = Math.round(rect.bottom + (window.pageYOffset || document.documentElement.scrollTop) + o.offsetTop) + 'px';
that.sc.style.width = Math.round(rect.right - rect.left) + 'px'; // outerWidth
if (!resize) {
that.sc.style.display = 'block';
if (!that.sc.maxHeight) { that.sc.maxHeight = parseInt((window.getComputedStyle ? getComputedStyle(that.sc, null) : that.sc.currentStyle).maxHeight); }
if (!that.sc.suggestionHeight) that.sc.suggestionHeight = that.sc.querySelector('.autocomplete-suggestion').offsetHeight;
if (that.sc.suggestionHeight)
if (!next) that.sc.scrollTop = 0;
else {
var scrTop = that.sc.scrollTop, selTop = next.getBoundingClientRect().top - that.sc.getBoundingClientRect().top;
if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0)
that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight;
else if (selTop < 0)
that.sc.scrollTop = selTop + scrTop;
}
}
}
addEvent(window, 'resize', that.updateSC);
document.body.appendChild(that.sc);
live('autocomplete-suggestion', 'mouseleave', function(e){
var sel = that.sc.querySelector('.autocomplete-suggestion.selected');
if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20);
}, that.sc);
live('autocomplete-suggestion', 'mouseover', function(e){
var sel = that.sc.querySelector('.autocomplete-suggestion.selected');
if (sel) sel.className = sel.className.replace('selected', '');
this.className += ' selected';
}, that.sc);
live('autocomplete-suggestion', 'mousedown', function(e){
if (hasClass(this, 'autocomplete-suggestion')) { // else outside click
var v = this.getAttribute('data-val');
that.value = v;
o.onSelect(e, v, this);
that.sc.style.display = 'none';
}
}, that.sc);
that.blurHandler = function(){
try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; }
if (!over_sb) {
that.last_val = that.value;
that.sc.style.display = 'none';
setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input
} else if (that !== document.activeElement) setTimeout(function(){ that.focus(); }, 20);
};
addEvent(that, 'blur', that.blurHandler);
var suggest = function(data){
var val = that.value;
that.cache[val] = data;
if (data.length && val.length >= o.minChars) {
var s = '';
for (var i=0;i<data.length;i++) s += o.renderItem(data[i], val);
that.sc.innerHTML = s;
that.updateSC(0);
}
else
that.sc.style.display = 'none';
}
that.keydownHandler = function(e){
var key = window.event ? e.keyCode : e.which;
// down (40), up (38)
if ((key == 40 || key == 38) && that.sc.innerHTML) {
var next, sel = that.sc.querySelector('.autocomplete-suggestion.selected');
if (!sel) {
next = (key == 40) ? that.sc.querySelector('.autocomplete-suggestion') : that.sc.childNodes[that.sc.childNodes.length - 1]; // first : last
next.className += ' selected';
console.log(next);
that.value = next.getAttribute('data-val');
} else {
next = (key == 40) ? sel.nextSibling : sel.previousSibling;
if (next) {
sel.className = sel.className.replace('selected', '');
next.className += ' selected';
that.value = next.getAttribute('data-val');
}
else { sel.className = sel.className.replace('selected', ''); that.value = that.last_val; next = 0; }
}
that.updateSC(0, next);
return false;
}
// esc
else if (key == 27) { that.value = that.last_val; that.sc.style.display = 'none'; }
// enter
else if (key == 13 || key == 9) {
var sel = that.sc.querySelector('.autocomplete-suggestion.selected');
if (sel && that.sc.style.display != 'none') { o.onSelect(e, sel.getAttribute('data-val'), sel); setTimeout(function(){ that.sc.style.display = 'none'; }, 20); }
}
};
addEvent(that, 'keydown', that.keydownHandler);
that.keyupHandler = function(e){
var key = window.event ? e.keyCode : e.which;
if (!key || (key < 35 || key > 40) && key != 13 && key != 27) {
var val = that.value;
if (val.length >= o.minChars) {
if (val != that.last_val) {
that.last_val = val;
clearTimeout(that.timer);
if (o.cache) {
if (val in that.cache) { suggest(that.cache[val]); return; }
// no requests if previous suggestions were empty
for (var i=1; i<val.length-o.minChars; i++) {
var part = val.slice(0, val.length-i);
if (part in that.cache && !that.cache[part].length) { suggest([]); return; }
}
}
that.timer = setTimeout(function(){ o.source(val, suggest) }, o.delay);
}
} else {
that.last_val = val;
that.sc.style.display = 'none';
}
}
};
addEvent(that, 'keyup', that.keyupHandler);
that.focusHandler = function(e){
that.last_val = '\n';
that.keyupHandler(e)
};
if (!o.minChars) addEvent(that, 'focus', that.focusHandler);
}
// public destroy method
this.destroy = function(){
for (var i=0; i<elems.length; i++) {
var that = elems[i];
removeEvent(window, 'resize', that.updateSC);
removeEvent(that, 'blur', that.blurHandler);
removeEvent(that, 'focus', that.focusHandler);
removeEvent(that, 'keydown', that.keydownHandler);
removeEvent(that, 'keyup', that.keyupHandler);
if (that.autocompleteAttr)
that.setAttribute('autocomplete', that.autocompleteAttr);
else
that.removeAttribute('autocomplete');
document.body.removeChild(that.sc);
that = null;
}
};
}
return autoComplete;
})();
(function(){
if (typeof define === 'function' && define.amd)
define('autoComplete', function () { return autoComplete; });
else if (typeof module !== 'undefined' && module.exports)
module.exports = autoComplete;
else
window.autoComplete = autoComplete;
})();

View File

@@ -17,7 +17,7 @@ var getUrlParameter = function getUrlParameter(sPageURL) {
};
// Execute actions on images generated from Markdown pages
var images = $("div#body-inner img");
var images = $("div#body-inner img").not(".inline");
// Wrap image inside a featherlight (to get a full size view in a popup)
images.wrap(function(){
var image =$(this);
@@ -56,7 +56,10 @@ images.each(function(index){
});
// Stick the top to the top of the screen when scrolling
$("#top-bar").stick_in_parent({spacer: false});
$("#top-bar").stick_in_parent( {
parent: ".sticky-parent",
spacer: ".sticky-spacer",
});
jQuery(document).ready(function() {

View File

@@ -83,9 +83,14 @@ $(window).resize(function() {
jQuery(document).ready(function() {
jQuery('#sidebar .category-icon').on('click', function() {
$( this ).toggleClass("fa-angle-down fa-angle-right") ;
$( this ).parent().parent().children('ul').toggle() ;
return false;
});
var sidebarStatus = searchStatus = 'open';
$('#sidebar .highlightable').perfectScrollbar();
// set the menu height
setMenuHeight();
jQuery('#overlay').on('click', function() {
@@ -147,10 +152,25 @@ jQuery(document).ready(function() {
});
});
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
if (sessionStorage.getItem('search-value')) {
jQuery(document.body).removeClass('searchbox-hidden');
jQuery('[data-search-input]').val(sessionStorage.getItem('search-value'));
jQuery('[data-search-input]').trigger('input');
var searchValue = sessionStorage.getItem('search-value')
$(document.body).removeClass('searchbox-hidden');
$('[data-search-input]').val(searchValue);
$('[data-search-input]').trigger('input');
var searchedElem = $('#body-inner').find(':contains(' + searchValue + ')').get(0);
if (searchedElem) {
searchedElem.scrollIntoView(true);
var scrolledY = window.scrollY;
if(scrolledY){
window.scroll(0, scrolledY - 125);
}
}
}
// clipboard
@@ -218,13 +238,108 @@ jQuery(document).ready(function() {
$('#top-bar a:not(:has(img)):not(.btn)').addClass('highlight');
$('#body-inner a:not(:has(img)):not(.btn)').addClass('highlight');
$('#toc-menu').hover(function() {
$('.progress').stop(true, false, true).fadeToggle(100);
});
var touchsupport = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)
if (!touchsupport){ // browser doesn't support touch
$('#toc-menu').hover(function() {
$('.progress').stop(true, false, true).fadeToggle(100);
});
$('.progress').hover(function() {
$('.progress').stop(true, false, true).fadeToggle(100);
});
}
if (touchsupport){ // browser does support touch
$('#toc-menu').click(function() {
$('.progress').stop(true, false, true).fadeToggle(100);
});
$('.progress').click(function() {
$('.progress').stop(true, false, true).fadeToggle(100);
});
}
/**
* Fix anchor scrolling that hides behind top nav bar
* Courtesy of https://stackoverflow.com/a/13067009/28106
*
* We could use pure css for this if only heading anchors were
* involved, but this works for any anchor, including footnotes
**/
(function (document, history, location) {
var HISTORY_SUPPORT = !!(history && history.pushState);
var anchorScrolls = {
ANCHOR_REGEX: /^#[^ ]+$/,
OFFSET_HEIGHT_PX: 50,
/**
* Establish events, and fix initial scroll position if a hash is provided.
*/
init: function () {
this.scrollToCurrent();
$(window).on('hashchange', $.proxy(this, 'scrollToCurrent'));
$('body').on('click', 'a', $.proxy(this, 'delegateAnchors'));
},
/**
* Return the offset amount to deduct from the normal scroll position.
* Modify as appropriate to allow for dynamic calculations
*/
getFixedOffset: function () {
return this.OFFSET_HEIGHT_PX;
},
/**
* If the provided href is an anchor which resolves to an element on the
* page, scroll to it.
* @param {String} href
* @return {Boolean} - Was the href an anchor.
*/
scrollIfAnchor: function (href, pushToHistory) {
var match, anchorOffset;
if (!this.ANCHOR_REGEX.test(href)) {
return false;
}
match = document.getElementById(href.slice(1));
if (match) {
anchorOffset = $(match).offset().top - this.getFixedOffset();
$('html, body').animate({ scrollTop: anchorOffset });
// Add the state to history as-per normal anchor links
if (HISTORY_SUPPORT && pushToHistory) {
history.pushState({}, document.title, location.pathname + href);
}
}
return !!match;
},
/**
* Attempt to scroll to the current location's hash.
*/
scrollToCurrent: function (e) {
if (this.scrollIfAnchor(window.location.hash) && e) {
e.preventDefault();
}
},
/**
* If the click event's target was an anchor, fix the scroll position.
*/
delegateAnchors: function (e) {
var elem = e.target;
if (this.scrollIfAnchor(elem.getAttribute('href'), true)) {
e.preventDefault();
}
}
};
$(document).ready($.proxy(anchorScrolls, 'init'));
})(window.document, window.history, window.location);
$('.progress').hover(function() {
$('.progress').stop(true, false, true).fadeToggle(100);
});
});
jQuery(window).on('load', function() {

View File

@@ -1,11 +1,19 @@
var lunrIndex, pagesIndex;
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
// Initialize lunrjs using our generated index file
function initLunr() {
if (!endsWith(baseurl,"/")){
baseurl = baseurl+'/'
};
// First retrieve the index file
$.getJSON(baseurl + "/json/search.json")
$.getJSON(baseurl +"index.json")
.done(function(index) {
pagesIndex = index;
pagesIndex = index;
// Set up lunrjs by declaring the fields we use
// Also provide their boost level for the ranking
lunrIndex = new lunr.Index
@@ -50,36 +58,33 @@ function search(query) {
// Let's get started
initLunr();
$( document ).ready(function() {
var horseyList = horsey($("#search-by").get(0), {
suggestions: function (value, done) {
var query = $("#search-by").val();
var results = search(query);
done(results);
var searchList = new autoComplete({
/* selector for the search box element */
selector: $("#search-by").get(0),
/* source is the callback to perform the search */
source: function(term, response) {
response(search(term));
},
filter: function (q, suggestion) {
return true;
/* renderItem displays individual search results */
renderItem: function(item, term) {
var numContextWords = 2;
var text = item.content.match(
"(?:\\s?(?:[\\w]+)\\s?){0,"+numContextWords+"}" +
term+"(?:\\s?(?:[\\w]+)\\s?){0,"+numContextWords+"}");
item.context = text;
return '<div class="autocomplete-suggestion" ' +
'data-term="' + term + '" ' +
'data-title="' + item.title + '" ' +
'data-uri="'+ item.uri + '" ' +
'data-context="' + item.context + '">' +
'» ' + item.title +
'<div class="context">' +
(item.context || '') +'</div>' +
'</div>';
},
set: function (value) {
location.href=value.href;
},
render: function (li, suggestion) {
var uri = suggestion.uri.substring(1,suggestion.uri.length);
var indexOfIndex = uri.lastIndexOf("/index");
if (indexOfIndex == -1) {
indexOfIndex = uri.length;
}
var href = uri.substring(uri.indexOf("/"), indexOfIndex);
suggestion.href = baseurl + href;
var query = $("#search-by").val();
var numWords = 2;
var text = suggestion.content.match("(?:\\s?(?:[\\w]+)\\s?){0,"+numWords+"}"+query+"(?:\\s?(?:[\\w]+)\\s?){0,"+numWords+"}");
suggestion.context = text;
var image = '<div>' + '» ' + suggestion.title + '</div><div style="font-size:12px">' + (suggestion.context || '') +'</div>';
li.innerHTML = image;
},
limit: 10
/* onSelect callback fires when a search suggestion is chosen */
onSelect: function(e, term, item) {
location.href = item.getAttribute('data-uri');
}
});
horseyList.refreshPosition();
});

View File

@@ -14,7 +14,7 @@
{
"uri": "/content/getting-started/intro",
"title": "Introduction",
"content": "\n{{% notice note %}}\nThis documentation is written for lettre 0.7.\nPlease use https://docs.rs/lettre/0.6.2/lettre/ for lettre 0.6.\n{{% /notice%}}\n\nLettre is an email library that allows creating and sending messages. It provides:\n\nAn easy to use email builder\nPluggable email transports\nUnicode support (for emails and transports, including for sender et recipient addresses when compatible)\nSecure defaults (emails are only sent encrypted by default)\n",
"content": "\nLettre is an email library that allows creating and sending messages. It provides:\n\nAn easy to use email builder\nPluggable email transports\nUnicode support (for emails and transports, including for sender et recipient addresses when compatible)\nSecure defaults (emails are only sent encrypted by default)\n",
"tags": []
},
{
@@ -26,7 +26,7 @@
{
"uri": "/content/sending-messages/file",
"title": "File transport",
"content": "\nThe file transport writes the emails to the given directory. The name of the file will be\nmessage_id.txt.\nIt can be useful for testing purposes, or if you want to keep track of sent messages.\n\nuse std::env::temp_dir;\n\nuse lettre::file::FileEmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};\n\n// Write to the local temp directory\nlet mut sender = FileEmailTransport::new(temp_dir());\nlet email = SimpleSendableEmail::new(\n EmailAddress::new(\"user@localhost\".to_string()),\n vec![EmailAddress::new(\"root@localhost\".to_string())],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n );\n\nlet result = sender.send(&email);\nassert!(result.is_ok());\n\nExample result in /tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.txt:\n\nb7c211bc-9811-45ce-8cd9-68eab575d695: from=user@localhost to=root@localhost\nTo: root@localhost\nFrom: user@localhost\nSubject: Hello\nDate: Sat, 31 Oct 2015 13:42:19 +0100\nMessage-ID: b7c211bc-9811-45ce-8cd9-68eab575d695.lettre@localhost\n\nHello World!\n",
"content": "\nThe file transport writes the emails to the given directory. The name of the file will be\nmessage_id.txt.\nIt can be useful for testing purposes, or if you want to keep track of sent messages.\n\nuse std::env::temp_dir;\n\nuse lettre::file::FileEmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\n// Write to the local temp directory\nlet mut sender = FileEmailTransport::new(temp_dir());\nlet email = SimpleSendableEmail::new(\n \"user@localhost\",\n vec![\"root@localhost\"],\n \"message_id\",\n \"Hello world\"\n );\n\nlet result = sender.send(email);\nassert!(result.is_ok());\n\nExample result in /tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.txt:\n\nb7c211bc-9811-45ce-8cd9-68eab575d695: from=user@localhost to=root@localhost\nTo: root@localhost\nFrom: user@localhost\nSubject: Hello\nDate: Sat, 31 Oct 2015 13:42:19 +0100\nMessage-ID: b7c211bc-9811-45ce-8cd9-68eab575d695.lettre@localhost\n\nHello World!\n",
"tags": []
},
{
@@ -38,19 +38,19 @@
{
"uri": "/content/sending-messages/sendmail",
"title": "Sendmail transport",
"content": "\nThe sendmail transport sends the email using the local sendmail command.\n\nuse lettre::sendmail::SendmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};\n\nlet email = SimpleSendableEmail::new(\n EmailAddress::new(\"user@localhost\".to_string()),\n vec![EmailAddress::new(\"root@localhost\".to_string())],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n );\n\nlet mut sender = SendmailTransport::new();\nlet result = sender.send(&email);\nassert!(result.is_ok());\n",
"content": "\nThe sendmail transport sends the email using the local sendmail command.\n\nuse lettre::sendmail::SendmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\nlet email = SimpleSendableEmail::new(\n \"user@localhost\",\n vec![\"root@localhost\"],\n \"message_id\",\n \"Hello world\"\n );\n\nlet mut sender = SendmailTransport::new();\nlet result = sender.send(email);\nassert!(result.is_ok());\n",
"tags": []
},
{
"uri": "/content/sending-messages/smtp",
"title": "SMTP transport",
"content": "\nThis transport uses the SMTP protocol to send emails over the network (locally or remotely).\n\nIt is desinged to be:\n\nSecured: email are encrypted by default\nModern: Unicode support for email content and sender/recipient adresses when compatible\nFast: supports tcp connection reuse\n\nThis client is designed to send emails to a relay server, and should not be used to send\nemails directly to the destination.\n\nThe relay server can be the local email server, a specific host or a third-party service.\n\nSimple example\n\nThis is the most basic example of usage:\n\nuse lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};\n\nlet email = SimpleSendableEmail::new(\n EmailAddress::new(\"user@localhost\".to_string()),\n vec![EmailAddress::new(\"root@localhost\".to_string())],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n );\n\n// Open a local connection on port 25\nlet mut mailer =\nSmtpTransport::builderunencryptedlocalhost().unwrap().build();\n// Send the email\nlet result = mailer.send(&email);\n\nassert!(result.is_ok());\n\n Complete example\n\nuse lettre::smtp::authentication::{Credentials, Mechanism};\nuse lettre::smtp::SUBMISSION_PORT;\nuse lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};\nuse lettre::smtp::extension::ClientId;\nuse lettre::smtp::ConnectionReuseParameters;\n\nlet email = SimpleSendableEmail::new(\n EmailAddress::new(\"user@localhost\".to_string()),\n vec![EmailAddress::new(\"root@localhost\".to_string())],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n );\n\n// Connect to a remote server on a custom port\nlet mut mailer = SmtpTransport::simplebuilder(\"server.tld\".tostring()).unwrap()\n // Set the name sent during EHLO/HELO, default is localhost\n .helloname(ClientId::Domain(\"my.hostname.tld\".tostring()))\n // Add credentials for authentication\n .credentials(Credentials::new(\"username\".tostring(), \"password\".tostring()))\n // Enable SMTPUTF8 if the server supports it\n .smtp_utf8(true)\n // Configure expected authentication mechanism\n .authentication_mechanism(Mechanism::Plain)\n // Enable connection reuse\n .connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();\n\nlet result_1 = mailer.send(&email);\nassert!(result1.isok());\n\n// The second email will use the same connection\nlet result_2 = mailer.send(&email);\nassert!(result2.isok());\n\n// Explicitly close the SMTP transaction as we enabled connection reuse\nmailer.close();\n\nLower level\n\nYou can also send commands, here is a simple email transaction without\nerror handling:\n\nuse lettre::EmailAddress;\nuse lettre::smtp::SMTP_PORT;\nuse lettre::smtp::client::Client;\nuse lettre::smtp::client::net::NetworkStream;\nuse lettre::smtp::extension::ClientId;\nuse lettre::smtp::commands::*;\n\nlet mut email_client: ClientNetworkStream = Client::new();\nlet _ = emailclient.connect(&(\"localhost\", SMTPPORT), None);\nlet _ = emailclient.smtpcommand(EhloCommand::new(ClientId::new(\"myhostname\".tostring())));\nlet _ = emailclient.smtpcommand(\n MailCommand::new(Some(EmailAddress::new(\"user@example.com\".to_string())), vec![])\n );\nlet _ = emailclient.smtpcommand(\n RcptCommand::new(EmailAddress::new(\"user@example.org\".to_string()), vec![])\n );\nlet _ = emailclient.smtpcommand(DataCommand);\nlet _ = emailclient.message(Box::new(\"Test email\".asbytes()));\nlet _ = emailclient.smtpcommand(QuitCommand);\n\n",
"content": "\nThis transport uses the SMTP protocol to send emails over the network (locally or remotely).\n\nIt is desinged to be:\n\nSecured: email are encrypted by default\nModern: Unicode support for email content and sender/recipient adresses when compatible\nFast: supports tcp connection reuse\n\nThis client is designed to send emails to a relay server, and should not be used to send\nemails directly to the destination.\n\nThe relay server can be the local email server, a specific host or a third-party service.\n\nSimple example\n\nThis is the most basic example of usage:\n\nuse lettre::{SimpleSendableEmail, EmailTransport};\nuse lettre::smtp::SmtpTransportBuilder;\nuse lettre::smtp::SecurityLevel;\n\nlet email = SimpleSendableEmail::new(\n \"user@localhost\",\n vec![\"root@localhost\"],\n \"message_id\",\n \"Hello world\"\n );\n\n// Open a local connection on port 25\nlet mut mailer =\nSmtpTransportBuilder::localhost().unwrap().security_level(SecurityLevel::Opportunistic).build();\n// Send the email\nlet result = mailer.send(email);\n\nassert!(result.is_ok());\n\n Complete example\n\nuse lettre::smtp::{SecurityLevel, SmtpTransport,\nSmtpTransportBuilder};\nuse lettre::smtp::authentication::Mechanism;\nuse lettre::smtp::SUBMISSION_PORT;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\nlet email = SimpleSendableEmail::new(\n \"user@localhost\",\n vec![\"root@localhost\"],\n \"message_id\",\n \"Hello world\"\n );\n\n// Connect to a remote server on a custom port\nlet mut mailer = SmtpTransportBuilder::new((\"server.tld\",\nSUBMISSION_PORT)).unwrap()\n // Set the name sent during EHLO/HELO, default is localhost\n .hello_name(\"my.hostname.tld\")\n // Add credentials for authentication\n .credentials(\"username\", \"password\")\n // Specify a TLS security level. You can also specify an SslContext with\n // .ssl_context(SslContext::Ssl23)\n .security_level(SecurityLevel::AlwaysEncrypt)\n // Enable SMTPUTF8 if the server supports it\n .smtp_utf8(true)\n // Configure expected authentication mechanism\n .authentication_mechanism(Mechanism::CramMd5)\n // Enable connection reuse\n .connection_reuse(true).build();\n\nlet result_1 = mailer.send(email.clone());\nassert!(result1.isok());\n\n// The second email will use the same connection\nlet result_2 = mailer.send(email);\nassert!(result2.isok());\n\n// Explicitly close the SMTP transaction as we enabled connection reuse\nmailer.close();\n\nLower level\n\nYou can also send commands, here is a simple email transaction without\nerror handling:\n\nuse lettre::smtp::SMTP_PORT;\nuse lettre::smtp::client::Client;\nuse lettre::smtp::client::net::NetworkStream;\n\nlet mut email_client: ClientNetworkStream = Client::new();\nlet _ = emailclient.connect(&(\"localhost\", SMTPPORT), None);\nlet _ = emailclient.ehlo(\"myhostname\");\nlet _ = email_client.mail(\"user@example.com\", None);\nlet _ = email_client.rcpt(\"user@example.org\");\nlet _ = email_client.data();\nlet _ = email_client.message(\"Test email\");\nlet _ = email_client.quit();\n\n",
"tags": []
},
{
"uri": "/content/sending-messages/stub",
"title": "Stub transport",
"content": "\nThe stub transport only logs message envelope and drops the content. It can be useful for\ntesting purposes.\n\nuse lettre::stub::StubEmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};\n\nlet email = SimpleSendableEmail::new(\n EmailAddress::new(\"user@localhost\".to_string()),\n vec![EmailAddress::new(\"root@localhost\".to_string())],\n \"messageid\".tostring(),\n \"Hello world\".to_string(),\n );\n\nlet mut sender = StubEmailTransport::new_positive();\nlet result = sender.send(&email);\nassert!(result.is_ok());\n\nWill log (when using a logger like env_logger):\n\nb7c211bc-9811-45ce-8cd9-68eab575d695: from=user@localhost to=root@localhost\n",
"content": "\nThe stub transport only logs message envelope and drops the content. It can be useful for\ntesting purposes.\n\nuse lettre::stub::StubEmailTransport;\nuse lettre::{SimpleSendableEmail, EmailTransport};\n\nlet email = SimpleSendableEmail::new(\n \"user@localhost\",\n vec![\"root@localhost\"],\n \"message_id\",\n \"Hello world\"\n );\n\nlet mut sender = StubEmailTransport;\nlet result = sender.send(email);\nassert!(result.is_ok());\n\nWill log the line:\n\nb7c211bc-9811-45ce-8cd9-68eab575d695: from=user@localhost to=root@localhost\n`",
"tags": []
}
]

273
docs/mermaid/mermaid.css Normal file
View File

@@ -0,0 +1,273 @@
/* Flowchart variables */
/* Sequence Diagram variables */
/* Gantt chart variables */
.mermaid .label {
color: #333;
}
.node rect,
.node circle,
.node ellipse,
.node polygon {
fill: #ECECFF;
stroke: #CCCCFF;
stroke-width: 1px;
}
.edgePath .path {
stroke: #333333;
}
.edgeLabel {
background-color: #e8e8e8;
}
.cluster rect {
fill: #ffffde !important;
rx: 4 !important;
stroke: #aaaa33 !important;
stroke-width: 1px !important;
}
.cluster text {
fill: #333;
}
.actor {
stroke: #CCCCFF;
fill: #ECECFF;
}
text.actor {
fill: black;
stroke: none;
}
.actor-line {
stroke: grey;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: #333;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
stroke: #333;
}
#arrowhead {
fill: #333;
}
#crosshead path {
fill: #333 !important;
stroke: #333 !important;
}
.messageText {
fill: #333;
stroke: none;
}
.labelBox {
stroke: #CCCCFF;
fill: #ECECFF;
}
.labelText {
fill: black;
stroke: none;
}
.loopText {
fill: black;
stroke: none;
}
.loopLine {
stroke-width: 2;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: #CCCCFF;
}
.note {
stroke: #aaaa33;
fill: #fff5ad;
}
.noteText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
/** Section styling */
.section {
stroke: none;
opacity: 0.2;
}
.section0 {
fill: rgba(102, 102, 255, 0.49);
}
.section2 {
fill: #fff400;
}
.section1,
.section3 {
fill: white;
opacity: 0.2;
}
.sectionTitle0 {
fill: #333;
}
.sectionTitle1 {
fill: #333;
}
.sectionTitle2 {
fill: #333;
}
.sectionTitle3 {
fill: #333;
}
.sectionTitle {
text-anchor: start;
font-size: 11px;
text-height: 14px;
}
/* Grid and axis */
.grid .tick {
stroke: lightgrey;
opacity: 0.3;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
/* Today line */
.today {
fill: none;
stroke: red;
stroke-width: 2px;
}
/* Task styling */
/* Default task */
.task {
stroke-width: 2;
}
.taskText {
text-anchor: middle;
font-size: 11px;
}
.taskTextOutsideRight {
fill: black;
text-anchor: start;
font-size: 11px;
}
.taskTextOutsideLeft {
fill: black;
text-anchor: end;
font-size: 11px;
}
/* Specific task settings for the sections*/
.taskText0,
.taskText1,
.taskText2,
.taskText3 {
fill: white;
}
.task0,
.task1,
.task2,
.task3 {
fill: #8a90dd;
stroke: #534fbc;
}
.taskTextOutside0,
.taskTextOutside2 {
fill: black;
}
.taskTextOutside1,
.taskTextOutside3 {
fill: black;
}
/* Active task */
.active0,
.active1,
.active2,
.active3 {
fill: #bfc7ff;
stroke: #534fbc;
}
.activeText0,
.activeText1,
.activeText2,
.activeText3 {
fill: black !important;
}
/* Completed task */
.done0,
.done1,
.done2,
.done3 {
stroke: grey;
fill: lightgrey;
stroke-width: 2;
}
.doneText0,
.doneText1,
.doneText2,
.doneText3 {
fill: black !important;
}
/* Tasks on the critical line */
.crit0,
.crit1,
.crit2,
.crit3 {
stroke: #ff8888;
fill: red;
stroke-width: 2;
}
.activeCrit0,
.activeCrit1,
.activeCrit2,
.activeCrit3 {
stroke: #ff8888;
fill: #bfc7ff;
stroke-width: 2;
}
.doneCrit0,
.doneCrit1,
.doneCrit2,
.doneCrit3 {
stroke: #ff8888;
fill: lightgrey;
stroke-width: 2;
cursor: pointer;
shape-rendering: crispEdges;
}
.doneCritText0,
.doneCritText1,
.doneCritText2,
.doneCritText3 {
fill: black !important;
}
.activeCritText0,
.activeCritText1,
.activeCritText2,
.activeCritText3 {
fill: black !important;
}
.titleText {
text-anchor: middle;
font-size: 18px;
fill: black;
}
/*
*/
.node text {
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: 'trebuchet ms', verdana, arial;
font-size: 12px;
background: #ffffde;
border: 1px solid #aaaa33;
border-radius: 2px;
pointer-events: none;
z-index: 100;
}

View File

@@ -0,0 +1,275 @@
/* Flowchart variables */
/* Sequence Diagram variables */
/* Gantt chart variables */
.mermaid .label {
color: #323D47;
}
.node rect,
.node circle,
.node ellipse,
.node polygon {
fill: #BDD5EA;
stroke: #81B1DB;
stroke-width: 1px;
}
.edgePath .path {
stroke: lightgrey;
}
.edgeLabel {
background-color: #e8e8e8;
}
.cluster rect {
fill: #6D6D65 !important;
rx: 4 !important;
stroke: rgba(255, 255, 255, 0.25) !important;
stroke-width: 1px !important;
}
.cluster text {
fill: #F9FFFE;
}
.actor {
stroke: #81B1DB;
fill: #BDD5EA;
}
text.actor {
fill: black;
stroke: none;
}
.actor-line {
stroke: lightgrey;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: lightgrey;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
stroke: lightgrey;
}
#arrowhead {
fill: lightgrey !important;
}
#crosshead path {
fill: lightgrey !important;
stroke: lightgrey !important;
}
.messageText {
fill: lightgrey;
stroke: none;
}
.labelBox {
stroke: #81B1DB;
fill: #BDD5EA;
}
.labelText {
fill: #323D47;
stroke: none;
}
.loopText {
fill: lightgrey;
stroke: none;
}
.loopLine {
stroke-width: 2;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: #81B1DB;
}
.note {
stroke: rgba(255, 255, 255, 0.25);
fill: #fff5ad;
}
.noteText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
/** Section styling */
.section {
stroke: none;
opacity: 0.2;
}
.section0 {
fill: rgba(255, 255, 255, 0.3);
}
.section2 {
fill: #EAE8B9;
}
.section1,
.section3 {
fill: white;
opacity: 0.2;
}
.sectionTitle0 {
fill: #F9FFFE;
}
.sectionTitle1 {
fill: #F9FFFE;
}
.sectionTitle2 {
fill: #F9FFFE;
}
.sectionTitle3 {
fill: #F9FFFE;
}
.sectionTitle {
text-anchor: start;
font-size: 11px;
text-height: 14px;
}
/* Grid and axis */
.grid .tick {
stroke: rgba(255, 255, 255, 0.3);
opacity: 0.3;
shape-rendering: crispEdges;
}
.grid .tick text {
fill: lightgrey;
opacity: 0.5;
}
.grid path {
stroke-width: 0;
}
/* Today line */
.today {
fill: none;
stroke: #DB5757;
stroke-width: 2px;
}
/* Task styling */
/* Default task */
.task {
stroke-width: 1;
}
.taskText {
text-anchor: middle;
font-size: 11px;
}
.taskTextOutsideRight {
fill: #323D47;
text-anchor: start;
font-size: 11px;
}
.taskTextOutsideLeft {
fill: #323D47;
text-anchor: end;
font-size: 11px;
}
/* Specific task settings for the sections*/
.taskText0,
.taskText1,
.taskText2,
.taskText3 {
fill: #323D47;
}
.task0,
.task1,
.task2,
.task3 {
fill: #BDD5EA;
stroke: rgba(255, 255, 255, 0.5);
}
.taskTextOutside0,
.taskTextOutside2 {
fill: lightgrey;
}
.taskTextOutside1,
.taskTextOutside3 {
fill: lightgrey;
}
/* Active task */
.active0,
.active1,
.active2,
.active3 {
fill: #81B1DB;
stroke: rgba(255, 255, 255, 0.5);
}
.activeText0,
.activeText1,
.activeText2,
.activeText3 {
fill: #323D47 !important;
}
/* Completed task */
.done0,
.done1,
.done2,
.done3 {
fill: lightgrey;
}
.doneText0,
.doneText1,
.doneText2,
.doneText3 {
fill: #323D47 !important;
}
/* Tasks on the critical line */
.crit0,
.crit1,
.crit2,
.crit3 {
stroke: #E83737;
fill: #E83737;
stroke-width: 2;
}
.activeCrit0,
.activeCrit1,
.activeCrit2,
.activeCrit3 {
stroke: #E83737;
fill: #81B1DB;
stroke-width: 2;
}
.doneCrit0,
.doneCrit1,
.doneCrit2,
.doneCrit3 {
stroke: #E83737;
fill: lightgrey;
stroke-width: 1;
cursor: pointer;
shape-rendering: crispEdges;
}
.doneCritText0,
.doneCritText1,
.doneCritText2,
.doneCritText3 {
fill: lightgrey !important;
}
.activeCritText0,
.activeCritText1,
.activeCritText2,
.activeCritText3 {
fill: #323D47 !important;
}
.titleText {
text-anchor: middle;
font-size: 18px;
fill: lightgrey;
}
/*
*/
.node text {
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: 'trebuchet ms', verdana, arial;
font-size: 12px;
background: #6D6D65;
border: 1px solid rgba(255, 255, 255, 0.25);
border-radius: 2px;
pointer-events: none;
z-index: 100;
}

View File

@@ -0,0 +1,353 @@
/* Flowchart variables */
/* Sequence Diagram variables */
/* Gantt chart variables */
.mermaid .label {
font-family: 'trebuchet ms', verdana, arial;
color: #333;
}
.node rect,
.node circle,
.node ellipse,
.node polygon {
fill: #cde498;
stroke: #13540c;
stroke-width: 1px;
}
.edgePath .path {
stroke: green;
stroke-width: 1.5px;
}
.edgeLabel {
background-color: #e8e8e8;
}
.cluster rect {
fill: #cdffb2 !important;
rx: 4 !important;
stroke: #6eaa49 !important;
stroke-width: 1px !important;
}
.cluster text {
fill: #333;
}
.actor {
stroke: #13540c;
fill: #cde498;
}
text.actor {
fill: black;
stroke: none;
}
.actor-line {
stroke: grey;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: #333;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: "2 2";
stroke: #333;
}
#arrowhead {
fill: #333;
}
#crosshead path {
fill: #333 !important;
stroke: #333 !important;
}
.messageText {
fill: #333;
stroke: none;
}
.labelBox {
stroke: #326932;
fill: #cde498;
}
.labelText {
fill: black;
stroke: none;
}
.loopText {
fill: black;
stroke: none;
}
.loopLine {
stroke-width: 2;
stroke-dasharray: "2 2";
marker-end: "url(#arrowhead)";
stroke: #326932;
}
.note {
stroke: #6eaa49;
fill: #fff5ad;
}
.noteText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
/** Section styling */
.section {
stroke: none;
opacity: 0.2;
}
.section0 {
fill: #6eaa49;
}
.section2 {
fill: #6eaa49;
}
.section1,
.section3 {
fill: white;
opacity: 0.2;
}
.sectionTitle0 {
fill: #333;
}
.sectionTitle1 {
fill: #333;
}
.sectionTitle2 {
fill: #333;
}
.sectionTitle3 {
fill: #333;
}
.sectionTitle {
text-anchor: start;
font-size: 11px;
text-height: 14px;
}
/* Grid and axis */
.grid .tick {
stroke: lightgrey;
opacity: 0.3;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
/* Today line */
.today {
fill: none;
stroke: red;
stroke-width: 2px;
}
/* Task styling */
/* Default task */
.task {
stroke-width: 2;
}
.taskText {
text-anchor: middle;
font-size: 11px;
}
.taskTextOutsideRight {
fill: black;
text-anchor: start;
font-size: 11px;
}
.taskTextOutsideLeft {
fill: black;
text-anchor: end;
font-size: 11px;
}
/* Specific task settings for the sections*/
.taskText0,
.taskText1,
.taskText2,
.taskText3 {
fill: white;
}
.task0,
.task1,
.task2,
.task3 {
fill: #487e3a;
stroke: #13540c;
}
.taskTextOutside0,
.taskTextOutside2 {
fill: black;
}
.taskTextOutside1,
.taskTextOutside3 {
fill: black;
}
/* Active task */
.active0,
.active1,
.active2,
.active3 {
fill: #cde498;
stroke: #13540c;
}
.activeText0,
.activeText1,
.activeText2,
.activeText3 {
fill: black !important;
}
/* Completed task */
.done0,
.done1,
.done2,
.done3 {
stroke: grey;
fill: lightgrey;
stroke-width: 2;
}
.doneText0,
.doneText1,
.doneText2,
.doneText3 {
fill: black !important;
}
/* Tasks on the critical line */
.crit0,
.crit1,
.crit2,
.crit3 {
stroke: #ff8888;
fill: red;
stroke-width: 2;
}
.activeCrit0,
.activeCrit1,
.activeCrit2,
.activeCrit3 {
stroke: #ff8888;
fill: #cde498;
stroke-width: 2;
}
.doneCrit0,
.doneCrit1,
.doneCrit2,
.doneCrit3 {
stroke: #ff8888;
fill: lightgrey;
stroke-width: 2;
cursor: pointer;
shape-rendering: crispEdges;
}
.doneCritText0,
.doneCritText1,
.doneCritText2,
.doneCritText3 {
fill: black !important;
}
.activeCritText0,
.activeCritText1,
.activeCritText2,
.activeCritText3 {
fill: black !important;
}
.titleText {
text-anchor: middle;
font-size: 18px;
fill: black;
}
/*
*/
g.classGroup text {
fill: #13540c;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
g.classGroup rect {
fill: #cde498;
stroke: #13540c;
}
g.classGroup line {
stroke: #13540c;
stroke-width: 1;
}
svg .classLabel .box {
stroke: none;
stroke-width: 0;
fill: #cde498;
opacity: 0.5;
}
svg .classLabel .label {
fill: #13540c;
}
.relation {
stroke: #13540c;
stroke-width: 1;
fill: none;
}
.composition {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
#compositionStart {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
#compositionEnd {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
.aggregation {
fill: #cde498;
stroke: #13540c;
stroke-width: 1;
}
#aggregationStart {
fill: #cde498;
stroke: #13540c;
stroke-width: 1;
}
#aggregationEnd {
fill: #cde498;
stroke: #13540c;
stroke-width: 1;
}
#dependencyStart {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
#dependencyEnd {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
#extensionStart {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
#extensionEnd {
fill: #13540c;
stroke: #13540c;
stroke-width: 1;
}
.node text {
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: 'trebuchet ms', verdana, arial;
font-size: 12px;
background: #cdffb2;
border: 1px solid #6eaa49;
border-radius: 2px;
pointer-events: none;
z-index: 100;
}

30
docs/mermaid/mermaid.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -3,54 +3,65 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>File transport :: Lettre site</title>
<title>File transport</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/sending-messages/file/">
<body class="" data-url="/sending-messages/file/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -61,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -125,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item parent" data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item active" data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
parent
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item active">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -213,139 +309,121 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="padding highlightable">
<div id="top-bar">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/file.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/sending-messages/'>Sending messages</a> > File transport
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/file.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<span id="toc-menu"><a href=""><i class="fa fa-list-alt"></i></a></span>
<a href="/lettre/sending-messages/" itemprop="url"><span itemprop="title">Sending messages</span></a> <i class="fa fa-angle-right"></i>
<span itemprop="title"> File transport</span>
</div>
<div class="progress">
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>File transport</h1>
<div id="body-inner">
<h1>File transport</h1>
<p>The file transport writes the emails to the given directory. The name of the file will be
<code>message_id.txt</code>.
It can be useful for testing purposes, or if you want to keep track of sent messages.</p>
use std::env::temp_dir;
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">crate</span> lettre;
use lettre::file::FileEmailTransport;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
<span style="color:#66d9ef">use</span> std::env::temp_dir;
// Write to the local temp directory
let mut sender = FileEmailTransport::new(temp_dir());
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
<span style="color:#66d9ef">use</span> lettre::file::FileEmailTransport;
<span style="color:#66d9ef">use</span> lettre::{SimpleSendableEmail, EmailTransport};
let result = sender.send(&email);
assert!(result.is_ok());
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
<span style="color:#75715e">// Write to the local temp directory
</span><span style="color:#75715e"></span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> sender <span style="color:#f92672">=</span> FileEmailTransport::new(temp_dir());
<span style="color:#66d9ef">let</span> email <span style="color:#f92672">=</span> SimpleSendableEmail::new(
<span style="color:#e6db74">&#34;user@localhost&#34;</span>.to_string(),
<span style="color:#f92672">&amp;</span>[<span style="color:#e6db74">&#34;root@localhost&#34;</span>.to_string()],
<span style="color:#e6db74">&#34;message_id&#34;</span>.to_string(),
<span style="color:#e6db74">&#34;Hello world&#34;</span>.to_string(),
).unwrap();
<span style="color:#66d9ef">let</span> result <span style="color:#f92672">=</span> sender.send(<span style="color:#f92672">&amp;</span>email);
assert<span style="color:#f92672">!</span>(result.is_ok());
}</code></pre></div>
<p>Example result in <code>/tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.txt</code>:</p>
b7c211bc-9811-45ce-8cd9-68eab575d695: from=<user@localhost> to=<root@localhost>
To: <root@localhost>
From: <user@localhost>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">b7c211bc-9811-45ce-8cd9-68eab575d695: from=&lt;user@localhost&gt; to=&lt;root@localhost&gt;
To: &lt;root@localhost&gt;
From: &lt;user@localhost&gt;
Subject: Hello
Date: Sat, 31 Oct 2015 13:42:19 +0100
Message-ID: <b7c211bc-9811-45ce-8cd9-68eab575d695.lettre@localhost>
Hello World!
Message-ID: &lt;b7c211bc-9811-45ce-8cd9-68eab575d695.lettre@localhost&gt;
Hello World!</code></pre></div>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -368,12 +446,6 @@ Hello World!
<a class="nav nav-prev" href="/lettre/sending-messages/sendmail/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/sending-messages/stub/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -383,23 +455,203 @@ Hello World!
<a class="nav nav-prev" href="/sending-messages/sendmail/" title="Sendmail transport"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/stub/" title="Stub transport" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>

View File

@@ -1,57 +1,67 @@
<!DOCTYPE html>
<html lang="en" class="js csstransforms3d">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Sending messages :: Lettre site</title>
<title>Sending messages</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/sending-messages/">
<body class="" data-url="/sending-messages/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -62,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -126,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item active parent" data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
parent
active
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -214,37 +309,82 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/_index.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > Sending messages
<div class="padding highlightable">
<div id="top-bar">
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<div class="progress">
<div class="wrapper">
<nav id="TableOfContents">
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#sending-messages">Sending Messages</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
</div>
</div>
<span itemprop="title"> Sending messages</span>
</div>
</div>
<div id="chapter">
<div id="body-inner">
<div id="body-inner">
<h1>Sending messages</h1>
@@ -254,55 +394,13 @@
<p>This section explains how to manipulate emails you have created.</p>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -317,12 +415,6 @@
<a class="nav nav-prev" href="/lettre/creating-messages/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/sending-messages/intro/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -340,26 +432,200 @@
<a class="nav nav-prev" href="/creating-messages/email/" title="Email creation"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/intro/" title="Introduction" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -2,67 +2,67 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Sending messages on Lettre site</title>
<link>https://lettre.github.io/lettre/sending-messages/</link>
<link>http://docs.lettre.at/sending-messages/</link>
<description>Recent content in Sending messages on Lettre site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Sun, 21 May 2017 23:46:01 +0200</lastBuildDate>
<atom:link href="https://lettre.github.io/lettre/sending-messages/index.xml" rel="self" type="application/rss+xml" />
<atom:link href="http://docs.lettre.at/sending-messages/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Introduction</title>
<link>https://lettre.github.io/lettre/sending-messages/intro/</link>
<link>http://docs.lettre.at/sending-messages/intro/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/intro/</guid>
<guid>http://docs.lettre.at/sending-messages/intro/</guid>
<description>This mailer contains several different transports for your emails. To be sendable, the emails have to implement SendableEmail, which is the case for emails created with lettre_email.
The following transports are available:
The SmtpTransport uses the SMTP protocol to send the message over the network. It is the prefered way of sending emails. The SendmailTransport uses the sendmail command to send messages. It is an alternative to the SMTP transport.</description>
The SmtpTransport uses the SMTP protocol to send the message over the network. It is the preferred way of sending emails. The SendmailTransport uses the sendmail command to send messages. It is an alternative to the SMTP transport.</description>
</item>
<item>
<title>SMTP transport</title>
<link>https://lettre.github.io/lettre/sending-messages/smtp/</link>
<link>http://docs.lettre.at/sending-messages/smtp/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/smtp/</guid>
<guid>http://docs.lettre.at/sending-messages/smtp/</guid>
<description>This transport uses the SMTP protocol to send emails over the network (locally or remotely).
It is desinged to be:
Secured: email are encrypted by default Modern: Unicode support for email content and sender/recipient adresses when compatible Fast: supports tcp connection reuse This client is designed to send emails to a relay server, and should not be used to send emails directly to the destination.
It is designed to be:
Secured: email are encrypted by default Modern: Unicode support for email content and sender/recipient addresses when compatible Fast: supports tcp connection reuse This client is designed to send emails to a relay server, and should not be used to send emails directly to the destination.
The relay server can be the local email server, a specific host or a third-party service.</description>
</item>
<item>
<title>Sendmail transport</title>
<link>https://lettre.github.io/lettre/sending-messages/sendmail/</link>
<link>http://docs.lettre.at/sending-messages/sendmail/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/sendmail/</guid>
<guid>http://docs.lettre.at/sending-messages/sendmail/</guid>
<description>The sendmail transport sends the email using the local sendmail command.
use lettre::sendmail::SendmailTransport; use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress}; let email = SimpleSendableEmail::new( EmailAddress::new(&#34;user@localhost&#34;.to_string()), vec![EmailAddress::new(&#34;root@localhost&#34;.to_string())], &#34;message_id&#34;.to_string(), &#34;Hello world&#34;.to_string(), ); let mut sender = SendmailTransport::new(); let result = sender.send(&amp;email); assert!(result.is_ok()); </description>
extern crate lettre; use lettre::sendmail::SendmailTransport; use lettre::{SimpleSendableEmail, EmailTransport}; fn main() { let email = SimpleSendableEmail::new( &amp;#34;user@localhost&amp;#34;.to_string(), &amp;amp;[&amp;#34;root@localhost&amp;#34;.to_string()], &amp;#34;message_id&amp;#34;.to_string(), &amp;#34;Hello world&amp;#34;.to_string(), ).unwrap(); let mut sender = SendmailTransport::new(); let result = sender.send(&amp;amp;email); assert!(result.is_ok()); }</description>
</item>
<item>
<title>File transport</title>
<link>https://lettre.github.io/lettre/sending-messages/file/</link>
<link>http://docs.lettre.at/sending-messages/file/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/file/</guid>
<guid>http://docs.lettre.at/sending-messages/file/</guid>
<description>The file transport writes the emails to the given directory. The name of the file will be message_id.txt. It can be useful for testing purposes, or if you want to keep track of sent messages.
use std::env::temp_dir; use lettre::file::FileEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress}; // Write to the local temp directory let mut sender = FileEmailTransport::new(temp_dir()); let email = SimpleSendableEmail::new( EmailAddress::new(&#34;user@localhost&#34;.to_string()), vec![EmailAddress::new(&#34;root@localhost&#34;.to_string())], &#34;message_id&#34;.to_string(), &#34;Hello world&#34;.to_string(), ); let result = sender.send(&amp;email); assert!(result.is_ok()); Example result in /tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.</description>
extern crate lettre; use std::env::temp_dir; use lettre::file::FileEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport}; fn main() { // Write to the local temp directory let mut sender = FileEmailTransport::new(temp_dir()); let email = SimpleSendableEmail::new( &amp;#34;user@localhost&amp;#34;.to_string(), &amp;amp;[&amp;#34;root@localhost&amp;#34;.to_string()], &amp;#34;message_id&amp;#34;.to_string(), &amp;#34;Hello world&amp;#34;.to_string(), ).</description>
</item>
<item>
<title>Stub transport</title>
<link>https://lettre.github.io/lettre/sending-messages/stub/</link>
<link>http://docs.lettre.at/sending-messages/stub/</link>
<pubDate>Sun, 21 May 2017 23:46:17 +0200</pubDate>
<guid>https://lettre.github.io/lettre/sending-messages/stub/</guid>
<guid>http://docs.lettre.at/sending-messages/stub/</guid>
<description>The stub transport only logs message envelope and drops the content. It can be useful for testing purposes.
use lettre::stub::StubEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress}; let email = SimpleSendableEmail::new( EmailAddress::new(&#34;user@localhost&#34;.to_string()), vec![EmailAddress::new(&#34;root@localhost&#34;.to_string())], &#34;message_id&#34;.to_string(), &#34;Hello world&#34;.to_string(), ); let mut sender = StubEmailTransport::new_positive(); let result = sender.send(&amp;email); assert!(result.is_ok()); Will log (when using a logger like env_logger):
b7c211bc-9811-45ce-8cd9-68eab575d695: from= to= </description>
extern crate lettre; use lettre::stub::StubEmailTransport; use lettre::{SimpleSendableEmail, EmailTransport}; fn main() { let email = SimpleSendableEmail::new( &amp;#34;user@localhost&amp;#34;.to_string(), &amp;amp;[&amp;#34;root@localhost&amp;#34;.to_string()], &amp;#34;message_id&amp;#34;.to_string(), &amp;#34;Hello world&amp;#34;.to_string(), ).unwrap(); let mut sender = StubEmailTransport::new_positive(); let result = sender.send(&amp;amp;email); assert!(result.is_ok()); } Will log (when using a logger like env_logger):
b7c211bc-9811-45ce-8cd9-68eab575d695: from=&amp;lt;user@localhost&amp;gt; to=&amp;lt;root@localhost&amp;gt;</description>
</item>
</channel>

View File

@@ -3,54 +3,65 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Introduction :: Lettre site</title>
<title>Introduction</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/sending-messages/intro/">
<body class="" data-url="/sending-messages/intro/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -61,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -125,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item parent" data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item active" data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
parent
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item active">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -213,59 +309,78 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="padding highlightable">
<div id="top-bar">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/intro.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/sending-messages/'>Sending messages</a> > Introduction
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/intro.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<span id="toc-menu"><a href=""><i class="fa fa-list-alt"></i></a></span>
<a href="/lettre/sending-messages/" itemprop="url"><span itemprop="title">Sending messages</span></a> <i class="fa fa-angle-right"></i>
<span itemprop="title"> Introduction</span>
</div>
<div class="progress">
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Introduction</h1>
<div id="body-inner">
<h1>Introduction</h1>
<p>This mailer contains several different transports for your emails. To be sendable, the
@@ -275,7 +390,7 @@ emails have to implement <code>SendableEmail</code>, which is the case for email
<ul>
<li>The <code>SmtpTransport</code> uses the SMTP protocol to send the message over the network. It is
the prefered way of sending emails.</li>
the preferred way of sending emails.</li>
<li>The <code>SendmailTransport</code> uses the sendmail command to send messages. It is an alternative to
the SMTP transport.</li>
<li>The <code>FileTransport</code> creates a file containing the email content to be sent. It can be used
@@ -285,53 +400,14 @@ logs.</li>
</ul>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -348,12 +424,6 @@ logs.</li>
<a class="nav nav-prev" href="/lettre/sending-messages/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/sending-messages/smtp/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -369,23 +439,200 @@ logs.</li>
<a class="nav nav-prev" href="/sending-messages/" title="Sending messages"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/smtp/" title="SMTP transport" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>

View File

@@ -3,54 +3,65 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Sendmail transport :: Lettre site</title>
<title>Sendmail transport</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/sending-messages/sendmail/">
<body class="" data-url="/sending-messages/sendmail/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -61,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -125,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item parent" data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item active" data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
parent
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item active">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -213,124 +309,107 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="padding highlightable">
<div id="top-bar">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/sendmail.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/sending-messages/'>Sending messages</a> > Sendmail transport
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/sendmail.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<span id="toc-menu"><a href=""><i class="fa fa-list-alt"></i></a></span>
<a href="/lettre/sending-messages/" itemprop="url"><span itemprop="title">Sending messages</span></a> <i class="fa fa-angle-right"></i>
<span itemprop="title"> Sendmail transport</span>
</div>
<div class="progress">
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Sendmail transport</h1>
<div id="body-inner">
<h1>Sendmail transport</h1>
<p>The sendmail transport sends the email using the local sendmail command.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust,no_run" data-lang="rust,no_run">extern crate lettre;
use lettre::sendmail::SendmailTransport;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
use lettre::{SimpleSendableEmail, EmailTransport};
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
let mut sender = SendmailTransport::new();
let result = sender.send(&email);
assert!(result.is_ok());
fn main() {
let email = SimpleSendableEmail::new(
&#34;user@localhost&#34;.to_string(),
&amp;[&#34;root@localhost&#34;.to_string()],
&#34;message_id&#34;.to_string(),
&#34;Hello world&#34;.to_string(),
).unwrap();
let mut sender = SendmailTransport::new();
let result = sender.send(&amp;email);
assert!(result.is_ok());
}</code></pre></div>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -351,12 +430,6 @@ assert!(result.is_ok());
<a class="nav nav-prev" href="/lettre/sending-messages/smtp/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/sending-messages/file/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -368,23 +441,203 @@ assert!(result.is_ok());
<a class="nav nav-prev" href="/sending-messages/smtp/" title="SMTP transport"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/file/" title="File transport" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>

View File

@@ -3,54 +3,65 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>SMTP transport :: Lettre site</title>
<title>SMTP transport</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/sending-messages/smtp/">
<body class="" data-url="/sending-messages/smtp/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -61,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -125,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item parent" data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item active" data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
parent
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item active">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -213,47 +309,61 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="padding highlightable">
<div id="top-bar">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/smtp.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/sending-messages/'>Sending messages</a> > SMTP transport
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/smtp.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<span id="toc-menu"><a href=""><i class="fa fa-list-alt"></i></a></span>
<a href="/lettre/sending-messages/" itemprop="url"><span itemprop="title">Sending messages</span></a> <i class="fa fa-angle-right"></i>
<span itemprop="title"> SMTP transport</span>
</div>
<div class="progress">
<div class="progress">
<div class="wrapper">
<nav id="TableOfContents">
<ul>
@@ -275,23 +385,28 @@
</div>
</div>
</div>
<div id="body-inner">
<h1>SMTP transport</h1>
<div id="body-inner">
<h1>SMTP transport</h1>
<p>This transport uses the SMTP protocol to send emails over the network (locally or remotely).</p>
<p>It is desinged to be:</p>
<p>It is designed to be:</p>
<ul>
<li>Secured: email are encrypted by default</li>
<li>Modern: Unicode support for email content and sender/recipient adresses when compatible</li>
<li>Modern: Unicode support for email content and sender/recipient addresses when compatible</li>
<li>Fast: supports tcp connection reuse</li>
</ul>
@@ -303,65 +418,71 @@ emails directly to the destination.</p>
<h4 id="simple-example">Simple example</h4>
<p>This is the most basic example of usage:</p>
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust,no_run" data-lang="rust,no_run">extern crate lettre;
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
use lettre::{SimpleSendableEmail, EmailTransport, SmtpTransport};
// Open a local connection on port 25
let mut mailer =
SmtpTransport::builder_unencrypted_localhost().unwrap().build();
// Send the email
let result = mailer.send(&email);
fn main() {
let email = SimpleSendableEmail::new(
&#34;user@localhost&#34;.to_string(),
&amp;[&#34;root@localhost&#34;.to_string()],
&#34;message_id&#34;.to_string(),
&#34;Hello world&#34;.to_string(),
).unwrap();
assert!(result.is_ok());
// Open a local connection on port 25
let mut mailer =
SmtpTransport::builder_unencrypted_localhost().unwrap().build();
// Send the email
let result = mailer.send(&amp;email);
assert!(result.is_ok());
}</code></pre></div>
<h4 id="complete-example">Complete example</h4>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust,no_run" data-lang="rust,no_run">extern crate lettre;
use lettre::smtp::authentication::{Credentials, Mechanism};
use lettre::smtp::SUBMISSION_PORT;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};
use lettre::{SimpleSendableEmail, EmailTransport, SmtpTransport};
use lettre::smtp::extension::ClientId;
use lettre::smtp::ConnectionReuseParameters;
fn main() {
let email = SimpleSendableEmail::new(
&#34;user@localhost&#34;.to_string(),
&amp;[&#34;root@localhost&#34;.to_string()],
&#34;message_id&#34;.to_string(),
&#34;Hello world&#34;.to_string(),
).unwrap();
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
// Connect to a remote server on a custom port
let mut mailer = SmtpTransport::simple_builder(&#34;server.tld&#34;).unwrap()
// Set the name sent during EHLO/HELO, default is `localhost`
.hello_name(ClientId::Domain(&#34;my.hostname.tld&#34;.to_string()))
// Add credentials for authentication
.credentials(Credentials::new(&#34;username&#34;.to_string(), &#34;password&#34;.to_string()))
// Enable SMTPUTF8 if the server supports it
.smtp_utf8(true)
// Configure expected authentication mechanism
.authentication_mechanism(Mechanism::Plain)
// Enable connection reuse
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();
// Connect to a remote server on a custom port
let mut mailer = SmtpTransport::simple_builder("server.tld".to_string()).unwrap()
// Set the name sent during EHLO/HELO, default is `localhost`
.hello_name(ClientId::Domain("my.hostname.tld".to_string()))
// Add credentials for authentication
.credentials(Credentials::new("username".to_string(), "password".to_string()))
// Enable SMTPUTF8 if the server supports it
.smtp_utf8(true)
// Configure expected authentication mechanism
.authentication_mechanism(Mechanism::Plain)
// Enable connection reuse
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();
let result_1 = mailer.send(&amp;email);
assert!(result_1.is_ok());
let result_1 = mailer.send(&email);
assert!(result_1.is_ok());
// The second email will use the same connection
let result_2 = mailer.send(&email);
assert!(result_2.is_ok());
// Explicitly close the SMTP transaction as we enabled connection reuse
mailer.close();
// The second email will use the same connection
let result_2 = mailer.send(&amp;email);
assert!(result_2.is_ok());
// Explicitly close the SMTP transaction as we enabled connection reuse
mailer.close();
}</code></pre></div>
<h4 id="lower-level">Lower level</h4>
<p>You can also send commands, here is a simple email transaction without
error handling:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust,no_run" data-lang="rust,no_run">extern crate lettre;
use lettre::EmailAddress;
use lettre::smtp::SMTP_PORT;
use lettre::smtp::client::Client;
@@ -369,67 +490,29 @@ use lettre::smtp::client::net::NetworkStream;
use lettre::smtp::extension::ClientId;
use lettre::smtp::commands::*;
let mut email_client: Client<NetworkStream> = Client::new();
let _ = email_client.connect(&("localhost", SMTP_PORT), None);
let _ = email_client.smtp_command(EhloCommand::new(ClientId::new("my_hostname".to_string())));
let _ = email_client.smtp_command(
MailCommand::new(Some(EmailAddress::new("user@example.com".to_string())), vec![])
);
let _ = email_client.smtp_command(
RcptCommand::new(EmailAddress::new("user@example.org".to_string()), vec![])
);
let _ = email_client.smtp_command(DataCommand);
let _ = email_client.message(Box::new("Test email".as_bytes()));
let _ = email_client.smtp_command(QuitCommand);
fn main() {
let mut email_client: Client&lt;NetworkStream&gt; = Client::new();
let _ = email_client.connect(&amp;(&#34;localhost&#34;, SMTP_PORT), None);
let _ = email_client.command(EhloCommand::new(ClientId::new(&#34;my_hostname&#34;.to_string())));
let _ = email_client.command(
MailCommand::new(Some(EmailAddress::new(&#34;user@example.com&#34;.to_string()).unwrap()), vec![])
);
let _ = email_client.command(
RcptCommand::new(EmailAddress::new(&#34;user@example.org&#34;.to_string()).unwrap(), vec![])
);
let _ = email_client.command(DataCommand);
let _ = email_client.message(Box::new(&#34;Test email&#34;.as_bytes()));
let _ = email_client.command(QuitCommand);
}</code></pre></div>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -448,12 +531,6 @@ let _ = email_client.smtp_command(QuitCommand);
<a class="nav nav-prev" href="/lettre/sending-messages/intro/"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/lettre/sending-messages/sendmail/" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
@@ -467,23 +544,203 @@ let _ = email_client.smtp_command(QuitCommand);
<a class="nav nav-prev" href="/sending-messages/intro/" title="Introduction"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/sendmail/" title="Sendmail transport" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>

View File

@@ -3,54 +3,65 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.20.7" />
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="https://lettre.github.io/lettre//images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Stub transport :: Lettre site</title>
<title>Stub transport</title>
<link href="https://lettre.github.io/lettre//css/nucleus.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/font-awesome.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hybrid.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/featherlight.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/perfect-scrollbar.min.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/horsey.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/theme.css" rel="stylesheet">
<link href="https://lettre.github.io/lettre//css/hugo-theme.css" rel="stylesheet">
<script src="https://lettre.github.io/lettre//js/jquery-2.x.min.js"></script>
<style type="text/css">:root #header + #content > #left > #rlblock_left
{display:none !important;}</style>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/lettre/sending-messages/stub/">
<body class="" data-url="/sending-messages/stub/">
<nav id="sidebar" class="">
<nav id="sidebar">
<div id="header-wrapper">
<div id="header">
<a href="https://lettre.github.io/lettre//getting-started/intro/"><img src="https://lettre.github.io/lettre//images/logo50.png" /></a>
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search">
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/lunr.min.js"></script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/horsey.js"></script>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "https:\/\/lettre.github.io\/lettre\/";
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="https://lettre.github.io/lettre//js/search.js"></script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
</div>
<div class="highlightable">
<div class="highlightable">
<ul class="topics">
@@ -61,60 +72,47 @@
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<li class="dd-item " data-nav-id="/lettre/getting-started/">
<a href="/lettre/getting-started/">
<span>
<b>1. </b>
Getting started
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/getting-started/intro/">
<a href="/lettre/getting-started/intro/">
<span>Introduction </i></span>
</a>
</li>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
</li>
@@ -125,86 +123,184 @@
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
<li class="dd-item " data-nav-id="/lettre/creating-messages/">
<a href="/lettre/creating-messages/">
<span>
</a>
<b>2. </b>
Creating messages
</span>
</a>
</li>
<li class="dd-item parent" data-nav-id="/lettre/sending-messages/">
<a href="/lettre/sending-messages/">
<span>
<b>3. </b>
Sending messages
</span>
</a>
<ul>
<li class="dd-item " data-nav-id="/lettre/sending-messages/intro/">
<a href="/lettre/sending-messages/intro/">
<span>Introduction </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/smtp/">
<a href="/lettre/sending-messages/smtp/">
<span>SMTP transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/sendmail/">
<a href="/lettre/sending-messages/sendmail/">
<span>Sendmail transport </i></span>
</a>
</li>
<li class="dd-item " data-nav-id="/lettre/sending-messages/file/">
<a href="/lettre/sending-messages/file/">
<span>File transport </i></span>
</a>
</li>
<li class="dd-item active" data-nav-id="/lettre/sending-messages/stub/">
<a href="/lettre/sending-messages/stub/">
<span>Stub transport </i></span>
</a>
</li>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
parent
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item active">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<hr>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
@@ -213,128 +309,110 @@
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="padding highlightable">
<div id="top-bar">
<div class="sticky-spacer">
<div id="top-bar">
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/stub.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
<a href='/'>Lettre site</a> > <a href='/sending-messages/'>Sending messages</a> > Stub transport
<div id="top-github-link">
<a class="github-link" href="https://github.com/lettre/lettre/edit/master/website/content/sending-messages/stub.md" target="blank">
<i class="fa fa-code-fork"></i>
Edit this page
</a>
</div>
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
</div>
<span id="toc-menu"><a href=""><i class="fa fa-list-alt"></i></a></span>
<a href="/lettre/sending-messages/" itemprop="url"><span itemprop="title">Sending messages</span></a> <i class="fa fa-angle-right"></i>
<span itemprop="title"> Stub transport</span>
</div>
<div class="progress">
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Stub transport</h1>
<div id="body-inner">
<h1>Stub transport</h1>
<p>The stub transport only logs message envelope and drops the content. It can be useful for
testing purposes.</p>
use lettre::stub::StubEmailTransport;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">crate</span> lettre;
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
<span style="color:#66d9ef">use</span> lettre::stub::StubEmailTransport;
<span style="color:#66d9ef">use</span> lettre::{SimpleSendableEmail, EmailTransport};
let mut sender = StubEmailTransport::new_positive();
let result = sender.send(&email);
assert!(result.is_ok());
<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
<span style="color:#66d9ef">let</span> email <span style="color:#f92672">=</span> SimpleSendableEmail::new(
<span style="color:#e6db74">&#34;user@localhost&#34;</span>.to_string(),
<span style="color:#f92672">&amp;</span>[<span style="color:#e6db74">&#34;root@localhost&#34;</span>.to_string()],
<span style="color:#e6db74">&#34;message_id&#34;</span>.to_string(),
<span style="color:#e6db74">&#34;Hello world&#34;</span>.to_string(),
).unwrap();
<span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> sender <span style="color:#f92672">=</span> StubEmailTransport::new_positive();
<span style="color:#66d9ef">let</span> result <span style="color:#f92672">=</span> sender.send(<span style="color:#f92672">&amp;</span>email);
assert<span style="color:#f92672">!</span>(result.is_ok());
}</code></pre></div>
<p>Will log (when using a logger like <code>env_logger</code>):</p>
b7c211bc-9811-45ce-8cd9-68eab575d695: from=<user@localhost> to=<root@localhost>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">b7c211bc-9811-45ce-8cd9-68eab575d695: from=&lt;user@localhost&gt; to=&lt;root@localhost&gt;</code></pre></div>
<footer class=" footline" >
</footer>
</div>
</div>
</div>
<div id="navigation">
@@ -359,7 +437,6 @@ b7c211bc-9811-45ce-8cd9-68eab575d695: from=<user@localhost> to=<root@localhost>
<a class="nav nav-prev" href="/lettre/sending-messages/file/"> <i class="fa fa-chevron-left"></i></a>
@@ -370,23 +447,197 @@ b7c211bc-9811-45ce-8cd9-68eab575d695: from=<user@localhost> to=<root@localhost>
<a class="nav nav-prev" href="/sending-messages/file/" title="File transport"> <i class="fa fa-chevron-left"></i></a>
<a class="nav nav-next" href="/sending-messages/intro/" title="Introduction" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="https://lettre.github.io/lettre//js/clipboard.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.min.js"></script>
<script src="https://lettre.github.io/lettre//js/perfect-scrollbar.jquery.min.js"></script>
<script src="https://lettre.github.io/lettre//js/jquery.sticky-kit.min.js"></script>
<script src="https://lettre.github.io/lettre//js/featherlight.min.js"></script>
<script src="https://lettre.github.io/lettre//js/html5shiv-printshiv.min.js"></script>
<script src="https://lettre.github.io/lettre//js/highlight.pack.js"></script>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://lettre.github.io/lettre//js/modernizr.custom.71422.js"></script>
<script src="https://lettre.github.io/lettre//js/learn.js"></script>
<script src="https://lettre.github.io/lettre//js/hugo-learn.js"></script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>

View File

@@ -1,64 +1,70 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://lettre.github.io/lettre/getting-started/intro/</loc>
<loc>http://docs.lettre.at/getting-started/intro/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/sending-messages/intro/</loc>
<loc>http://docs.lettre.at/sending-messages/intro/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/getting-started/</loc>
<loc>http://docs.lettre.at/getting-started/</loc>
<lastmod>2017-05-21T23:46:01+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/sending-messages/smtp/</loc>
<loc>http://docs.lettre.at/sending-messages/smtp/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/creating-messages/</loc>
<loc>http://docs.lettre.at/creating-messages/</loc>
<lastmod>2017-05-21T23:46:01+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/sending-messages/sendmail/</loc>
<loc>http://docs.lettre.at/sending-messages/sendmail/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/sending-messages/</loc>
<loc>http://docs.lettre.at/sending-messages/</loc>
<lastmod>2017-05-21T23:46:01+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/sending-messages/file/</loc>
<loc>http://docs.lettre.at/creating-messages/email/</loc>
<lastmod>2018-01-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>http://docs.lettre.at/sending-messages/file/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/sending-messages/stub/</loc>
<loc>http://docs.lettre.at/sending-messages/stub/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
</url>
<url>
<loc>https://lettre.github.io/lettre/categories/</loc>
<loc>http://docs.lettre.at/categories/</loc>
<priority>0</priority>
</url>
<url>
<loc>https://lettre.github.io/lettre/</loc>
<loc>http://docs.lettre.at/</loc>
<lastmod>2017-05-21T23:46:17+02:00</lastmod>
<priority>0</priority>
</url>
<url>
<loc>https://lettre.github.io/lettre/tags/</loc>
<loc>http://docs.lettre.at/tags/</loc>
<priority>0</priority>
</url>

593
docs/tags/index.html Normal file
View File

@@ -0,0 +1,593 @@
<!DOCTYPE html>
<html lang="en" class="js csstransforms3d">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="generator" content="Hugo 0.37.1" />
<meta name="description" content="Documentation for the Lettre mailer in Rust">
<meta name="author" content="Alexis Mousset">
<link rel="shortcut icon" href="http://docs.lettre.at//images/favicon.png" type="image/x-icon" />
<title>Tags :: Lettre site</title>
<link href="/css/nucleus.css?1522603726" rel="stylesheet">
<link href="/css/font-awesome.min.css?1522603726" rel="stylesheet">
<link href="/css/hybrid.css?1522603726" rel="stylesheet">
<link href="/css/featherlight.min.css?1522603726" rel="stylesheet">
<link href="/css/perfect-scrollbar.min.css?1522603726" rel="stylesheet">
<link href="/css/auto-complete.css?1522603726" rel="stylesheet">
<link href="/css/theme.css?1522603726" rel="stylesheet">
<link href="/css/hugo-theme.css?1522603726" rel="stylesheet">
<script src="/js/jquery-2.x.min.js?1522603726"></script>
<style type="text/css">
:root #header + #content > #left > #rlblock_left{
display:none !important;
}
</style>
</head>
<body class="" data-url="/tags/">
<nav id="sidebar" class="">
<div id="header-wrapper">
<div id="header">
<a href="http://docs.lettre.at//getting-started/intro/"><img src="http://docs.lettre.at//images/logo50.png" /></a>
</div>
<div class="searchbox">
<label for="search-by"><i class="fa fa-search"></i></label>
<input data-search-input id="search-by" type="text" placeholder="Search...">
<span data-search-clear=""><i class="fa fa-close"></i></span>
</div>
<script type="text/javascript" src="/js/lunr.min.js?1522603726"></script>
<script type="text/javascript" src="/js/auto-complete.js?1522603726"></script>
<script type="text/javascript">
var baseurl = "http:\/\/docs.lettre.at\/";
</script>
<script type="text/javascript" src="/js/search.js?1522603726"></script>
</div>
<div class="highlightable">
<ul class="topics">
<li data-nav-id="/getting-started/" title="Getting started" class="dd-item
">
<a href="/getting-started/">
Getting started
</a>
<ul>
<li data-nav-id="/getting-started/intro/" title="Introduction" class="dd-item ">
<a href="/getting-started/intro/">
Introduction
</a>
</li>
</ul>
</li>
<li data-nav-id="/creating-messages/" title="Creating messages" class="dd-item
">
<a href="/creating-messages/">
Creating messages
</a>
<ul>
<li data-nav-id="/creating-messages/email/" title="Email creation" class="dd-item ">
<a href="/creating-messages/email/">
Email creation
</a>
</li>
</ul>
</li>
<li data-nav-id="/sending-messages/" title="Sending messages" class="dd-item
">
<a href="/sending-messages/">
Sending messages
</a>
<ul>
<li data-nav-id="/sending-messages/intro/" title="Introduction" class="dd-item ">
<a href="/sending-messages/intro/">
Introduction
</a>
</li>
<li data-nav-id="/sending-messages/smtp/" title="SMTP transport" class="dd-item ">
<a href="/sending-messages/smtp/">
SMTP transport
</a>
</li>
<li data-nav-id="/sending-messages/sendmail/" title="Sendmail transport" class="dd-item ">
<a href="/sending-messages/sendmail/">
Sendmail transport
</a>
</li>
<li data-nav-id="/sending-messages/file/" title="File transport" class="dd-item ">
<a href="/sending-messages/file/">
File transport
</a>
</li>
<li data-nav-id="/sending-messages/stub/" title="Stub transport" class="dd-item ">
<a href="/sending-messages/stub/">
Stub transport
</a>
</li>
</ul>
</li>
</ul>
<section id="footer">
<p>Built with <a href="https://github.com/matcornic/hugo-theme-learn"><i class="fa fa-heart"></i></a> from <a href="http://getgrav.org">Grav</a> and <a href="http://gohugo.io/">Hugo</a></p>
</section>
</div>
</nav>
<section id="body">
<div id="overlay"></div>
<div class="padding highlightable sticky-parent">
<div class="sticky-spacer">
<div id="top-bar">
<div id="breadcrumbs" itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb">
<span id="sidebar-toggle-span">
<a href="#" id="sidebar-toggle" data-sidebar-toggle="">
<i class="fa fa-bars"></i>
</a>
</span>
<span id="toc-menu"><i class="fa fa-list-alt"></i></span>
<span class="links">
Tags
</span>
</div>
<div class="progress">
<div class="wrapper">
</div>
</div>
</div>
</div>
<div id="body-inner">
<h1>Tags</h1>
<footer class=" footline" >
</footer>
</div>
</div>
<div id="navigation">
<a class="nav nav-next" href="/getting-started/" title="Getting started" style="margin-right: 0px;"><i class="fa fa-chevron-right"></i></a>
</div>
</section>
<div style="left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;">
<div style="border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;"></div>
</div>
<script src="/js/clipboard.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.min.js?1522603726"></script>
<script src="/js/perfect-scrollbar.jquery.min.js?1522603726"></script>
<script src="/js/jquery.sticky-kit.min.js?1522603726"></script>
<script src="/js/featherlight.min.js?1522603726"></script>
<script src="/js/html5shiv-printshiv.min.js?1522603726"></script>
<script src="/js/highlight.pack.js?1522603726"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="/js/modernizr.custom.71422.js?1522603726"></script>
<script src="/js/learn.js?1522603726"></script>
<script src="/js/hugo-learn.js?1522603726"></script>
<link href="/mermaid/mermaid.css?1522603726" type="text/css" rel="stylesheet" />
<script src="/mermaid/mermaid.js?1522603726"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -2,12 +2,12 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Tags on Lettre site</title>
<link>https://lettre.github.io/lettre/tags/</link>
<link>http://docs.lettre.at/tags/</link>
<description>Recent content in Tags on Lettre site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://lettre.github.io/lettre/tags/index.xml" rel="self" type="application/rss+xml" />
<atom:link href="http://docs.lettre.at/tags/index.xml" rel="self" type="application/rss+xml" />
</channel>

View File

@@ -1,37 +0,0 @@
### v0.7.0 (2017-10-08)
#### Features
* **all**
* Split into the *lettre* and *lettre_email* crates
* A lot of small improvements
* **smtp transport**
* Use *tls-native* instead of *openssl*
* Allow validating server certificate
### v0.6.2 (2017-02-18)
#### Features
* **all**
* 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
* **tests**
* #93: Force building tests before coverage computing
### v0.6.0 (2016-05-05)
Nothing.

1
lettre/CHANGELOG.md Symbolic link
View File

@@ -0,0 +1 @@
../CHANGELOG.md

View File

@@ -1,7 +1,7 @@
[package]
name = "lettre"
version = "0.7.0"
version = "0.8.1" # remember to update html_root_url
description = "Email client"
readme = "README.md"
documentation = "https://docs.rs/lettre/"
@@ -15,18 +15,21 @@ keywords = ["email", "smtp", "mailer"]
travis-ci = { repository = "lettre/lettre" }
[dependencies]
log = "^0.3"
log = "^0.4"
nom = { version = "^3.2", optional = true }
bufstream = { version = "^0.1", optional = true }
native-tls = { version = "^0.1", optional = true }
base64 = { version = "^0.7", optional = true }
hex = { version = "^0.2", optional = true }
base64 = { version = "^0.9", optional = true }
hex = { version = "^0.3", optional = true }
hostname = { version = "^0.1", optional = true }
rust-crypto = { version = "^0.2", optional = true }
serde = { version = "^1.0", optional = true }
serde_json = { version = "^1.0", optional = true }
serde_derive = { version = "^1.0", optional = true }
[dev-dependencies]
env_logger = "^0.4"
env_logger = "^0.5"
glob = "0.2"
[features]
default = ["file-transport", "crammd5-auth", "smtp-transport", "sendmail-transport"]
@@ -34,7 +37,7 @@ unstable = []
serde-impls = ["serde", "serde_derive"]
file-transport = ["serde-impls", "serde_json"]
crammd5-auth = ["rust-crypto", "hex"]
smtp-transport = ["bufstream", "native-tls", "base64"]
smtp-transport = ["bufstream", "native-tls", "base64", "nom", "hostname"]
sendmail-transport = []
[[example]]

View File

@@ -1,17 +1,17 @@
extern crate lettre;
extern crate env_logger;
extern crate lettre;
use lettre::{EmailAddress, EmailTransport, SimpleSendableEmail, SmtpTransport};
use lettre::{EmailTransport, SimpleSendableEmail, SmtpTransport};
fn main() {
env_logger::init().unwrap();
env_logger::init();
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"file_id".to_string(),
"user@localhost".to_string(),
&["root@localhost".to_string()],
"my-message-id".to_string(),
"Hello ß☺ example".to_string(),
);
).unwrap();
// Open a local connection on port 25
let mut mailer = SmtpTransport::builder_unencrypted_localhost()

View File

@@ -1 +0,0 @@
../rustfmt.toml

View File

@@ -34,8 +34,8 @@ impl StdError for Error {
fn cause(&self) -> Option<&StdError> {
match *self {
Io(ref err) => Some(&*err as &StdError),
JsonSerialization(ref err) => Some(&*err as &StdError),
Io(ref err) => Some(&*err),
JsonSerialization(ref err) => Some(&*err),
_ => None,
}
}

View File

@@ -2,36 +2,6 @@
//! `message_id.txt`.
//! It can be useful for testing purposes, or if you want to keep track of sent messages.
//!
//! ```rust
//! use std::env::temp_dir;
//!
//! use lettre::file::FileEmailTransport;
//! use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
//!
//! // Write to the local temp directory
//! let mut sender = FileEmailTransport::new(temp_dir());
//! let email = SimpleSendableEmail::new(
//! EmailAddress::new("user@localhost".to_string()),
//! vec![EmailAddress::new("root@localhost".to_string())],
//! "message_id".to_string(),
//! "Hello world".to_string(),
//! );
//!
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! ```
//! Example result in `/tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.txt`:
//!
//! ```text
//! b7c211bc-9811-45ce-8cd9-68eab575d695: from=<user@localhost> to=<root@localhost>
//! To: <root@localhost>
//! From: <user@localhost>
//! Subject: Hello
//! Date: Sat, 31 Oct 2015 13:42:19 +0100
//! Message-ID: <b7c211bc-9811-45ce-8cd9-68eab575d695.lettre@localhost>
//!
//! Hello World!
//! ```
use EmailTransport;
use SendableEmail;
@@ -47,6 +17,7 @@ pub mod error;
/// Writes the content and the envelope information to a file
#[derive(Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct FileEmailTransport {
path: PathBuf,
}
@@ -70,16 +41,13 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, FileResult> for FileEmailTransport
let mut message_content = String::new();
let _ = email.message().read_to_string(&mut message_content);
let simple_email = SimpleSendableEmail::new(
email.from().clone(),
email.to().clone(),
email.message_id().clone(),
let simple_email = SimpleSendableEmail::new_with_envelope(
email.envelope().clone(),
email.message_id().to_string(),
message_content,
);
f.write_all(
serde_json::to_string(&simple_email)?.as_bytes(),
)?;
f.write_all(serde_json::to_string(&simple_email)?.as_bytes())?;
Ok(())
}

View File

@@ -4,25 +4,32 @@
//! emails have to implement `SendableEmail`.
//!
#![deny(missing_docs, unsafe_code, unstable_features, warnings)]
#[macro_use]
extern crate log;
#[cfg(feature = "crammd5-auth")]
extern crate hex;
#[cfg(feature = "crammd5-auth")]
extern crate crypto;
#![doc(html_root_url = "https://docs.rs/lettre/0.8.1")]
#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
unused_qualifications)]
#[cfg(feature = "smtp-transport")]
extern crate base64;
#[cfg(feature = "smtp-transport")]
extern crate bufstream;
#[cfg(feature = "crammd5-auth")]
extern crate crypto;
#[cfg(feature = "crammd5-auth")]
extern crate hex;
#[cfg(feature = "smtp-transport")]
extern crate hostname;
#[macro_use]
extern crate log;
#[cfg(feature = "smtp-transport")]
extern crate native_tls;
#[cfg(feature = "file-transport")]
extern crate serde_json;
#[cfg(feature = "smtp-transport")]
#[macro_use]
extern crate nom;
#[cfg(feature = "serde-impls")]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "file-transport")]
extern crate serde_json;
#[cfg(feature = "smtp-transport")]
pub mod smtp;
@@ -37,16 +44,68 @@ pub use file::FileEmailTransport;
#[cfg(feature = "sendmail-transport")]
pub use sendmail::SendmailTransport;
#[cfg(feature = "smtp-transport")]
pub use smtp::{SmtpTransport, ClientSecurity};
pub use smtp::{ClientSecurity, SmtpTransport};
#[cfg(feature = "smtp-transport")]
pub use smtp::client::net::ClientTlsParameters;
use std::fmt::{self, Display, Formatter};
use std::io::Read;
use std::error::Error as StdError;
use std::str::FromStr;
/// Error type for email content
#[derive(Debug, Clone, Copy)]
pub enum Error {
/// Missing from in envelope
MissingFrom,
/// Missing to in envelope
MissingTo,
/// Invalid email
InvalidEmailAddress,
}
impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::MissingFrom => "missing source address, invalid envelope",
Error::MissingTo => "missing destination address, invalid envelope",
Error::InvalidEmailAddress => "invalid email address",
}
}
fn cause(&self) -> Option<&StdError> {
None
}
}
impl Display for Error {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
fmt.write_str(self.description())
}
}
/// Email result type
pub type EmailResult<T> = Result<T, Error>;
/// Email address
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct EmailAddress(pub String);
pub struct EmailAddress(String);
impl EmailAddress {
/// Creates a new `EmailAddress`. For now it makes no validation.
pub fn new(address: String) -> EmailResult<EmailAddress> {
// TODO make some basic sanity checks
Ok(EmailAddress(address))
}
}
impl FromStr for EmailAddress {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
EmailAddress::new(s.to_string())
}
}
impl Display for EmailAddress {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
@@ -54,19 +113,98 @@ impl Display for EmailAddress {
}
}
impl EmailAddress {
/// Creates a new email address
pub fn new(address: String) -> EmailAddress {
EmailAddress(address)
/// Simple email envelope representation
///
/// We only accept mailboxes, and do not support source routes (as per RFC).
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct Envelope {
/// The envelope recipients' addresses
///
/// This can not be empty.
forward_path: Vec<EmailAddress>,
/// The envelope sender address
reverse_path: Option<EmailAddress>,
}
impl Envelope {
/// Creates a new envelope, which may fail if `to` is empty.
pub fn new(from: Option<EmailAddress>, to: Vec<EmailAddress>) -> EmailResult<Envelope> {
if to.is_empty() {
return Err(Error::MissingTo);
}
Ok(Envelope {
forward_path: to,
reverse_path: from,
})
}
/// Destination addresses of the envelope
pub fn to(&self) -> &[EmailAddress] {
self.forward_path.as_slice()
}
/// Source address of the envelope
pub fn from(&self) -> Option<&EmailAddress> {
self.reverse_path.as_ref()
}
/// Creates a new builder
pub fn builder() -> EnvelopeBuilder {
EnvelopeBuilder::new()
}
}
/// Simple email envelope representation
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct EnvelopeBuilder {
/// The envelope recipients' addresses
to: Vec<EmailAddress>,
/// The envelope sender address
from: Option<EmailAddress>,
}
impl EnvelopeBuilder {
/// Constructs an envelope with no recipients and an empty sender
pub fn new() -> Self {
EnvelopeBuilder {
to: vec![],
from: None,
}
}
/// Adds a recipient
pub fn to<S: Into<EmailAddress>>(mut self, address: S) -> Self {
self.add_to(address);
self
}
/// Adds a recipient
pub fn add_to<S: Into<EmailAddress>>(&mut self, address: S) {
self.to.push(address.into());
}
/// Sets the sender
pub fn from<S: Into<EmailAddress>>(mut self, address: S) -> Self {
self.set_from(address);
self
}
/// Sets the sender
pub fn set_from<S: Into<EmailAddress>>(&mut self, address: S) {
self.from = Some(address.into());
}
/// Build the envelope
pub fn build(self) -> EmailResult<Envelope> {
Envelope::new(self.from, self.to)
}
}
/// Email sendable by an SMTP client
pub trait SendableEmail<'a, T: Read + 'a> {
/// To
fn to(&self) -> Vec<EmailAddress>;
/// From
fn from(&self) -> EmailAddress;
/// Envelope
fn envelope(&self) -> Envelope;
/// Message ID, used for logging
fn message_id(&self) -> String;
/// Message content
@@ -83,10 +221,8 @@ pub trait EmailTransport<'a, U: Read + 'a, V> {
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct SimpleSendableEmail {
/// To
to: Vec<EmailAddress>,
/// From
from: EmailAddress,
/// Envelope
envelope: Envelope,
/// Message ID
message_id: String,
/// Message content
@@ -96,27 +232,39 @@ pub struct SimpleSendableEmail {
impl SimpleSendableEmail {
/// Returns a new email
pub fn new(
from_address: EmailAddress,
to_addresses: Vec<EmailAddress>,
from_address: String,
to_addresses: &[String],
message_id: String,
message: String,
) -> EmailResult<SimpleSendableEmail> {
let to: Result<Vec<EmailAddress>, Error> = to_addresses
.iter()
.map(|x| EmailAddress::new(x.clone()))
.collect();
Ok(SimpleSendableEmail::new_with_envelope(
Envelope::new(Some(EmailAddress::new(from_address)?), to?)?,
message_id,
message,
))
}
/// Returns a new email from a valid envelope
pub fn new_with_envelope(
envelope: Envelope,
message_id: String,
message: String,
) -> SimpleSendableEmail {
SimpleSendableEmail {
from: from_address,
to: to_addresses,
message_id: message_id,
envelope,
message_id,
message: message.into_bytes(),
}
}
}
impl<'a> SendableEmail<'a, &'a [u8]> for SimpleSendableEmail {
fn to(&self) -> Vec<EmailAddress> {
self.to.clone()
}
fn from(&self) -> EmailAddress {
self.from.clone()
fn envelope(&self) -> Envelope {
self.envelope.clone()
}
fn message_id(&self) -> String {

View File

@@ -30,7 +30,7 @@ impl StdError for Error {
fn cause(&self) -> Option<&StdError> {
match *self {
Io(ref err) => Some(&*err as &StdError),
Io(ref err) => Some(&*err),
_ => None,
}
}

View File

@@ -1,20 +1,5 @@
//! The sendmail transport sends the email using the local sendmail command.
//!
//! ```rust
//! use lettre::sendmail::SendmailTransport;
//! use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
//!
//! let email = SimpleSendableEmail::new(
//! EmailAddress::new("user@localhost".to_string()),
//! vec![EmailAddress::new("root@localhost".to_string())],
//! "message_id".to_string(),
//! "Hello world".to_string(),
//! );
//!
//! let mut sender = SendmailTransport::new();
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! ```
use {EmailTransport, SendableEmail};
use sendmail::error::SendmailResult;
@@ -26,6 +11,7 @@ pub mod error;
/// Sends an email using the `sendmail` command
#[derive(Debug, Default)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct SendmailTransport {
command: String,
}
@@ -33,28 +19,35 @@ pub struct SendmailTransport {
impl SendmailTransport {
/// Creates a new transport with the default `/usr/sbin/sendmail` command
pub fn new() -> SendmailTransport {
SendmailTransport { command: "/usr/sbin/sendmail".to_string() }
SendmailTransport {
command: "/usr/sbin/sendmail".to_string(),
}
}
/// Creates a new transport to the given sendmail command
pub fn new_with_command<S: Into<String>>(command: S) -> SendmailTransport {
SendmailTransport { command: command.into() }
SendmailTransport {
command: command.into(),
}
}
}
impl<'a, T: Read + 'a> EmailTransport<'a, T, SendmailResult> for SendmailTransport {
fn send<U: SendableEmail<'a, T> + 'a>(&mut self, email: &'a U) -> SendmailResult {
let envelope = email.envelope();
// Spawn the sendmail command
let to_addresses: Vec<String> = email.to().iter().map(|x| x.to_string()).collect();
let to_addresses: Vec<String> = envelope.to().iter().map(|x| x.to_string()).collect();
let mut process = Command::new(&self.command)
.args(
&[
"-i",
"-f",
&email.from().to_string(),
&to_addresses.join(" "),
],
)
.args(&[
"-i",
"-f",
&match envelope.from() {
Some(address) => address.to_string(),
None => "\"\"".to_string(),
},
&to_addresses.join(" "),
])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
@@ -62,9 +55,12 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SendmailResult> for SendmailTranspo
let mut message_content = String::new();
let _ = email.message().read_to_string(&mut message_content);
match process.stdin.as_mut().unwrap().write_all(
message_content.as_bytes(),
) {
match process
.stdin
.as_mut()
.unwrap()
.write_all(message_content.as_bytes())
{
Ok(_) => (),
Err(error) => return Err(From::from(error)),
}

View File

@@ -7,30 +7,28 @@ use crypto::mac::Mac;
#[cfg(feature = "crammd5-auth")]
use crypto::md5::Md5;
#[cfg(feature = "crammd5-auth")]
use hex::ToHex;
use hex;
use smtp::NUL;
use smtp::error::Error;
use std::fmt::{self, Display, Formatter};
/// Accepted authentication mecanisms on an encrypted connection
/// Accepted authentication mechanisms on an encrypted connection
/// Trying LOGIN last as it is deprecated.
#[cfg(feature = "crammd5-auth")]
pub const DEFAULT_ENCRYPTED_MECHANISMS: &'static [Mechanism] =
pub const DEFAULT_ENCRYPTED_MECHANISMS: &[Mechanism] =
&[Mechanism::Plain, Mechanism::CramMd5, Mechanism::Login];
/// Accepted authentication mecanisms on an encrypted connection
/// Accepted authentication mechanisms on an encrypted connection
/// Trying LOGIN last as it is deprecated.
#[cfg(not(feature = "crammd5-auth"))]
pub const DEFAULT_ENCRYPTED_MECHANISMS: &'static [Mechanism] =
&[Mechanism::Plain, Mechanism::Login];
pub const DEFAULT_ENCRYPTED_MECHANISMS: &[Mechanism] = &[Mechanism::Plain, Mechanism::Login];
/// Accepted authentication mecanisms on an unencrypted connection
/// Accepted authentication mechanisms on an unencrypted connection
#[cfg(feature = "crammd5-auth")]
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &'static [Mechanism] = &[Mechanism::CramMd5];
/// Accepted authentication mecanisms on an unencrypted connection
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &[Mechanism] = &[Mechanism::CramMd5];
/// Accepted authentication mechanisms on an unencrypted connection
/// When CRAMMD5 support is not enabled, no mechanisms are allowed.
#[cfg(not(feature = "crammd5-auth"))]
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &'static [Mechanism] = &[];
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &[Mechanism] = &[];
/// Convertable to user credentials
pub trait IntoCredentials {
@@ -53,6 +51,7 @@ impl<S: Into<String>, T: Into<String>> IntoCredentials for (S, T) {
/// Contains user credentials
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct Credentials {
username: String,
password: String,
@@ -61,15 +60,13 @@ pub struct Credentials {
impl Credentials {
/// Create a `Credentials` struct from username and password
pub fn new(username: String, password: String) -> Credentials {
Credentials {
username: username,
password: password,
}
Credentials { username, password }
}
}
/// Represents authentication mechanisms
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum Mechanism {
/// PLAIN authentication mechanism
/// RFC 4616: https://tools.ietf.org/html/rfc4616
@@ -119,18 +116,13 @@ impl Mechanism {
challenge: Option<&str>,
) -> Result<String, Error> {
match *self {
Mechanism::Plain => {
match challenge {
Some(_) => Err(Error::Client("This mechanism does not expect a challenge")),
None => Ok(format!(
"{}{}{}{}",
NUL,
credentials.username,
NUL,
credentials.password
)),
}
}
Mechanism::Plain => match challenge {
Some(_) => Err(Error::Client("This mechanism does not expect a challenge")),
None => Ok(format!(
"{}{}{}{}",
NUL, credentials.username, NUL, credentials.password
)),
},
Mechanism::Login => {
let decoded_challenge = match challenge {
Some(challenge) => challenge,
@@ -160,7 +152,7 @@ impl Mechanism {
Ok(format!(
"{} {}",
credentials.username,
hmac.result().code().to_hex()
hex::encode(hmac.result().code())
))
}
}
@@ -212,7 +204,7 @@ mod test {
mechanism
.response(
&credentials,
Some("PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg=="),
Some("PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==")
)
.unwrap(),
"alice a540ebe4ef2304070bbc3c456c1f64c0"

View File

@@ -41,11 +41,11 @@ impl MockStream {
vec
}
pub fn next_vec(&mut self, vec: Vec<u8>) {
pub fn next_vec(&mut self, vec: &[u8]) {
let mut cursor = self.reader.lock().unwrap();
cursor.set_position(0);
cursor.get_mut().clear();
cursor.get_mut().extend_from_slice(vec.as_slice());
cursor.get_mut().extend_from_slice(vec);
}
pub fn swap(&mut self) {

View File

@@ -1,12 +1,13 @@
//! SMTP client
use bufstream::BufStream;
use nom::ErrorKind as NomErrorKind;
use smtp::{CRLF, MESSAGE_ENDING};
use smtp::authentication::{Credentials, Mechanism};
use smtp::client::net::{ClientTlsParameters, Connector, NetworkStream, Timeout};
use smtp::commands::*;
use smtp::error::{Error, SmtpResult};
use smtp::response::ResponseParser;
use smtp::response::Response;
use std::fmt::{Debug, Display};
use std::io::{self, BufRead, BufReader, Read, Write};
use std::net::ToSocketAddrs;
@@ -17,7 +18,8 @@ pub mod net;
pub mod mock;
/// The codec used for transparency
#[derive(Default, Debug)]
#[derive(Default, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct ClientCodec {
escape_count: u8,
}
@@ -60,9 +62,9 @@ impl ClientCodec {
start = idx;
}
}
Ok(buf.write_all(&frame[start..])?)
buf.write_all(&frame[start..])?;
Ok(())
}
}
}
}
@@ -73,12 +75,6 @@ fn escape_crlf(string: &str) -> String {
string.replace(CRLF, "<CRLF>")
}
/// Returns the string removing all the CRLF
/// Used for debug displays
fn remove_crlf(string: &str) -> String {
string.replace(CRLF, "")
}
/// Structure that implements the SMTP client
#[derive(Debug, Default)]
pub struct Client<S: Write + Read = NetworkStream> {
@@ -106,7 +102,7 @@ impl<S: Write + Read> Client<S> {
impl<S: Connector + Write + Read + Timeout + Debug> Client<S> {
/// Closes the SMTP transaction if possible
pub fn close(&mut self) {
let _ = self.smtp_command(QuitCommand);
let _ = self.command(QuitCommand);
self.stream = None;
}
@@ -166,29 +162,27 @@ impl<S: Connector + Write + Read + Timeout + Debug> Client<S> {
// Try to connect
self.set_stream(Connector::connect(&server_addr, tls_parameters)?);
self.get_reply()
self.read_response()
}
/// Checks if the server is connected using the NOOP SMTP command
#[cfg_attr(feature = "cargo-clippy", allow(wrong_self_convention))]
pub fn is_connected(&mut self) -> bool {
self.smtp_command(NoopCommand).is_ok()
self.command(NoopCommand).is_ok()
}
/// Sends an AUTH command with the given mechanism, and handles challenge if needed
pub fn auth(&mut self, mechanism: Mechanism, credentials: &Credentials) -> SmtpResult {
// TODO
let mut challenges = 10;
let mut response = self.smtp_command(
AuthCommand::new(mechanism, credentials.clone(), None)?,
)?;
let mut response = self.command(AuthCommand::new(mechanism, credentials.clone(), None)?)?;
while challenges > 0 && response.has_code(334) {
challenges -= 1;
response = self.smtp_command(AuthCommand::new_from_response(
response = self.command(AuthCommand::new_from_response(
mechanism,
credentials.clone(),
response,
&response,
)?)?;
}
@@ -209,8 +203,11 @@ impl<S: Connector + Write + Read + Timeout + Debug> Client<S> {
out_buf.clear();
let consumed = match message_reader.fill_buf() {
Ok(bytes) => { codec.encode(bytes, &mut out_buf)?; bytes.len() },
Err(ref err) => panic!("Failed with: {}", err)
Ok(bytes) => {
codec.encode(bytes, &mut out_buf)?;
bytes.len()
}
Err(ref err) => panic!("Failed with: {}", err),
};
message_reader.consume(consumed);
@@ -218,21 +215,21 @@ impl<S: Connector + Write + Read + Timeout + Debug> Client<S> {
break;
}
self.write_server(out_buf.as_slice())?;
self.write(out_buf.as_slice())?;
}
self.write_server(MESSAGE_ENDING.as_bytes())?;
self.get_reply()
self.write(MESSAGE_ENDING.as_bytes())?;
self.read_response()
}
/// Sends an SMTP command
pub fn smtp_command<C: Display>(&mut self, command: C) -> SmtpResult {
self.write_server(command.to_string().as_bytes())?;
self.get_reply()
pub fn command<C: Display>(&mut self, command: C) -> SmtpResult {
self.write(command.to_string().as_bytes())?;
self.read_response()
}
/// Writes a string to the server
fn write_server(&mut self, string: &[u8]) -> Result<(), Error> {
fn write(&mut self, string: &[u8]) -> Result<(), Error> {
if self.stream.is_none() {
return Err(From::from("Connection closed"));
}
@@ -248,33 +245,34 @@ impl<S: Connector + Write + Read + Timeout + Debug> Client<S> {
}
/// Gets the SMTP response
fn get_reply(&mut self) -> SmtpResult {
fn read_response(&mut self) -> SmtpResult {
let mut raw_response = String::new();
let mut response = raw_response.parse::<Response>();
let mut parser = ResponseParser::default();
let mut line = String::new();
self.stream.as_mut().unwrap().read_line(&mut line)?;
debug!("Read: {}", escape_crlf(line.as_ref()));
while parser.read_line(remove_crlf(line.as_ref()).as_ref())? {
line.clear();
self.stream.as_mut().unwrap().read_line(&mut line)?;
while response.is_err() {
if response.as_ref().err().unwrap() != &NomErrorKind::Complete {
break;
}
// TODO read more than one line
self.stream.as_mut().unwrap().read_line(&mut raw_response)?;
response = raw_response.parse::<Response>();
}
let response = parser.response()?;
debug!("Read: {}", escape_crlf(raw_response.as_ref()));
if response.is_positive() {
Ok(response)
let final_response = response?;
if final_response.is_positive() {
Ok(final_response)
} else {
Err(From::from(response))
Err(From::from(final_response))
}
}
}
#[cfg(test)]
mod test {
use super::{ClientCodec, escape_crlf, remove_crlf};
use super::{escape_crlf, ClientCodec};
#[test]
fn test_codec() {
@@ -296,16 +294,6 @@ mod test {
);
}
#[test]
fn test_remove_crlf() {
assert_eq!(remove_crlf("\r\n"), "");
assert_eq!(remove_crlf("EHLO my_name\r\n"), "EHLO my_name");
assert_eq!(
remove_crlf("EHLO my_name\r\nSIZE 42\r\n"),
"EHLO my_nameSIZE 42"
);
}
#[test]
fn test_escape_crlf() {
assert_eq!(escape_crlf("\r\n"), "<CRLF>");

View File

@@ -1,6 +1,6 @@
//! A trait to represent a stream
use native_tls::{TlsConnector, TlsStream, Protocol};
use native_tls::{Protocol, TlsConnector, TlsStream};
use smtp::client::mock::MockStream;
use std::io::{self, ErrorKind, Read, Write};
use std::net::{Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, TcpStream};
@@ -8,6 +8,7 @@ use std::time::Duration;
/// Parameters to use for secure clients
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct ClientTlsParameters {
/// A connector from `native-tls`
pub connector: TlsConnector,
@@ -18,16 +19,13 @@ pub struct ClientTlsParameters {
impl ClientTlsParameters {
/// Creates a `ClientTlsParameters`
pub fn new(domain: String, connector: TlsConnector) -> ClientTlsParameters {
ClientTlsParameters {
connector: connector,
domain: domain,
}
ClientTlsParameters { connector, domain }
}
}
/// Accepted protocols by default.
/// This removes TLS 1.0 compared to tls-native defaults.
pub const DEFAULT_TLS_PROTOCOLS : &'static [Protocol] = &[Protocol::Tlsv11, Protocol::Tlsv12];
pub const DEFAULT_TLS_PROTOCOLS: &[Protocol] = &[Protocol::Tlsv11, Protocol::Tlsv12];
#[derive(Debug)]
/// Represents the different types of underlying network streams
@@ -46,11 +44,10 @@ impl NetworkStream {
match *self {
NetworkStream::Tcp(ref s) => s.peer_addr(),
NetworkStream::Tls(ref s) => s.get_ref().peer_addr(),
NetworkStream::Mock(_) => {
Ok(SocketAddr::V4(
SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80),
))
}
NetworkStream::Mock(_) => Ok(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
80,
))),
}
}
@@ -111,13 +108,11 @@ impl Connector for NetworkStream {
let tcp_stream = TcpStream::connect(addr)?;
match tls_parameters {
Some(context) => {
context
.connector
.connect(context.domain.as_ref(), tcp_stream)
.map(NetworkStream::Tls)
.map_err(|e| io::Error::new(ErrorKind::Other, e))
}
Some(context) => context
.connector
.connect(context.domain.as_ref(), tcp_stream)
.map(NetworkStream::Tls)
.map_err(|e| io::Error::new(ErrorKind::Other, e)),
None => Ok(NetworkStream::Tcp(tcp_stream)),
}
}
@@ -125,15 +120,13 @@ impl Connector for NetworkStream {
#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
fn upgrade_tls(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()> {
*self = match *self {
NetworkStream::Tcp(ref mut stream) => {
match tls_parameters.connector.connect(
tls_parameters.domain.as_ref(),
stream.try_clone().unwrap(),
) {
Ok(tls_stream) => NetworkStream::Tls(tls_stream),
Err(err) => return Err(io::Error::new(ErrorKind::Other, err)),
}
}
NetworkStream::Tcp(ref mut stream) => match tls_parameters
.connector
.connect(tls_parameters.domain.as_ref(), stream.try_clone().unwrap())
{
Ok(tls_stream) => NetworkStream::Tls(tls_stream),
Err(err) => return Err(io::Error::new(ErrorKind::Other, err)),
},
NetworkStream::Tls(_) => return Ok(()),
NetworkStream::Mock(_) => return Ok(()),
};

View File

@@ -12,6 +12,7 @@ use std::fmt::{self, Display, Formatter};
/// EHLO command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct EhloCommand {
client_id: ClientId,
}
@@ -26,12 +27,13 @@ impl Display for EhloCommand {
impl EhloCommand {
/// Creates a EHLO command
pub fn new(client_id: ClientId) -> EhloCommand {
EhloCommand { client_id: client_id }
EhloCommand { client_id }
}
}
/// STARTTLS command
#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct StarttlsCommand;
impl Display for StarttlsCommand {
@@ -43,6 +45,7 @@ impl Display for StarttlsCommand {
/// MAIL command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct MailCommand {
sender: Option<EmailAddress>,
parameters: Vec<MailParameter>,
@@ -68,15 +71,13 @@ impl Display for MailCommand {
impl MailCommand {
/// Creates a MAIL command
pub fn new(sender: Option<EmailAddress>, parameters: Vec<MailParameter>) -> MailCommand {
MailCommand {
sender: sender,
parameters: parameters,
}
MailCommand { sender, parameters }
}
}
/// RCPT command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct RcptCommand {
recipient: EmailAddress,
parameters: Vec<RcptParameter>,
@@ -96,14 +97,15 @@ impl RcptCommand {
/// Creates an RCPT command
pub fn new(recipient: EmailAddress, parameters: Vec<RcptParameter>) -> RcptCommand {
RcptCommand {
recipient: recipient,
parameters: parameters,
recipient,
parameters,
}
}
}
/// DATA command
#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct DataCommand;
impl Display for DataCommand {
@@ -114,7 +116,8 @@ impl Display for DataCommand {
}
/// QUIT command
#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct QuitCommand;
impl Display for QuitCommand {
@@ -125,7 +128,8 @@ impl Display for QuitCommand {
}
/// NOOP command
#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct NoopCommand;
impl Display for NoopCommand {
@@ -137,6 +141,7 @@ impl Display for NoopCommand {
/// HELP command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct HelpCommand {
argument: Option<String>,
}
@@ -154,12 +159,13 @@ impl Display for HelpCommand {
impl HelpCommand {
/// Creates an HELP command
pub fn new(argument: Option<String>) -> HelpCommand {
HelpCommand { argument: argument }
HelpCommand { argument }
}
}
/// VRFY command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct VrfyCommand {
argument: String,
}
@@ -174,12 +180,13 @@ impl Display for VrfyCommand {
impl VrfyCommand {
/// Creates a VRFY command
pub fn new(argument: String) -> VrfyCommand {
VrfyCommand { argument: argument }
VrfyCommand { argument }
}
}
/// EXPN command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct ExpnCommand {
argument: String,
}
@@ -194,12 +201,13 @@ impl Display for ExpnCommand {
impl ExpnCommand {
/// Creates an EXPN command
pub fn new(argument: String) -> ExpnCommand {
ExpnCommand { argument: argument }
ExpnCommand { argument }
}
}
/// RSET command
#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct RsetCommand;
impl Display for RsetCommand {
@@ -211,6 +219,7 @@ impl Display for RsetCommand {
/// AUTH command
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct AuthCommand {
mechanism: Mechanism,
credentials: Credentials,
@@ -249,18 +258,15 @@ impl AuthCommand {
challenge: Option<String>,
) -> Result<AuthCommand, Error> {
let response = if mechanism.supports_initial_response() || challenge.is_some() {
Some(mechanism.response(
&credentials,
challenge.as_ref().map(String::as_str),
)?)
Some(mechanism.response(&credentials, challenge.as_ref().map(String::as_str))?)
} else {
None
};
Ok(AuthCommand {
mechanism: mechanism,
credentials: credentials,
challenge: challenge,
response: response,
mechanism,
credentials,
challenge,
response,
})
}
@@ -269,7 +275,7 @@ impl AuthCommand {
pub fn new_from_response(
mechanism: Mechanism,
credentials: Credentials,
response: Response,
response: &Response,
) -> Result<AuthCommand, Error> {
if !response.has_code(334) {
return Err(Error::ResponseParsing("Expecting a challenge"));
@@ -283,27 +289,22 @@ impl AuthCommand {
debug!("auth encoded challenge: {}", encoded_challenge);
let decoded_challenge = match base64::decode(&encoded_challenge) {
Ok(challenge) => {
match String::from_utf8(challenge) {
Ok(value) => value,
Err(error) => return Err(Error::Utf8Parsing(error)),
}
}
Ok(challenge) => match String::from_utf8(challenge) {
Ok(value) => value,
Err(error) => return Err(Error::Utf8Parsing(error)),
},
Err(error) => return Err(Error::ChallengeParsing(error)),
};
debug!("auth decoded challenge: {}", decoded_challenge);
let response = Some(mechanism.response(
&credentials,
Some(decoded_challenge.as_ref()),
)?);
let response = Some(mechanism.response(&credentials, Some(decoded_challenge.as_ref()))?);
Ok(AuthCommand {
mechanism: mechanism,
credentials: credentials,
mechanism,
credentials,
challenge: Some(decoded_challenge),
response: response,
response,
})
}
}
@@ -313,14 +314,12 @@ mod test {
use super::*;
use smtp::extension::MailBodyParameter;
#[cfg(feature = "crammd5-auth")]
use smtp::response::Code;
#[cfg(feature = "crammd5-auth")]
use std::str::FromStr;
use smtp::response::{Category, Code, Detail, Severity};
#[test]
fn test_display() {
let id = ClientId::Domain("localhost".to_string());
let email = EmailAddress::new("test@example.com".to_string());
let email = EmailAddress::new("test@example.com".to_string()).unwrap();
let mail_parameter = MailParameter::Other {
keyword: "TEST".to_string(),
value: Some("value".to_string()),
@@ -418,7 +417,14 @@ mod test {
AuthCommand::new_from_response(
Mechanism::CramMd5,
credentials.clone(),
Response::new(Code::from_str("334").unwrap(), vec!["dGVzdAo=".to_string()]),
&Response::new(
Code::new(
Severity::PositiveIntermediate,
Category::Unspecified3,
Detail::Four,
),
vec!["dGVzdAo=".to_string()],
),
).unwrap()
),
"dXNlciA1NTIzNThiMzExOWFjOWNkYzM2YWRiN2MxNWRmMWJkNw==\r\n"

View File

@@ -2,13 +2,14 @@
use self::Error::*;
use base64::DecodeError;
use native_tls;
use nom;
use smtp::response::{Response, Severity};
use std::error::Error as StdError;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io;
use std::string::FromUtf8Error;
use native_tls;
/// An enum of all error kinds.
#[derive(Debug)]
@@ -35,6 +36,8 @@ pub enum Error {
Io(io::Error),
/// TLS error
Tls(native_tls::Error),
/// Parsing error
Parsing(nom::simple_errors::Err),
}
impl Display for Error {
@@ -49,18 +52,14 @@ impl StdError for Error {
match *self {
// Try to display the first line of the server's response that usually
// contains a short humanly readable error message
Transient(ref err) => {
match err.first_line() {
Some(line) => line,
None => "undetailed transient error during SMTP transaction",
}
}
Permanent(ref err) => {
match err.first_line() {
Some(line) => line,
None => "undetailed permanent error during SMTP transaction",
}
}
Transient(ref err) => match err.first_line() {
Some(line) => line,
None => "undetailed transient error during SMTP transaction",
},
Permanent(ref err) => match err.first_line() {
Some(line) => line,
None => "undetailed permanent error during SMTP transaction",
},
ResponseParsing(err) => err,
ChallengeParsing(ref err) => err.description(),
Utf8Parsing(ref err) => err.description(),
@@ -68,15 +67,17 @@ impl StdError for Error {
Client(err) => err,
Io(ref err) => err.description(),
Tls(ref err) => err.description(),
Parsing(ref err) => err.description(),
}
}
fn cause(&self) -> Option<&StdError> {
match *self {
ChallengeParsing(ref err) => Some(&*err as &StdError),
Utf8Parsing(ref err) => Some(&*err as &StdError),
Io(ref err) => Some(&*err as &StdError),
Tls(ref err) => Some(&*err as &StdError),
ChallengeParsing(ref err) => Some(&*err),
Utf8Parsing(ref err) => Some(&*err),
Io(ref err) => Some(&*err),
Tls(ref err) => Some(&*err),
Parsing(ref err) => Some(&*err),
_ => None,
}
}
@@ -94,6 +95,12 @@ impl From<native_tls::Error> for Error {
}
}
impl From<nom::simple_errors::Err> for Error {
fn from(err: nom::simple_errors::Err) -> Error {
Parsing(err)
}
}
impl From<Response> for Error {
fn from(response: Response) -> Error {
match response.code.severity {

View File

@@ -1,5 +1,6 @@
//! ESMTP features
use hostname::get_hostname;
use smtp::authentication::Mechanism;
use smtp::error::Error;
use smtp::response::Response;
@@ -9,8 +10,12 @@ use std::fmt::{self, Display, Formatter};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::result::Result;
/// Default ehlo clinet id
pub const DEFAULT_EHLO_HOSTNAME: &str = "localhost";
/// Client identifier, the parameter to `EHLO`
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum ClientId {
/// A fully-qualified domain name
Domain(String),
@@ -35,10 +40,20 @@ impl ClientId {
pub fn new(domain: String) -> ClientId {
ClientId::Domain(domain)
}
/// Defines a `ClientId` with the current hostname, of `localhost` if hostname could not be
/// found
pub fn hostname() -> ClientId {
ClientId::Domain(match get_hostname() {
Some(name) => name,
None => DEFAULT_EHLO_HOSTNAME.to_string(),
})
}
}
/// Supported ESMTP keywords
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum Extension {
/// 8BITMIME keyword
///
@@ -59,16 +74,17 @@ pub enum Extension {
impl Display for Extension {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Extension::EightBitMime => write!(f, "{}", "8BITMIME"),
Extension::SmtpUtfEight => write!(f, "{}", "SMTPUTF8"),
Extension::StartTls => write!(f, "{}", "STARTTLS"),
Extension::Authentication(ref mechanism) => write!(f, "{} {}", "AUTH", mechanism),
Extension::EightBitMime => write!(f, "8BITMIME"),
Extension::SmtpUtfEight => write!(f, "SMTPUTF8"),
Extension::StartTls => write!(f, "STARTTLS"),
Extension::Authentication(ref mechanism) => write!(f, "AUTH {}", mechanism),
}
}
}
/// Contains information about an SMTP server
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct ServerInfo {
/// Server name
///
@@ -106,6 +122,10 @@ impl ServerInfo {
let mut features: HashSet<Extension> = HashSet::new();
for line in response.message.as_slice() {
if line.is_empty() {
continue;
}
let splitted: Vec<&str> = line.split_whitespace().collect();
match splitted[0] {
"8BITMIME" => {
@@ -117,30 +137,28 @@ impl ServerInfo {
"STARTTLS" => {
features.insert(Extension::StartTls);
}
"AUTH" => {
for &mechanism in &splitted[1..] {
match mechanism {
"PLAIN" => {
features.insert(Extension::Authentication(Mechanism::Plain));
}
"LOGIN" => {
features.insert(Extension::Authentication(Mechanism::Login));
}
#[cfg(feature = "crammd5-auth")]
"CRAM-MD5" => {
features.insert(Extension::Authentication(Mechanism::CramMd5));
}
_ => (),
"AUTH" => for &mechanism in &splitted[1..] {
match mechanism {
"PLAIN" => {
features.insert(Extension::Authentication(Mechanism::Plain));
}
"LOGIN" => {
features.insert(Extension::Authentication(Mechanism::Login));
}
#[cfg(feature = "crammd5-auth")]
"CRAM-MD5" => {
features.insert(Extension::Authentication(Mechanism::CramMd5));
}
_ => (),
}
}
},
_ => (),
};
}
Ok(ServerInfo {
name: name.to_string(),
features: features,
features,
})
}
@@ -151,14 +169,14 @@ impl ServerInfo {
/// Checks if the server supports an ESMTP feature
pub fn supports_auth_mechanism(&self, mechanism: Mechanism) -> bool {
self.features.contains(
&Extension::Authentication(mechanism),
)
self.features
.contains(&Extension::Authentication(mechanism))
}
}
/// A `MAIL FROM` extension parameter
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum MailParameter {
/// `BODY` parameter
Body(MailBodyParameter),
@@ -194,7 +212,8 @@ impl Display for MailParameter {
}
/// Values for the `BODY` parameter to `MAIL FROM`
#[derive(PartialEq, Eq, Clone, Debug)]
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum MailBodyParameter {
/// `7BIT`
SevenBit,
@@ -213,6 +232,7 @@ impl Display for MailBodyParameter {
/// A `RCPT TO` extension parameter
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum RcptParameter {
/// Custom parameter
Other {
@@ -241,11 +261,19 @@ impl Display for RcptParameter {
#[cfg(test)]
mod test {
use super::{Extension, ServerInfo};
use super::{ClientId, Extension, ServerInfo};
use smtp::authentication::Mechanism;
use smtp::response::{Category, Code, Detail, Response, Severity};
use std::collections::HashSet;
#[test]
fn test_clientid_fmt() {
assert_eq!(
format!("{}", ClientId::new("test".to_string())),
"test".to_string()
);
}
#[test]
fn test_extension_fmt() {
assert_eq!(
@@ -308,7 +336,7 @@ mod test {
Code::new(
Severity::PositiveCompletion,
Category::Unspecified4,
Detail(1),
Detail::One,
),
vec![
"me".to_string(),
@@ -336,7 +364,7 @@ mod test {
Code::new(
Severity::PositiveCompletion,
Category::Unspecified4,
Detail(1),
Detail::One,
),
vec![
"me".to_string(),
@@ -348,13 +376,9 @@ mod test {
let mut features2 = HashSet::new();
assert!(features2.insert(Extension::EightBitMime));
assert!(features2.insert(
Extension::Authentication(Mechanism::Plain),
));
assert!(features2.insert(Extension::Authentication(Mechanism::Plain),));
#[cfg(feature = "crammd5-auth")]
assert!(features2.insert(
Extension::Authentication(Mechanism::CramMd5),
));
assert!(features2.insert(Extension::Authentication(Mechanism::CramMd5),));
let server_info2 = ServerInfo {
name: "me".to_string(),

View File

@@ -13,107 +13,17 @@
//! * STARTTLS ([RFC 2487](http://tools.ietf.org/html/rfc2487))
//! * SMTPUTF8 ([RFC 6531](http://tools.ietf.org/html/rfc6531))
//!
//! #### Simple example
//!
//! This is the most basic example of usage:
//!
//! ```rust,no_run
//! use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};
//!
//! let email = SimpleSendableEmail::new(
//! EmailAddress::new("user@localhost".to_string()),
//! vec![EmailAddress::new("root@localhost".to_string())],
//! "message_id".to_string(),
//! "Hello world".to_string(),
//! );
//!
//! // Open a local connection on port 25
//! let mut mailer =
//! SmtpTransport::builder_unencrypted_localhost().unwrap().build();
//! // Send the email
//! let result = mailer.send(&email);
//!
//! assert!(result.is_ok());
//! ```
//!
//! #### Complete example
//!
//! ```rust,no_run
//! use lettre::smtp::authentication::{Credentials, Mechanism};
//! use lettre::smtp::SUBMISSION_PORT;
//! use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};
//! use lettre::smtp::extension::ClientId;
//! use lettre::smtp::ConnectionReuseParameters;
//!
//!
//! let email = SimpleSendableEmail::new(
//! EmailAddress::new("user@localhost".to_string()),
//! vec![EmailAddress::new("root@localhost".to_string())],
//! "message_id".to_string(),
//! "Hello world".to_string(),
//! );
//!
//! // Connect to a remote server on a custom port
//! let mut mailer = SmtpTransport::simple_builder("server.tld".to_string()).unwrap()
//! // Set the name sent during EHLO/HELO, default is `localhost`
//! .hello_name(ClientId::Domain("my.hostname.tld".to_string()))
//! // Add credentials for authentication
//! .credentials(Credentials::new("username".to_string(), "password".to_string()))
//! // Enable SMTPUTF8 if the server supports it
//! .smtp_utf8(true)
//! // Configure expected authentication mechanism
//! .authentication_mechanism(Mechanism::Plain)
//! // Enable connection reuse
//! .connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();
//!
//! let result_1 = mailer.send(&email);
//! assert!(result_1.is_ok());
//!
//! // The second email will use the same connection
//! let result_2 = mailer.send(&email);
//! assert!(result_2.is_ok());
//!
//! // Explicitly close the SMTP transaction as we enabled connection reuse
//! mailer.close();
//! ```
//!
//! #### Lower level
//!
//! You can also send commands, here is a simple email transaction without
//! error handling:
//!
//! ```rust
//! use lettre::EmailAddress;
//! use lettre::smtp::SMTP_PORT;
//! use lettre::smtp::client::Client;
//! use lettre::smtp::client::net::NetworkStream;
//! use lettre::smtp::extension::ClientId;
//! use lettre::smtp::commands::*;
//!
//! let mut email_client: Client<NetworkStream> = Client::new();
//! let _ = email_client.connect(&("localhost", SMTP_PORT), None);
//! let _ = email_client.smtp_command(EhloCommand::new(ClientId::new("my_hostname".to_string())));
//! let _ = email_client.smtp_command(
//! MailCommand::new(Some(EmailAddress::new("user@example.com".to_string())), vec![])
//! );
//! let _ = email_client.smtp_command(
//! RcptCommand::new(EmailAddress::new("user@example.org".to_string()), vec![])
//! );
//! let _ = email_client.smtp_command(DataCommand);
//! let _ = email_client.message(Box::new("Test email".as_bytes()));
//! let _ = email_client.smtp_command(QuitCommand);
//! ```
use EmailTransport;
use SendableEmail;
use native_tls::TlsConnector;
use smtp::authentication::{Credentials, DEFAULT_ENCRYPTED_MECHANISMS,
DEFAULT_UNENCRYPTED_MECHANISMS, Mechanism};
use smtp::authentication::{Credentials, Mechanism, DEFAULT_ENCRYPTED_MECHANISMS,
DEFAULT_UNENCRYPTED_MECHANISMS};
use smtp::client::Client;
use smtp::client::net::ClientTlsParameters;
use smtp::client::net::DEFAULT_TLS_PROTOCOLS;
use smtp::commands::*;
use smtp::error::{Error, SmtpResult};
use smtp::client::net::DEFAULT_TLS_PROTOCOLS;
use smtp::extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo};
use std::io::Read;
use std::net::{SocketAddr, ToSocketAddrs};
@@ -140,22 +50,23 @@ pub const SUBMISSION_PORT: u16 = 587;
// Useful strings and characters
/// The word separator for SMTP transactions
pub const SP: &'static str = " ";
pub const SP: &str = " ";
/// The line ending for SMTP transactions (carriage return + line feed)
pub const CRLF: &'static str = "\r\n";
pub const CRLF: &str = "\r\n";
/// Colon
pub const COLON: &'static str = ":";
pub const COLON: &str = ":";
/// The ending of message content
pub const MESSAGE_ENDING: &'static str = "\r\n.\r\n";
pub const MESSAGE_ENDING: &str = "\r\n.\r\n";
/// NUL unicode character
pub const NUL: &'static str = "\0";
pub const NUL: &str = "\0";
/// How to apply TLS to a client connection
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub enum ClientSecurity {
/// Insecure connection
None,
@@ -169,7 +80,8 @@ pub enum ClientSecurity {
}
/// Configures connection reuse behavior
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Copy)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum ConnectionReuseParameters {
/// Unlimitied connection reuse
ReuseUnlimited,
@@ -180,6 +92,7 @@ pub enum ConnectionReuseParameters {
}
/// Contains client configuration
#[allow(missing_debug_implementations)]
pub struct SmtpTransportBuilder {
/// Enable connection reuse
connection_reuse: ConnectionReuseParameters,
@@ -207,7 +120,6 @@ impl SmtpTransportBuilder {
/// Defaults are:
///
/// * No connection reuse
/// * "localhost" as EHLO name
/// * No authentication
/// * No SMTPUTF8 support
/// * A 60 seconds timeout for smtp commands
@@ -218,18 +130,16 @@ impl SmtpTransportBuilder {
let mut addresses = addr.to_socket_addrs()?;
match addresses.next() {
Some(addr) => {
Ok(SmtpTransportBuilder {
server_addr: addr,
security: security,
smtp_utf8: false,
credentials: None,
connection_reuse: ConnectionReuseParameters::NoReuse,
hello_name: ClientId::Domain("localhost".to_string()),
authentication_mechanism: None,
timeout: Some(Duration::new(60, 0)),
})
}
Some(addr) => Ok(SmtpTransportBuilder {
server_addr: addr,
security,
smtp_utf8: false,
credentials: None,
connection_reuse: ConnectionReuseParameters::NoReuse,
hello_name: ClientId::hostname(),
authentication_mechanism: None,
timeout: Some(Duration::new(60, 0)),
}),
None => Err(Error::Resolution),
}
}
@@ -291,6 +201,7 @@ struct State {
}
/// Structure that implements the high level SMTP client
#[allow(missing_debug_implementations)]
pub struct SmtpTransport {
/// Information about the server
/// Value is None before HELO/EHLO
@@ -310,7 +221,7 @@ macro_rules! try_smtp (
Err(err) => {
if !$client.state.panic {
$client.state.panic = true;
$client.reset();
$client.close();
}
return Err(From::from(err))
},
@@ -322,18 +233,15 @@ impl<'a> SmtpTransport {
/// Simple and secure transport, should be used when possible.
/// Creates an encrypted transport over submission port, using the provided domain
/// to validate TLS certificates.
pub fn simple_builder(domain: String) -> Result<SmtpTransportBuilder, Error> {
pub fn simple_builder(domain: &str) -> Result<SmtpTransportBuilder, Error> {
let mut tls_builder = TlsConnector::builder()?;
tls_builder.supported_protocols(DEFAULT_TLS_PROTOCOLS)?;
let tls_parameters = ClientTlsParameters::new(
domain.clone(),
tls_builder.build().unwrap(),
);
let tls_parameters =
ClientTlsParameters::new(domain.to_string(), tls_builder.build().unwrap());
SmtpTransportBuilder::new(
(domain.as_ref(), SUBMISSION_PORT),
(domain, SUBMISSION_PORT),
ClientSecurity::Required(tls_parameters),
)
}
@@ -355,11 +263,10 @@ impl<'a> SmtpTransport {
///
/// It does not connect to the server, but only creates the `SmtpTransport`
pub fn new(builder: SmtpTransportBuilder) -> SmtpTransport {
let client = Client::new();
SmtpTransport {
client: client,
client,
server_info: None,
client_info: builder,
state: State {
@@ -370,12 +277,12 @@ impl<'a> SmtpTransport {
}
/// Gets the EHLO response and updates server information
pub fn get_ehlo(&mut self) -> SmtpResult {
fn ehlo(&mut self) -> SmtpResult {
// Extended Hello
let ehlo_response = try_smtp!(
self.client.smtp_command(EhloCommand::new(
ClientId::new(self.client_info.hello_name.to_string()),
)),
self.client.command(EhloCommand::new(ClientId::new(
self.client_info.hello_name.to_string()
),)),
self
);
@@ -387,15 +294,10 @@ impl<'a> SmtpTransport {
Ok(ehlo_response)
}
/// Closes the inner connection
pub fn close(&mut self) {
self.client.close();
}
/// Reset the client state
pub fn reset(&mut self) {
pub fn close(&mut self) {
// Close the SMTP transaction if needed
self.close();
self.client.close();
// Reset the client state
self.server_info = None;
@@ -408,13 +310,13 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
/// Sends an email
#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms, cyclomatic_complexity))]
fn send<U: SendableEmail<'a, T> + 'a>(&mut self, email: &'a U) -> SmtpResult {
// Extract email information
let message_id = email.message_id();
let envelope = email.envelope();
// Check if the connection is still available
if (self.state.connection_reuse_count > 0) && (!self.client.is_connected()) {
self.reset();
self.close();
}
if self.state.connection_reuse_count == 0 {
@@ -431,13 +333,14 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
// Log the connection
info!("connection established to {}", self.client_info.server_addr);
self.get_ehlo()?;
self.ehlo()?;
match (
&self.client_info.security.clone(),
self.server_info.as_ref().unwrap().supports_feature(
Extension::StartTls,
),
self.server_info
.as_ref()
.unwrap()
.supports_feature(Extension::StartTls),
) {
(&ClientSecurity::Required(_), false) => {
return Err(From::from("Could not encrypt connection, aborting"))
@@ -445,15 +348,15 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
(&ClientSecurity::Opportunistic(_), false) => (),
(&ClientSecurity::None, _) => (),
(&ClientSecurity::Wrapper(_), _) => (),
(&ClientSecurity::Opportunistic(ref tls_parameters), true) |
(&ClientSecurity::Required(ref tls_parameters), true) => {
try_smtp!(self.client.smtp_command(StarttlsCommand), self);
(&ClientSecurity::Opportunistic(ref tls_parameters), true)
| (&ClientSecurity::Required(ref tls_parameters), true) => {
try_smtp!(self.client.command(StarttlsCommand), self);
try_smtp!(self.client.upgrade_tls_stream(tls_parameters), self);
debug!("connection encrypted");
// Send EHLO again
self.get_ehlo()?;
self.ehlo()?;
}
}
@@ -473,16 +376,15 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
};
for mechanism in accepted_mechanisms {
if self.server_info.as_ref().unwrap().supports_auth_mechanism(
mechanism,
)
if self.server_info
.as_ref()
.unwrap()
.supports_auth_mechanism(mechanism)
{
found = true;
try_smtp!(
self.client.auth(
mechanism,
self.client_info.credentials.as_ref().unwrap(),
),
self.client
.auth(mechanism, self.client_info.credentials.as_ref().unwrap(),),
self
);
break;
@@ -498,37 +400,43 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
// Mail
let mut mail_options = vec![];
if self.server_info.as_ref().unwrap().supports_feature(
Extension::EightBitMime,
)
if self.server_info
.as_ref()
.unwrap()
.supports_feature(Extension::EightBitMime)
{
mail_options.push(MailParameter::Body(MailBodyParameter::EightBitMime));
}
if self.server_info.as_ref().unwrap().supports_feature(
Extension::SmtpUtfEight,
) && self.client_info.smtp_utf8
if self.server_info
.as_ref()
.unwrap()
.supports_feature(Extension::SmtpUtfEight) && self.client_info.smtp_utf8
{
mail_options.push(MailParameter::SmtpUtfEight);
}
try_smtp!(
self.client.smtp_command(MailCommand::new(
Some(email.from().clone()),
mail_options,
)),
self.client
.command(MailCommand::new(envelope.from().cloned(), mail_options,)),
self
);
// Log the mail command
info!("{}: from=<{}>", message_id, email.from());
info!(
"{}: from=<{}>",
message_id,
match envelope.from() {
Some(address) => address.to_string(),
None => "".to_string(),
}
);
// Recipient
for to_address in &email.to() {
for to_address in envelope.to() {
try_smtp!(
self.client.smtp_command(
RcptCommand::new(to_address.clone(), vec![]),
),
self.client
.command(RcptCommand::new(to_address.clone(), vec![]),),
self
);
// Log the rcpt command
@@ -536,7 +444,7 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
}
// Data
try_smtp!(self.client.smtp_command(DataCommand), self);
try_smtp!(self.client.command(DataCommand), self);
// Message content
let result = self.client.message(email.message());
@@ -564,8 +472,11 @@ impl<'a, T: Read + 'a> EmailTransport<'a, T, SmtpResult> for SmtpTransport {
// Test if we can reuse the existing connection
match self.client_info.connection_reuse {
ConnectionReuseParameters::ReuseLimited(limit)
if self.state.connection_reuse_count >= limit => self.reset(),
ConnectionReuseParameters::NoReuse => self.reset(),
if self.state.connection_reuse_count >= limit =>
{
self.close()
}
ConnectionReuseParameters::NoReuse => self.close(),
_ => (),
}

View File

@@ -1,131 +1,91 @@
//! SMTP response, containing a mandatory return code and an optional text
//! message
use self::Category::*;
use self::Severity::*;
use smtp::error::{Error, SmtpResult};
use nom::{crlf, ErrorKind as NomErrorKind, IResult as NomResult};
use nom::simple_errors::Err as NomError;
use std::fmt::{Display, Formatter, Result};
use std::result;
use std::str::FromStr;
use std::str::{FromStr, from_utf8};
/// First digit indicates severity
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum Severity {
/// 2yx
PositiveCompletion,
PositiveCompletion = 2,
/// 3yz
PositiveIntermediate,
PositiveIntermediate = 3,
/// 4yz
TransientNegativeCompletion,
TransientNegativeCompletion = 4,
/// 5yz
PermanentNegativeCompletion,
}
impl FromStr for Severity {
type Err = Error;
fn from_str(s: &str) -> result::Result<Severity, Error> {
match s {
"2" => Ok(PositiveCompletion),
"3" => Ok(PositiveIntermediate),
"4" => Ok(TransientNegativeCompletion),
"5" => Ok(PermanentNegativeCompletion),
_ => Err(Error::ResponseParsing(
"First digit must be between 2 and 5",
)),
}
}
PermanentNegativeCompletion = 5,
}
impl Display for Severity {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(
f,
"{}",
match *self {
PositiveCompletion => 2,
PositiveIntermediate => 3,
TransientNegativeCompletion => 4,
PermanentNegativeCompletion => 5,
}
)
write!(f, "{}", *self as u8)
}
}
/// Second digit
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum Category {
/// x0z
Syntax,
Syntax = 0,
/// x1z
Information,
Information = 1,
/// x2z
Connections,
Connections = 2,
/// x3z
Unspecified3,
Unspecified3 = 3,
/// x4z
Unspecified4,
Unspecified4 = 4,
/// x5z
MailSystem,
}
impl FromStr for Category {
type Err = Error;
fn from_str(s: &str) -> result::Result<Category, Error> {
match s {
"0" => Ok(Syntax),
"1" => Ok(Information),
"2" => Ok(Connections),
"3" => Ok(Unspecified3),
"4" => Ok(Unspecified4),
"5" => Ok(MailSystem),
_ => Err(Error::ResponseParsing(
"Second digit must be between 0 and 5",
)),
}
}
MailSystem = 5,
}
impl Display for Category {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(
f,
"{}",
match *self {
Syntax => 0,
Information => 1,
Connections => 2,
Unspecified3 => 3,
Unspecified4 => 4,
MailSystem => 5,
}
)
write!(f, "{}", *self as u8)
}
}
/// The detail digit of a response code (third digit)
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct Detail(pub u8);
impl FromStr for Detail {
type Err = Error;
fn from_str(s: &str) -> result::Result<Detail, Error> {
match s.parse::<u8>() {
Ok(d) if d < 10 => Ok(Detail(d)),
_ => Err(Error::ResponseParsing(
"Third digit must be between 0 and 9",
)),
}
}
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub enum Detail {
#[allow(missing_docs)]
Zero = 0,
#[allow(missing_docs)]
One = 1,
#[allow(missing_docs)]
Two = 2,
#[allow(missing_docs)]
Three = 3,
#[allow(missing_docs)]
Four = 4,
#[allow(missing_docs)]
Five = 5,
#[allow(missing_docs)]
Six = 6,
#[allow(missing_docs)]
Seven = 7,
#[allow(missing_docs)]
Eight = 8,
#[allow(missing_docs)]
Nine = 9,
}
impl Display for Detail {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}", self.0)
write!(f, "{}", *self as u8)
}
}
/// Represents a 3 digit SMTP response code
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct Code {
/// First digit of the response code
pub severity: Severity,
@@ -141,99 +101,13 @@ impl Display for Code {
}
}
impl FromStr for Code {
type Err = Error;
#[inline]
fn from_str(s: &str) -> result::Result<Code, Error> {
if s.len() == 3 {
match (
s[0..1].parse::<Severity>(),
s[1..2].parse::<Category>(),
s[2..3].parse::<Detail>(),
) {
(Ok(severity), Ok(category), Ok(detail)) => {
Ok(Code {
severity: severity,
category: category,
detail: detail,
})
}
_ => Err(Error::ResponseParsing("Could not parse response code")),
}
} else {
Err(Error::ResponseParsing(
"Wrong code length (should be 3 digit)",
))
}
}
}
impl Code {
/// Creates a new `Code` structure
pub fn new(severity: Severity, category: Category, detail: Detail) -> Code {
if detail.0 > 9 {
panic!("The detail code must be between 0 and 9");
}
Code {
severity: severity,
category: category,
detail: detail,
}
}
}
/// Parses an SMTP response
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct ResponseParser {
/// Response code
code: Option<Code>,
/// Server response string (optional)
/// Handle multiline responses
message: Vec<String>,
}
impl ResponseParser {
/// Parses a line and return a `bool` indicating if there are more lines to come
pub fn read_line(&mut self, line: &str) -> result::Result<bool, Error> {
if line.len() < 3 {
return Err(Error::ResponseParsing(
"Incorrect response code (should be 3 digits)",
));
}
match self.code {
Some(ref code) => {
if code.to_string() != line[0..3] {
return Err(Error::ResponseParsing(
"Response code has changed during a \
reponse",
));
}
}
None => self.code = Some(line[0..3].parse::<Code>()?),
}
if line.len() > 4 {
self.message.push(line[4..].to_string());
Ok(line.as_bytes()[3] == b'-')
} else {
Ok(false)
}
}
/// Builds a response from a `ResponseParser`
pub fn response(self) -> SmtpResult {
match self.code {
Some(code) => Ok(Response::new(code, self.message)),
None => {
Err(Error::ResponseParsing(
"Incomplete response, could not read response \
code",
))
}
severity,
category,
detail,
}
}
}
@@ -242,6 +116,7 @@ impl ResponseParser {
///
/// The text message is optional, only the code is mandatory
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct Response {
/// Response code
pub code: Code,
@@ -250,33 +125,42 @@ pub struct Response {
pub message: Vec<String>,
}
impl FromStr for Response {
type Err = NomError;
fn from_str(s: &str) -> result::Result<Response, NomError> {
match parse_response(s.as_bytes()) {
NomResult::Done(_, res) => Ok(res),
NomResult::Error(e) => Err(e),
NomResult::Incomplete(_) => Err(NomErrorKind::Complete),
}
}
}
impl Response {
/// Creates a new `Response`
pub fn new(code: Code, message: Vec<String>) -> Response {
Response {
code: code,
message: message,
}
Response { code, message }
}
/// Tells if the response is positive
pub fn is_positive(&self) -> bool {
match self.code.severity {
PositiveCompletion | PositiveIntermediate => true,
Severity::PositiveCompletion | Severity::PositiveIntermediate => true,
_ => false,
}
}
/// Tests code equality
pub fn has_code(&self, code: u16) -> bool {
self.code.to_string() == format!("{}", code)
self.code.to_string() == code.to_string()
}
/// Returns only the first word of the message if possible
pub fn first_word(&self) -> Option<&str> {
self.message.get(0).and_then(
|line| line.split_whitespace().next(),
)
self.message
.get(0)
.and_then(|line| line.split_whitespace().next())
}
/// Returns only the line of the message if possible
@@ -285,36 +169,109 @@ impl Response {
}
}
// Parsers (originaly from tokio-smtp)
named!(
parse_code<Code>,
map!(
tuple!(parse_severity, parse_category, parse_detail),
|(severity, category, detail)| Code {
severity,
category,
detail,
}
)
);
named!(
parse_severity<Severity>,
alt!(
tag!("2") => { |_| Severity::PositiveCompletion } |
tag!("3") => { |_| Severity::PositiveIntermediate } |
tag!("4") => { |_| Severity::TransientNegativeCompletion } |
tag!("5") => { |_| Severity::PermanentNegativeCompletion }
)
);
named!(
parse_category<Category>,
alt!(
tag!("0") => { |_| Category::Syntax } |
tag!("1") => { |_| Category::Information } |
tag!("2") => { |_| Category::Connections } |
tag!("3") => { |_| Category::Unspecified3 } |
tag!("4") => { |_| Category::Unspecified4 } |
tag!("5") => { |_| Category::MailSystem }
)
);
named!(
parse_detail<Detail>,
alt!(
tag!("0") => { |_| Detail::Zero } |
tag!("1") => { |_| Detail::One } |
tag!("2") => { |_| Detail::Two } |
tag!("3") => { |_| Detail::Three } |
tag!("4") => { |_| Detail::Four} |
tag!("5") => { |_| Detail::Five } |
tag!("6") => { |_| Detail::Six} |
tag!("7") => { |_| Detail::Seven } |
tag!("8") => { |_| Detail::Eight } |
tag!("9") => { |_| Detail::Nine }
)
);
named!(
parse_response<Response>,
map_res!(
tuple!(
// Parse any number of continuation lines.
many0!(tuple!(
parse_code,
preceded!(char!('-'), take_until_and_consume!(b"\r\n".as_ref()))
)),
// Parse the final line.
tuple!(
parse_code,
terminated!(
opt!(preceded!(char!(' '), take_until!(b"\r\n".as_ref()))),
crlf
)
)
),
|(lines, (last_code, last_line)): (Vec<_>, _)| {
// Check that all codes are equal.
if !lines.iter().all(|&(ref code, _)| *code == last_code) {
return Err(());
}
// Extract text from lines, and append last line.
let mut lines = lines.into_iter().map(|(_, text)| text).collect::<Vec<_>>();
if let Some(text) = last_line {
lines.push(text);
}
Ok(Response {
code: last_code,
message: lines
.into_iter()
.map(|line| from_utf8(line).map(|s| s.to_string()))
.collect::<result::Result<Vec<_>, _>>()
.map_err(|_| ())?,
})
}
)
);
#[cfg(test)]
mod test {
use super::{Category, Code, Detail, Response, ResponseParser, Severity};
#[test]
fn test_severity_from_str() {
assert_eq!(
"2".parse::<Severity>().unwrap(),
Severity::PositiveCompletion
);
assert_eq!(
"4".parse::<Severity>().unwrap(),
Severity::TransientNegativeCompletion
);
assert!("1".parse::<Severity>().is_err());
assert!("51".parse::<Severity>().is_err());
}
use super::{Category, Code, Detail, Response, Severity};
#[test]
fn test_severity_fmt() {
assert_eq!(format!("{}", Severity::PositiveCompletion), "2");
}
#[test]
fn test_category_from_str() {
assert_eq!("2".parse::<Category>().unwrap(), Category::Connections);
assert_eq!("4".parse::<Category>().unwrap(), Category::Unspecified4);
assert!("6".parse::<Category>().is_err());
}
#[test]
fn test_category_fmt() {
assert_eq!(format!("{}", Category::Unspecified4), "4");
@@ -326,121 +283,37 @@ mod test {
Code::new(
Severity::TransientNegativeCompletion,
Category::Connections,
Detail(0),
Detail::Zero,
),
Code {
severity: Severity::TransientNegativeCompletion,
category: Category::Connections,
detail: Detail(0),
detail: Detail::Zero,
}
);
}
#[test]
#[should_panic]
fn test_code_new_panic() {
let _ = Code::new(
Severity::TransientNegativeCompletion,
Category::Connections,
Detail(11),
);
}
#[test]
fn test_code_from_str() {
assert_eq!(
"421".parse::<Code>().unwrap(),
Code {
severity: Severity::TransientNegativeCompletion,
category: Category::Connections,
detail: "1".parse::<Detail>().unwrap(),
}
);
assert!("2222".parse::<Code>().is_err());
assert!("aaa".parse::<Code>().is_err());
assert!("-32".parse::<Code>().is_err());
assert!("-333".parse::<Code>().is_err());
assert!("".parse::<Code>().is_err());
assert!("292".parse::<Code>().is_err());
}
#[test]
fn test_code_display() {
let code = Code {
severity: Severity::TransientNegativeCompletion,
category: Category::Connections,
detail: Detail(1),
detail: Detail::One,
};
assert_eq!(code.to_string(), "421");
}
#[test]
fn test_response_new() {
fn test_response_from_str() {
let raw_response = "250-me\r\n250-8BITMIME\r\n250-SIZE 42\r\n250 AUTH PLAIN CRAM-MD5\r\n";
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "4".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
},
vec![
"me".to_string(),
"8BITMIME".to_string(),
"SIZE 42".to_string(),
],
),
Response {
code: Code {
severity: Severity::PositiveCompletion,
category: Category::Unspecified4,
detail: "1".parse::<Detail>().unwrap(),
},
message: vec![
"me".to_string(),
"8BITMIME".to_string(),
"SIZE 42".to_string(),
],
}
);
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "4".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
},
vec![],
),
Response {
code: Code {
severity: Severity::PositiveCompletion,
category: Category::Unspecified4,
detail: "1".parse::<Detail>().unwrap(),
},
message: vec![],
}
);
}
#[test]
fn test_response_parser() {
let mut parser = ResponseParser::default();
assert!(parser.read_line("250-me").unwrap());
assert!(parser.read_line("250-8BITMIME").unwrap());
assert!(parser.read_line("250-SIZE 42").unwrap());
assert!(!parser.read_line("250 AUTH PLAIN CRAM-MD5").unwrap());
let response = parser.response().unwrap();
assert_eq!(
response,
raw_response.parse::<Response>().unwrap(),
Response {
code: Code {
severity: Severity::PositiveCompletion,
category: Category::MailSystem,
detail: Detail(0),
detail: Detail::Zero,
},
message: vec![
"me".to_string(),
@@ -450,6 +323,12 @@ mod test {
],
}
);
let wrong_code = "2506-me\r\n250-8BITMIME\r\n250-SIZE 42\r\n250 AUTH PLAIN CRAM-MD5\r\n";
assert!(wrong_code.parse::<Response>().is_err());
let wrong_end = "250-me\r\n250-8BITMIME\r\n250-SIZE 42\r\n250-AUTH PLAIN CRAM-MD5\r\n";
assert!(wrong_end.parse::<Response>().is_err());
}
#[test]
@@ -457,9 +336,9 @@ mod test {
assert!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::PositiveCompletion,
category: Category::MailSystem,
detail: Detail::Zero,
},
vec![
"me".to_string(),
@@ -470,9 +349,9 @@ mod test {
);
assert!(!Response::new(
Code {
severity: "5".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::Zero,
},
vec![
"me".to_string(),
@@ -487,29 +366,29 @@ mod test {
assert!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "4".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![
"me".to_string(),
"8BITMIME".to_string(),
"SIZE 42".to_string(),
],
).has_code(241)
).has_code(451)
);
assert!(!Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "5".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![
"me".to_string(),
"8BITMIME".to_string(),
"SIZE 42".to_string(),
],
).has_code(241));
).has_code(251));
}
#[test]
@@ -517,9 +396,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![
"me".to_string(),
@@ -532,9 +411,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![
"me mo".to_string(),
@@ -547,9 +426,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![],
).first_word(),
@@ -558,9 +437,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![" ".to_string()],
).first_word(),
@@ -569,9 +448,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![" ".to_string()],
).first_word(),
@@ -580,9 +459,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec!["".to_string()],
).first_word(),
@@ -595,9 +474,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![
"me".to_string(),
@@ -610,9 +489,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![
"me mo".to_string(),
@@ -625,9 +504,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![],
).first_line(),
@@ -636,9 +515,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![" ".to_string()],
).first_line(),
@@ -647,9 +526,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec![" ".to_string()],
).first_line(),
@@ -658,9 +537,9 @@ mod test {
assert_eq!(
Response::new(
Code {
severity: "2".parse::<Severity>().unwrap(),
category: "3".parse::<Category>().unwrap(),
detail: "1".parse::<Detail>().unwrap(),
severity: Severity::TransientNegativeCompletion,
category: Category::MailSystem,
detail: Detail::One,
},
vec!["".to_string()],
).first_line(),

View File

@@ -4,6 +4,7 @@ use std::fmt::{Display, Formatter, Result as FmtResult};
/// Encode a string as xtext
#[derive(Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct XText<'a>(pub &'a str);
impl<'a> Display for XText<'a> {
@@ -27,7 +28,6 @@ impl<'a> Display for XText<'a> {
}
}
#[cfg(test)]
mod tests {
use super::XText;
@@ -39,8 +39,7 @@ mod tests {
("bjørn", "bjørn"),
("Ø+= ❤️‰", "Ø+2B+3D+20❤"),
("+", "+2B"),
]
{
] {
assert_eq!(format!("{}", XText(input)), expect);
}
}

View File

@@ -1,34 +1,13 @@
//! The stub transport only logs message envelope and drops the content. It can be useful for
//! testing purposes.
//!
//! ```rust
//! use lettre::stub::StubEmailTransport;
//! use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
//!
//! let email = SimpleSendableEmail::new(
//! EmailAddress::new("user@localhost".to_string()),
//! vec![EmailAddress::new("root@localhost".to_string())],
//! "message_id".to_string(),
//! "Hello world".to_string(),
//! );
//!
//! let mut sender = StubEmailTransport::new_positive();
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! ```
//!
//! Will log (when using a logger like `env_logger`):
//!
//! ```text
//! b7c211bc-9811-45ce-8cd9-68eab575d695: from=<user@localhost> to=<root@localhost>
//! ```
use EmailTransport;
use SendableEmail;
use std::io::Read;
/// This transport logs the message envelope and returns the given response
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub struct StubEmailTransport {
response: StubResult,
}
@@ -36,14 +15,12 @@ pub struct StubEmailTransport {
impl StubEmailTransport {
/// Creates a new transport that always returns the given response
pub fn new(response: StubResult) -> StubEmailTransport {
StubEmailTransport { response: response }
StubEmailTransport { response }
}
/// Creates a new transport that always returns a success response
pub fn new_positive() -> StubEmailTransport {
StubEmailTransport {
response: Ok(()),
}
StubEmailTransport { response: Ok(()) }
}
}
@@ -52,12 +29,15 @@ pub type StubResult = Result<(), ()>;
impl<'a, T: Read + 'a> EmailTransport<'a, T, StubResult> for StubEmailTransport {
fn send<U: SendableEmail<'a, T>>(&mut self, email: &'a U) -> StubResult {
let envelope = email.envelope();
info!(
"{}: from=<{}> to=<{:?}>",
email.message_id(),
email.from(),
email.to()
match envelope.from() {
Some(address) => address.to_string(),
None => "".to_string(),
},
envelope.to()
);
self.response
}

62
lettre/tests/skeptic.rs Normal file
View File

@@ -0,0 +1,62 @@
extern crate glob;
use self::glob::glob;
use std::env::consts::EXE_EXTENSION;
use std::env;
use std::path::Path;
use std::process::Command;
#[test]
fn test_readme() {
let readme = Path::new(file!())
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.join("README.md");
skeptic_test(&readme);
}
#[test]
fn book_test() {
let mut book_path = env::current_dir().unwrap();
book_path.push(
Path::new(file!())
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.join("../website/content/sending-messages"),
); // For some reasons, calling .parent() once more gives us None...
for md in glob(&format!("{}/*.md", book_path.to_str().unwrap())).unwrap() {
skeptic_test(&md.unwrap());
}
}
fn skeptic_test(path: &Path) {
let rustdoc = Path::new("rustdoc").with_extension(EXE_EXTENSION);
let exe = env::current_exe().unwrap();
let depdir = exe.parent().unwrap();
let mut cmd = Command::new(rustdoc);
cmd.args(&["--verbose", "--test"])
.arg("-L")
.arg(&depdir)
.arg(path);
let result = cmd.spawn()
.expect("Failed to spawn process")
.wait()
.expect("Failed to run process");
assert!(
result.success(),
format!("Failed to run rustdoc tests on {:?}", path)
);
}

View File

@@ -4,7 +4,7 @@ extern crate lettre;
#[cfg(feature = "file-transport")]
mod test {
use lettre::{EmailAddress, EmailTransport, SendableEmail, SimpleSendableEmail};
use lettre::{EmailTransport, SendableEmail, SimpleSendableEmail};
use lettre::file::FileEmailTransport;
use std::env::temp_dir;
use std::fs::File;
@@ -15,11 +15,11 @@ mod test {
fn file_transport() {
let mut sender = FileEmailTransport::new(temp_dir());
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"user@localhost".to_string(),
&["root@localhost".to_string()],
"file_id".to_string(),
"Hello file".to_string(),
);
).unwrap();
let result = sender.send(&email);
assert!(result.is_ok());
@@ -31,8 +31,7 @@ mod test {
assert_eq!(
buffer,
"{\"to\":[\"root@localhost\"],\"from\":\"user@localhost\",\"message_id\":\
\"file_id\",\"message\":[72,101,108,108,111,32,102,105,108,101]}"
"{\"envelope\":{\"forward_path\":[\"root@localhost\"],\"reverse_path\":\"user@localhost\"},\"message_id\":\"file_id\",\"message\":[72,101,108,108,111,32,102,105,108,101]}"
);
remove_file(file).unwrap();

View File

@@ -4,18 +4,18 @@ extern crate lettre;
#[cfg(feature = "sendmail-transport")]
mod test {
use lettre::{EmailAddress, EmailTransport, SimpleSendableEmail};
use lettre::{EmailTransport, SimpleSendableEmail};
use lettre::sendmail::SendmailTransport;
#[test]
fn sendmail_transport_simple() {
let mut sender = SendmailTransport::new();
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"user@localhost".to_string(),
&["root@localhost".to_string()],
"sendmail_id".to_string(),
"Hello sendmail".to_string(),
);
).unwrap();
let result = sender.send(&email);
println!("{:?}", result);

View File

@@ -4,7 +4,7 @@ extern crate lettre;
#[cfg(feature = "smtp-transport")]
mod test {
use lettre::{ClientSecurity, EmailAddress, EmailTransport, SimpleSendableEmail, SmtpTransport};
use lettre::{ClientSecurity, EmailTransport, SimpleSendableEmail, SmtpTransport};
#[test]
fn smtp_transport_simple() {
@@ -12,11 +12,11 @@ mod test {
.unwrap()
.build();
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"user@localhost".to_string(),
&["root@localhost".to_string()],
"smtp_id".to_string(),
"Hello smtp".to_string(),
);
).unwrap();
sender.send(&email).unwrap();
}

View File

@@ -1,19 +1,18 @@
extern crate lettre;
use lettre::{EmailAddress, EmailTransport, SimpleSendableEmail};
use lettre::{EmailTransport, SimpleSendableEmail};
use lettre::stub::StubEmailTransport;
#[test]
fn stub_transport() {
let mut sender_ok = StubEmailTransport::new_positive();
let mut sender_ko = StubEmailTransport::new(Err(()));
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"user@localhost".to_string(),
&["root@localhost".to_string()],
"stub_id".to_string(),
"Hello stub".to_string(),
);
).unwrap();
sender_ok.send(&email).unwrap();
sender_ko.send(&email).unwrap_err();

View File

@@ -1,48 +0,0 @@
### v0.7.0 (2017-10-08)
#### Features
* **all**
* Split into the *lettre* and *lettre_email* crates
* A lot of small improvements
* **email**
* Initial (incomplete) attachments support
### v0.6.2 (2017-02-18)
#### Features
* **all**
* Update uuid crate to 0.4
### 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

1
lettre_email/CHANGELOG.md Symbolic link
View File

@@ -0,0 +1 @@
../CHANGELOG.md

View File

@@ -1,7 +1,7 @@
[package]
name = "lettre_email"
version = "0.7.0"
version = "0.8.1" # remember to update html_root_url
description = "Email builder"
readme = "README.md"
documentation = "https://docs.rs/lettre_email/"
@@ -15,12 +15,13 @@ keywords = ["email", "mailer"]
travis-ci = { repository = "lettre/lettre_email" }
[dev-dependencies]
env_logger = "*"
lettre = { path = "../lettre", features = ["smtp-transport"] }
lettre = { version = "^0.8", path = "../lettre", features = ["smtp-transport"] }
glob = "0.2"
[dependencies]
email = "^0.0"
mime = "^0.3"
time = "^0.1"
uuid = { version = ">=0.4, <0.6", features = ["v4"] }
lettre = { path = "../lettre", default-features = false }
uuid = { version = "^0.6", features = ["v4"] }
lettre = { version = "^0.8", path = "../lettre", default-features = false }
base64 = "^0.9"

View File

@@ -14,7 +14,7 @@ fn main() {
.from("user@example.com")
.subject("Hi, Hello world")
.text("Hello world.")
.attachment(Path::new("Cargo.toml"), None, mime::TEXT_PLAIN).unwrap()
.attachment(Path::new("Cargo.toml"), None, &mime::TEXT_PLAIN).unwrap()
.build()
.unwrap();

View File

@@ -1 +0,0 @@
../rustfmt.toml

View File

@@ -2,16 +2,16 @@
use self::Error::*;
use std::error::Error as StdError;
use std::io;
use std::fmt::{self, Display, Formatter};
use std::io;
use lettre;
/// An enum of all error kinds.
#[derive(Debug)]
pub enum Error {
/// Missing sender
MissingFrom,
/// Missing recipient
MissingTo,
/// Envelope error
Email(lettre::Error),
/// Unparseable filename for attachment
CannotParseFilename,
/// IO error
@@ -27,8 +27,7 @@ impl Display for Error {
impl StdError for Error {
fn description(&self) -> &str {
match *self {
MissingFrom => "the sender is missing",
MissingTo => "the recipient is missing",
Email(ref err) => err.description(),
CannotParseFilename => "the attachment filename could not be parsed",
Io(ref err) => err.description(),
}
@@ -41,3 +40,8 @@ impl From<io::Error> for Error {
}
}
impl From<lettre::Error> for Error {
fn from(err: lettre::Error) -> Error {
Email(err)
}
}

View File

@@ -1,76 +1,30 @@
//! 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::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.
//! Lettre is a mailer written in Rust. lettre_email provides a simple email builder.
//!
#![deny(missing_docs, unsafe_code, unstable_features, warnings, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/lettre_email/0.8.1")]
#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
unused_qualifications)]
extern crate base64;
extern crate email as email_format;
extern crate lettre;
extern crate mime;
extern crate time;
extern crate uuid;
extern crate email as email_format;
extern crate lettre;
pub mod error;
pub use email_format::{Address, Header, Mailbox, MimeMessage, MimeMultipartType};
use error::Error;
use lettre::{EmailAddress, SendableEmail};
use lettre::{EmailAddress, Envelope, Error as EmailError, SendableEmail};
use mime::Mime;
use time::{Tm, now};
use uuid::Uuid;
use std::fs::File;
use std::path::Path;
use std::io::Read;
use std::path::Path;
use time::{now, Tm};
use uuid::Uuid;
use std::str::FromStr;
/// Converts an address or an address with an alias to a `Header`
pub trait IntoHeader {
@@ -169,7 +123,6 @@ impl IntoEmail for SimpleEmail {
}
}
/// Simple representation of an email, useful for some transports
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct SimpleEmail {
@@ -322,7 +275,6 @@ impl Default for PartBuilder {
}
}
/// Builds an `Email` structure
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct EmailBuilder {
@@ -346,43 +298,6 @@ pub struct EmailBuilder {
date_issued: bool,
}
/// Simple email enveloppe representation
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct Envelope {
/// The envelope recipients' addresses
pub to: Vec<String>,
/// The envelope sender address
pub from: String,
}
impl Envelope {
/// Constructs an envelope with no receivers and an empty sender
pub fn new() -> Self {
Envelope {
to: vec![],
from: String::new(),
}
}
/// Adds a receiver
pub fn to<S: Into<String>>(mut self, address: S) -> Self {
self.add_to(address);
self
}
/// Adds a receiver
pub fn add_to<S: Into<String>>(&mut self, address: S) {
self.to.push(address.into());
}
/// Sets the sender
pub fn from<S: Into<String>>(mut self, address: S) -> Self {
self.set_from(address);
self
}
/// Sets the sender
pub fn set_from<S: Into<String>>(&mut self, address: S) {
self.from = address.into();
}
}
/// Simple email representation
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Email {
@@ -397,7 +312,9 @@ pub struct Email {
impl PartBuilder {
/// Creates a new empty part
pub fn new() -> PartBuilder {
PartBuilder { message: MimeMessage::new_blank_message() }
PartBuilder {
message: MimeMessage::new_blank_message(),
}
}
/// Adds a generic header
@@ -434,13 +351,13 @@ impl PartBuilder {
}
/// Adds a `ContentType` header with the given MIME type
pub fn content_type(mut self, content_type: Mime) -> PartBuilder {
pub fn content_type(mut self, content_type: &Mime) -> PartBuilder {
self.set_content_type(content_type);
self
}
/// Adds a `ContentType` header with the given MIME type
pub fn set_content_type(&mut self, content_type: Mime) {
pub fn set_content_type(&mut self, content_type: &Mime) {
self.add_header(("Content-Type", format!("{}", content_type).as_ref()));
}
@@ -580,9 +497,8 @@ impl EmailBuilder {
/// Adds a `Subject` header
pub fn set_subject<S: Into<String>>(&mut self, subject: S) {
self.message.add_header(
("Subject".to_string(), subject.into()),
);
self.message
.add_header(("Subject".to_string(), subject.into()));
}
/// Adds a `Date` header with the given date
@@ -593,26 +509,35 @@ impl EmailBuilder {
/// Adds a `Date` header with the given date
pub fn set_date(&mut self, date: &Tm) {
self.message.add_header(
("Date", Tm::rfc822z(date).to_string()),
);
self.message
.add_header(("Date", Tm::rfc822z(date).to_string()));
self.date_issued = true;
}
/// Adds an attachment to the email
pub fn attachment(mut self, path: &Path, filename: Option<&str>, content_type: Mime) -> Result<EmailBuilder, Error> {
pub fn attachment(
mut self,
path: &Path,
filename: Option<&str>,
content_type: &Mime,
) -> Result<EmailBuilder, Error> {
self.set_attachment(path, filename, content_type)?;
Ok(self)
}
/// Adds an attachment to the email
/// If filename is not provided, the name of the file will be used.
pub fn set_attachment(&mut self, path: &Path, filename: Option<&str>, content_type: Mime) -> Result<(), Error> {
let file = File::open(path);
pub fn set_attachment(
&mut self,
path: &Path,
filename: Option<&str>,
content_type: &Mime,
) -> Result<(), Error> {
let file = File::open(path);
let body = match file {
Ok(mut f) => {
let mut data = String::new();
let read = f.read_to_string(&mut data);
let mut data = Vec::new();
let read = f.read_to_end(&mut data);
match read {
Ok(_) => data,
Err(e) => {
@@ -636,10 +561,15 @@ impl EmailBuilder {
},
};
let encoded_body = base64::encode(&body);
let content = PartBuilder::new()
.body(body)
.header(("Content-Disposition", format!("attachment; filename=\"{}\"", actual_filename)))
.body(encoded_body)
.header((
"Content-Disposition",
format!("attachment; filename=\"{}\"", actual_filename),
))
.header(("Content-Type", content_type.to_string()))
.header(("Content-Transfer-Encoding", "base64"))
.build();
self.set_message_type(MimeMultipartType::Mixed);
@@ -678,11 +608,14 @@ impl EmailBuilder {
/// Sets the email body to plain text content
pub fn set_text<S: Into<String>>(&mut self, body: S) {
self.message.set_body(body);
self.message.add_header((
"Content-Type",
format!("{}", mime::TEXT_PLAIN_UTF_8).as_ref(),
));
let text = PartBuilder::new()
.body(body)
.header((
"Content-Type",
format!("{}", mime::TEXT_PLAIN_UTF_8).as_ref(),
))
.build();
self.add_child(text);
}
/// Sets the email body to HTML content
@@ -693,11 +626,14 @@ impl EmailBuilder {
/// Sets the email body to HTML content
pub fn set_html<S: Into<String>>(&mut self, body: S) {
self.message.set_body(body);
self.message.add_header((
"Content-Type",
format!("{}", mime::TEXT_HTML).as_ref(),
));
let html = PartBuilder::new()
.body(body)
.header((
"Content-Type",
format!("{}", mime::TEXT_HTML_UTF_8).as_ref(),
))
.build();
self.add_child(html);
}
/// Sets the email content
@@ -729,7 +665,10 @@ impl EmailBuilder {
let html = PartBuilder::new()
.body(body_html)
.header(("Content-Type", format!("{}", mime::TEXT_HTML).as_ref()))
.header((
"Content-Type",
format!("{}", mime::TEXT_HTML_UTF_8).as_ref(),
))
.build();
alternate.add_child(text);
@@ -780,72 +719,63 @@ impl EmailBuilder {
Some(e) => e,
None => {
// we need to generate the envelope
let mut e = Envelope::new();
let mut e = Envelope::builder();
// add all receivers in to_header and cc_header
for receiver in self.to_header.iter().chain(self.cc_header.iter()).chain(
self.bcc_header.iter(),
)
for receiver in self.to_header
.iter()
.chain(self.cc_header.iter())
.chain(self.bcc_header.iter())
{
match *receiver {
Address::Mailbox(ref m) => e.add_to(m.address.clone()),
Address::Group(_, ref ms) => {
for m in ms.iter() {
e.add_to(m.address.clone());
}
}
Address::Mailbox(ref m) => e.add_to(EmailAddress::from_str(&m.address)?),
Address::Group(_, ref ms) => for m in ms.iter() {
e.add_to(EmailAddress::from_str(&m.address.clone())?);
},
}
}
if e.to.is_empty() {
return Err(Error::MissingTo);
}
e.set_from(match self.sender_header {
e.set_from(EmailAddress::from_str(&match self.sender_header {
Some(x) => x.address.clone(), // if we have a sender_header, use it
None => {
// use a from header
debug_assert!(self.from_header.len()<=1); // else we'd have sender_header
debug_assert!(self.from_header.len() <= 1); // else we'd have sender_header
match self.from_header.first() {
Some(a) => match *a {
// if we have a from header
Address::Mailbox(ref mailbox) => mailbox.address.clone(), // use it
Address::Group(_,ref mailbox_list) => match mailbox_list.first() {
Address::Group(_, ref mailbox_list) => match mailbox_list.first() {
// if it's an author group, use the first author
Some(mailbox) => mailbox.address.clone(),
// for an empty author group (the rarest of the rare cases)
None => return Err(Error::MissingFrom), // empty envelope sender
None => return Err(Error::Email(EmailError::MissingFrom)), // empty envelope sender
},
},
// if we don't have a from header
None => return Err(Error::MissingFrom), // empty envelope sender
None => return Err(Error::Email(EmailError::MissingFrom)), // empty envelope sender
}
}
});
e
})?);
e.build()?
}
};
// Add the collected addresses as mailbox-list all at once.
// The unwraps are fine because the conversions for Vec<Address> never errs.
if !self.to_header.is_empty() {
self.message.add_header(
Header::new_with_value(
"To".into(),
self.to_header,
).unwrap(),
);
self.message
.add_header(Header::new_with_value("To".into(), self.to_header).unwrap());
}
if !self.from_header.is_empty() {
self.message.add_header(
Header::new_with_value("From".into(), self.from_header).unwrap(),
);
self.message
.add_header(Header::new_with_value("From".into(), self.from_header).unwrap());
} else {
return Err(Error::MissingFrom);
return Err(Error::Email(EmailError::MissingFrom));
}
if !self.cc_header.is_empty() {
self.message.add_header(
Header::new_with_value(
"Cc".into(),
self.cc_header,
).unwrap(),
);
self.message
.add_header(Header::new_with_value("Cc".into(), self.cc_header).unwrap());
}
if !self.bcc_header.is_empty() {
self.message
.add_header(Header::new_with_value("Bcc".into(), self.bcc_header).unwrap());
}
if !self.reply_to_header.is_empty() {
self.message.add_header(
@@ -854,10 +784,8 @@ impl EmailBuilder {
}
if !self.date_issued {
self.message.add_header((
"Date",
Tm::rfc822z(&now()).to_string().as_ref(),
));
self.message
.add_header(("Date", Tm::rfc822z(&now()).to_string().as_ref()));
}
self.message.add_header(("MIME-Version", "1.0"));
@@ -867,34 +795,25 @@ impl EmailBuilder {
if let Ok(header) = Header::new_with_value(
"Message-ID".to_string(),
format!("<{}.lettre@localhost>", message_id),
)
{
) {
self.message.add_header(header)
}
Ok(Email {
message: self.message.build().as_string().into_bytes(),
envelope: envelope,
message_id: message_id,
envelope,
message_id,
})
}
}
impl<'a> SendableEmail<'a, &'a [u8]> for Email {
fn to(&self) -> Vec<EmailAddress> {
self.envelope
.to
.iter()
.map(|x| EmailAddress::new(x.clone()))
.collect()
}
fn from(&self) -> EmailAddress {
EmailAddress::new(self.envelope.from.clone())
fn envelope(&self) -> Envelope {
self.envelope.clone()
}
fn message_id(&self) -> String {
format!("{}", self.message_id)
self.message_id.to_string()
}
fn message(&'a self) -> Box<&[u8]> {
@@ -926,45 +845,12 @@ pub trait ExtractableEmail {
fn text(self) -> String;
}
#[cfg(test)]
mod test {
use super::{EmailBuilder, IntoEmail, SimpleEmail};
use super::EmailBuilder;
use lettre::{EmailAddress, SendableEmail};
use time::now;
#[test]
fn test_simple_email_builder() {
let email_builder = SimpleEmail::default();
let date_now = now();
let email = email_builder
.to("user@localhost")
.from("user@localhost")
.cc(("cc@localhost", "Alias"))
.reply_to("reply@localhost")
.text("Hello World!")
.date(date_now.clone())
.subject("Hello")
.header(("X-test", "value"))
.into_email()
.unwrap();
assert_eq!(
format!("{}", String::from_utf8_lossy(email.message().as_ref())),
format!(
"Subject: Hello\r\nContent-Type: text/plain; \
charset=utf-8\r\nX-test: value\r\nTo: <user@localhost>\r\nFrom: \
<user@localhost>\r\nCc: \"Alias\" <cc@localhost>\r\nReply-To: \
<reply@localhost>\r\nDate: {}\r\nMIME-Version: 1.0\r\nMessage-ID: \
<{}.lettre@localhost>\r\n\r\nHello World!\r\n",
date_now.rfc822z(),
email.message_id()
)
);
}
#[test]
fn test_multiple_from() {
let email_builder = EmailBuilder::new();
@@ -1000,6 +886,7 @@ mod test {
.to("user@localhost")
.from("user@localhost")
.cc(("cc@localhost", "Alias"))
.bcc("bcc@localhost")
.reply_to("reply@localhost")
.sender("sender@localhost")
.body("Hello World!")
@@ -1014,8 +901,9 @@ mod test {
format!(
"Date: {}\r\nSubject: Hello\r\nX-test: value\r\nSender: \
<sender@localhost>\r\nTo: <user@localhost>\r\nFrom: \
<user@localhost>\r\nCc: \"Alias\" <cc@localhost>\r\nReply-To: \
<reply@localhost>\r\nMIME-Version: 1.0\r\nMessage-ID: \
<user@localhost>\r\nCc: \"Alias\" <cc@localhost>\r\n\
Bcc: <bcc@localhost>\r\nReply-To: <reply@localhost>\r\n\
MIME-Version: 1.0\r\nMessage-ID: \
<{}.lettre@localhost>\r\n\r\nHello World!\r\n",
date_now.rfc822z(),
email.message_id()
@@ -1042,14 +930,17 @@ mod test {
.build()
.unwrap();
assert_eq!(email.from().to_string(), "sender@localhost".to_string());
assert_eq!(
email.to(),
email.envelope().from().unwrap().to_string(),
"sender@localhost".to_string()
);
assert_eq!(
email.envelope().to(),
vec![
EmailAddress::new("user@localhost".to_string()),
EmailAddress::new("cc@localhost".to_string()),
EmailAddress::new("bcc@localhost".to_string()),
]
EmailAddress::new("user@localhost".to_string()).unwrap(),
EmailAddress::new("cc@localhost".to_string()).unwrap(),
EmailAddress::new("bcc@localhost".to_string()).unwrap(),
].as_slice()
);
}

View File

@@ -0,0 +1,48 @@
extern crate glob;
use self::glob::glob;
use std::env::consts::EXE_EXTENSION;
use std::env;
use std::path::Path;
use std::process::Command;
#[test]
fn book_test() {
let mut book_path = env::current_dir().unwrap();
book_path.push(
Path::new(file!())
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.join("../website/content/creating-messages"),
); // For some reasons, calling .parent() once more gives us None...
for md in glob(&format!("{}/*.md", book_path.to_str().unwrap())).unwrap() {
skeptic_test(&md.unwrap());
}
}
fn skeptic_test(path: &Path) {
let rustdoc = Path::new("rustdoc").with_extension(EXE_EXTENSION);
let exe = env::current_exe().unwrap();
let depdir = exe.parent().unwrap();
let mut cmd = Command::new(rustdoc);
cmd.args(&["--verbose", "--test"])
.arg("-L")
.arg(&depdir)
.arg(path);
let result = cmd.spawn()
.expect("Failed to spawn process")
.wait()
.expect("Failed to run process");
assert!(
result.success(),
format!("Failed to run rustdoc tests on {:?}!", path)
);
}

View File

@@ -1,3 +0,0 @@
write_mode = "Overwrite"
reorder_imports = true
reorder_imported_names = true

View File

@@ -1,4 +1,3 @@
#!/bin/sh
hugo
lunr-hugo -i "content/**/*.md" -o ../docs/json/search.json -l toml
lunr-hugo -i "content/**/*.md" -o ../docs/index.json -l toml

View File

@@ -1,4 +1,4 @@
baseURL = "https://lettre.github.io/lettre/"
baseURL = "http://docs.lettre.at/"
languageCode = "en-us"
title = "Lettre site"
theme = "hugo-theme-learn"

View File

@@ -7,3 +7,5 @@ weight = 2
+++
### Creating messages
This section explains how to create emails.

View File

@@ -0,0 +1,69 @@
+++
date = "2018-01-21T23:46:17+02:00"
title = "Email creation"
toc = true
weight = 4
+++
#### Simple example
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
extern crate lettre_email;
use lettre_email::EmailBuilder;
fn main() {
// 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.
#### Complete example
Below is a more complete example, not using method chaining:
```rust
extern crate lettre_email;
use lettre_email::EmailBuilder;
fn main() {
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.

View File

@@ -7,8 +7,8 @@ weight = 1
+++
{{% notice note %}}
This documentation is written for lettre 0.7.
Please use https://docs.rs/lettre/0.6.2/lettre/ for lettre 0.6.
This documentation is written for lettre 0.8.
Please use https://docs.rs/lettre/0.7.0/lettre/ for lettre 0.7.
{{% /notice%}}
Lettre is an email library that allows creating and sending messages. It provides:

View File

@@ -11,22 +11,26 @@ The file transport writes the emails to the given directory. The name of the fil
It can be useful for testing purposes, or if you want to keep track of sent messages.
```rust
extern crate lettre;
use std::env::temp_dir;
use lettre::file::FileEmailTransport;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
use lettre::{SimpleSendableEmail, EmailTransport};
// Write to the local temp directory
let mut sender = FileEmailTransport::new(temp_dir());
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
fn main() {
// Write to the local temp directory
let mut sender = FileEmailTransport::new(temp_dir());
let email = SimpleSendableEmail::new(
"user@localhost".to_string(),
&["root@localhost".to_string()],
"message_id".to_string(),
"Hello world".to_string(),
).unwrap();
let result = sender.send(&email);
assert!(result.is_ok());
let result = sender.send(&email);
assert!(result.is_ok());
}
```
Example result in `/tmp/b7c211bc-9811-45ce-8cd9-68eab575d695.txt`:

View File

@@ -12,7 +12,7 @@ emails have to implement `SendableEmail`, which is the case for emails created w
The following transports are available:
* The `SmtpTransport` uses the SMTP protocol to send the message over the network. It is
the prefered way of sending emails.
the preferred way of sending emails.
* The `SendmailTransport` uses the sendmail command to send messages. It is an alternative to
the SMTP transport.
* The `FileTransport` creates a file containing the email content to be sent. It can be used

View File

@@ -8,18 +8,22 @@ weight = 3
The sendmail transport sends the email using the local sendmail command.
``` rust
```rust,no_run
extern crate lettre;
use lettre::sendmail::SendmailTransport;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
use lettre::{SimpleSendableEmail, EmailTransport};
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
fn main() {
let email = SimpleSendableEmail::new(
"user@localhost".to_string(),
&["root@localhost".to_string()],
"message_id".to_string(),
"Hello world".to_string(),
).unwrap();
let mut sender = SendmailTransport::new();
let result = sender.send(&email);
assert!(result.is_ok());
let mut sender = SendmailTransport::new();
let result = sender.send(&email);
assert!(result.is_ok());
}
```

View File

@@ -8,10 +8,10 @@ weight = 2
This transport uses the SMTP protocol to send emails over the network (locally or remotely).
It is desinged to be:
It is designed to be:
* Secured: email are encrypted by default
* Modern: Unicode support for email content and sender/recipient adresses when compatible
* Modern: Unicode support for email content and sender/recipient addresses when compatible
* Fast: supports tcp connection reuse
This client is designed to send emails to a relay server, and should *not* be used to send
@@ -23,64 +23,70 @@ The relay server can be the local email server, a specific host or a third-party
This is the most basic example of usage:
``` rust
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};
```rust,no_run
extern crate lettre;
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
use lettre::{SimpleSendableEmail, EmailTransport, SmtpTransport};
// Open a local connection on port 25
let mut mailer =
SmtpTransport::builder_unencrypted_localhost().unwrap().build();
// Send the email
let result = mailer.send(&email);
fn main() {
let email = SimpleSendableEmail::new(
"user@localhost".to_string(),
&["root@localhost".to_string()],
"message_id".to_string(),
"Hello world".to_string(),
).unwrap();
assert!(result.is_ok());
// Open a local connection on port 25
let mut mailer =
SmtpTransport::builder_unencrypted_localhost().unwrap().build();
// Send the email
let result = mailer.send(&email);
assert!(result.is_ok());
}
```
#### Complete example
``` rust
```rust,no_run
extern crate lettre;
use lettre::smtp::authentication::{Credentials, Mechanism};
use lettre::smtp::SUBMISSION_PORT;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress, SmtpTransport};
use lettre::{SimpleSendableEmail, EmailTransport, SmtpTransport};
use lettre::smtp::extension::ClientId;
use lettre::smtp::ConnectionReuseParameters;
fn main() {
let email = SimpleSendableEmail::new(
"user@localhost".to_string(),
&["root@localhost".to_string()],
"message_id".to_string(),
"Hello world".to_string(),
).unwrap();
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
// Connect to a remote server on a custom port
let mut mailer = SmtpTransport::simple_builder("server.tld").unwrap()
// Set the name sent during EHLO/HELO, default is `localhost`
.hello_name(ClientId::Domain("my.hostname.tld".to_string()))
// Add credentials for authentication
.credentials(Credentials::new("username".to_string(), "password".to_string()))
// Enable SMTPUTF8 if the server supports it
.smtp_utf8(true)
// Configure expected authentication mechanism
.authentication_mechanism(Mechanism::Plain)
// Enable connection reuse
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();
// Connect to a remote server on a custom port
let mut mailer = SmtpTransport::simple_builder("server.tld".to_string()).unwrap()
// Set the name sent during EHLO/HELO, default is `localhost`
.hello_name(ClientId::Domain("my.hostname.tld".to_string()))
// Add credentials for authentication
.credentials(Credentials::new("username".to_string(), "password".to_string()))
// Enable SMTPUTF8 if the server supports it
.smtp_utf8(true)
// Configure expected authentication mechanism
.authentication_mechanism(Mechanism::Plain)
// Enable connection reuse
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited).build();
let result_1 = mailer.send(&email);
assert!(result_1.is_ok());
let result_1 = mailer.send(&email);
assert!(result_1.is_ok());
// The second email will use the same connection
let result_2 = mailer.send(&email);
assert!(result_2.is_ok());
// The second email will use the same connection
let result_2 = mailer.send(&email);
assert!(result_2.is_ok());
// Explicitly close the SMTP transaction as we enabled connection reuse
mailer.close();
// Explicitly close the SMTP transaction as we enabled connection reuse
mailer.close();
}
```
#### Lower level
@@ -88,7 +94,9 @@ mailer.close();
You can also send commands, here is a simple email transaction without
error handling:
``` rust
```rust,no_run
extern crate lettre;
use lettre::EmailAddress;
use lettre::smtp::SMTP_PORT;
use lettre::smtp::client::Client;
@@ -96,17 +104,19 @@ use lettre::smtp::client::net::NetworkStream;
use lettre::smtp::extension::ClientId;
use lettre::smtp::commands::*;
let mut email_client: Client<NetworkStream> = Client::new();
let _ = email_client.connect(&("localhost", SMTP_PORT), None);
let _ = email_client.smtp_command(EhloCommand::new(ClientId::new("my_hostname".to_string())));
let _ = email_client.smtp_command(
MailCommand::new(Some(EmailAddress::new("user@example.com".to_string())), vec![])
);
let _ = email_client.smtp_command(
RcptCommand::new(EmailAddress::new("user@example.org".to_string()), vec![])
);
let _ = email_client.smtp_command(DataCommand);
let _ = email_client.message(Box::new("Test email".as_bytes()));
let _ = email_client.smtp_command(QuitCommand);
fn main() {
let mut email_client: Client<NetworkStream> = Client::new();
let _ = email_client.connect(&("localhost", SMTP_PORT), None);
let _ = email_client.command(EhloCommand::new(ClientId::new("my_hostname".to_string())));
let _ = email_client.command(
MailCommand::new(Some(EmailAddress::new("user@example.com".to_string()).unwrap()), vec![])
);
let _ = email_client.command(
RcptCommand::new(EmailAddress::new("user@example.org".to_string()).unwrap(), vec![])
);
let _ = email_client.command(DataCommand);
let _ = email_client.message(Box::new("Test email".as_bytes()));
let _ = email_client.command(QuitCommand);
}
```

View File

@@ -9,20 +9,24 @@ weight = 5
The stub transport only logs message envelope and drops the content. It can be useful for
testing purposes.
``` rust
```rust
extern crate lettre;
use lettre::stub::StubEmailTransport;
use lettre::{SimpleSendableEmail, EmailTransport, EmailAddress};
use lettre::{SimpleSendableEmail, EmailTransport};
let email = SimpleSendableEmail::new(
EmailAddress::new("user@localhost".to_string()),
vec![EmailAddress::new("root@localhost".to_string())],
"message_id".to_string(),
"Hello world".to_string(),
);
fn main() {
let email = SimpleSendableEmail::new(
"user@localhost".to_string(),
&["root@localhost".to_string()],
"message_id".to_string(),
"Hello world".to_string(),
).unwrap();
let mut sender = StubEmailTransport::new_positive();
let result = sender.send(&email);
assert!(result.is_ok());
let mut sender = StubEmailTransport::new_positive();
let result = sender.send(&email);
assert!(result.is_ok());
}
```
Will log (when using a logger like `env_logger`):

View File

@@ -1,2 +1,3 @@
.DS_Store
public/
exampleSite/public

Some files were not shown because too many files have changed in this diff Show More