Updated lettre (and other crates) and workflow.

General:
- Updated several dependancies

Lettre:
- Updateded lettere and the workflow
- Changed encoding to base64
- Convert unix newlines to dos newlines for e-mails.
- Created custom e-mail boundary (auto generated could cause errors)

Tested the e-mails sent using several clients (Linux, Windows, MacOS, Web).
Run msglint (https://tools.ietf.org/tools/msglint/) on the generated e-mails until all errors were gone.

Lettre has changed quite some stuff compared between alpha.1 and alpha.2, i haven't noticed any issues sending e-mails during my tests.
This commit is contained in:
BlackDex
2020-09-11 23:52:20 +02:00
parent a0d92a167c
commit 844cf70345
4 changed files with 139 additions and 172 deletions

View File

@@ -49,7 +49,7 @@ use yubico::yubicoerror::YubicoError as YubiErr;
use lettre::address::AddressError as AddrErr;
use lettre::error::Error as LettreErr;
use lettre::message::mime::FromStrError as FromStrErr;
use lettre::transport::smtp::error::Error as SmtpErr;
use lettre::transport::smtp::Error as SmtpErr;
#[derive(Serialize)]
pub struct Empty {}

View File

@@ -2,14 +2,13 @@ use std::{env, str::FromStr};
use chrono::{DateTime, Local};
use chrono_tz::Tz;
use native_tls::{Protocol, TlsConnector};
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
use lettre::{
message::{header, Mailbox, Message, MultiPart, SinglePart},
transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism},
transport::smtp::extension::ClientId,
Address, SmtpTransport, Tls, TlsParameters, Transport,
Address, SmtpTransport, Transport,
};
use crate::{
@@ -20,28 +19,23 @@ use crate::{
};
fn mailer() -> SmtpTransport {
use std::time::Duration;
let host = CONFIG.smtp_host().unwrap();
let client_security = if CONFIG.smtp_ssl() {
let tls = TlsConnector::builder()
.min_protocol_version(Some(Protocol::Tlsv11))
.build()
.unwrap();
let params = TlsParameters::new(host.clone(), tls);
// Determine security
let smtp_client = if CONFIG.smtp_ssl() {
if CONFIG.smtp_explicit_tls() {
Tls::Wrapper(params)
SmtpTransport::relay(host.as_str())
} else {
Tls::Required(params)
SmtpTransport::starttls_relay(host.as_str())
}
} else {
Tls::None
Ok(SmtpTransport::builder_dangerous(host.as_str()))
};
use std::time::Duration;
let smtp_client = SmtpTransport::builder(host).port(CONFIG.smtp_port()).tls(client_security);
let smtp_client = smtp_client.unwrap()
.port(CONFIG.smtp_port())
.timeout(Some(Duration::from_secs(CONFIG.smtp_timeout())));
let smtp_client = match (CONFIG.smtp_username(), CONFIG.smtp_password()) {
(Some(user), Some(pass)) => smtp_client.credentials(Credentials::new(user, pass)),
@@ -49,7 +43,7 @@ fn mailer() -> SmtpTransport {
};
let smtp_client = match CONFIG.helo_name() {
Some(helo_name) => smtp_client.hello_name(ClientId::new(helo_name)),
Some(helo_name) => smtp_client.hello_name(ClientId::Domain(helo_name)),
None => smtp_client,
};
@@ -66,7 +60,7 @@ fn mailer() -> SmtpTransport {
_ => smtp_client,
};
smtp_client.timeout(Some(Duration::from_secs(CONFIG.smtp_timeout()))).build()
smtp_client.build()
}
fn get_text(template_name: &'static str, data: serde_json::Value) -> Result<(String, String, String), Error> {
@@ -84,8 +78,9 @@ fn get_template(template_name: &str, data: &serde_json::Value) -> Result<(String
None => err!("Template doesn't contain subject"),
};
use newline_converter::unix2dos;
let body = match text_split.next() {
Some(s) => s.trim().to_string(),
Some(s) => unix2dos(s.trim()).to_string(),
None => err!("Template doesn't contain body"),
};
@@ -303,25 +298,18 @@ fn send_email(address: &str, subject: &str, body_html: &str, body_text: &str) ->
let address = format!("{}@{}", address_split[1], domain_puny);
let data = MultiPart::mixed()
.multipart(
MultiPart::alternative()
.singlepart(
SinglePart::quoted_printable()
.header(header::ContentType("text/plain; charset=utf-8".parse()?))
.body(body_text),
)
.multipart(
MultiPart::related().singlepart(
SinglePart::quoted_printable()
.header(header::ContentType("text/html; charset=utf-8".parse()?))
.body(body_html),
)
// .singlepart(SinglePart::base64() -- Inline files would go here
),
)
// .singlepart(SinglePart::base64() -- Attachments would go here
;
let html = SinglePart::base64()
.header(header::ContentType("text/html; charset=utf-8".parse()?))
.body(body_html);
let text = SinglePart::base64()
.header(header::ContentType("text/plain; charset=utf-8".parse()?))
.body(body_text);
// The boundary generated by Lettre it self is mostly too large based on the RFC822, so we generate one our selfs.
use uuid::Uuid;
let boundary = format!("_Part_{}_", Uuid::new_v4().to_simple());
let alternative = MultiPart::alternative().boundary(boundary).singlepart(text).singlepart(html);
let email = Message::builder()
.to(Mailbox::new(None, Address::from_str(&address)?))
@@ -330,7 +318,7 @@ fn send_email(address: &str, subject: &str, body_html: &str, body_text: &str) ->
Address::from_str(&CONFIG.smtp_from())?,
))
.subject(subject)
.multipart(data)?;
.multipart(alternative)?;
let _ = mailer().send(&email)?;
Ok(())