mail: update to lettre-0.10.0-rc.5 and adapt

This commit is contained in:
Vincent Breitmoser 2022-04-09 13:27:17 +02:00
parent 39fae28f53
commit 55ec155b30
4 changed files with 62 additions and 118 deletions

74
Cargo.lock generated
View File

@ -56,12 +56,6 @@ dependencies = [
"term", "term",
] ]
[[package]]
name = "ascii_utils"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.2" version = "0.3.2"
@ -166,12 +160,6 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "base64"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.0" version = "0.13.0"
@ -506,18 +494,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]] [[package]]
name = "email" name = "email-encoding"
version = "0.0.20" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91549a51bb0241165f13d57fc4c72cef063b4088fb078b019ecbf464a45f22e4" checksum = "6690291166824e467790ac08ba42f241791567e8337bbf00c5a6e87889629f98"
dependencies = [ dependencies = [
"base64 0.9.3", "base64 0.13.0",
"chrono",
"encoding",
"lazy_static",
"rand 0.4.6",
"time 0.1.43",
"version_check 0.1.5",
] ]
[[package]] [[package]]
@ -615,12 +597,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]] [[package]]
name = "fast_chemail" name = "fastrand"
version = "0.9.6" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4" checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [ dependencies = [
"ascii_utils", "instant",
] ]
[[package]] [[package]]
@ -944,7 +926,6 @@ dependencies = [
"multipart", "multipart",
"num_cpus", "num_cpus",
"regex", "regex",
"rfc2047",
"ring", "ring",
"rocket", "rocket",
"rocket_codegen", "rocket_codegen",
@ -1356,17 +1337,19 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "lettre" name = "lettre"
version = "0.10.0-pre" version = "0.10.0-rc.5"
source = "git+https://github.com/lettre/lettre?rev=245c600c82ee18b766e8729f005ff453a55dce34#245c600c82ee18b766e8729f005ff453a55dce34" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5144148f337be14dabfc0f0d85b691a68ac6c77ef22a5c47c5504b70a7c9fcf3"
dependencies = [ dependencies = [
"base64 0.11.0", "base64 0.13.0",
"email", "email-encoding",
"fast_chemail", "fastrand",
"log 0.4.14", "httpdate",
"idna 0.2.3",
"mime 0.3.16", "mime 0.3.16",
"serde", "once_cell",
"serde_json", "quoted_printable",
"time 0.2.27", "regex",
"uuid 0.8.2", "uuid 0.8.2",
] ]
@ -2097,17 +2080,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "rand" name = "quoted_printable"
version = "0.4.6" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "rand" name = "rand"
@ -2379,12 +2355,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "rfc2047"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6986b5de4fa30c92b50020fdedf45bf9296d9842df4355b62f92dcc18bcdee15"
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.13.5" version = "0.13.5"

View File

@ -39,8 +39,8 @@ gettext-macros = "0.6.1"
gettext-utils = "0.1" gettext-utils = "0.1"
gettext = "0.4" gettext = "0.4"
glob = "0.3" glob = "0.3"
rfc2047 = "0.1"
hyperx = "1.4" hyperx = "1.4"
lettre = { version = "0.10.0-rc.5", default-features = false, features = ["builder", "file-transport", "sendmail-transport"] }
[dependencies.rocket_i18n] [dependencies.rocket_i18n]
git = "https://github.com/Plume-org/rocket_i18n" git = "https://github.com/Plume-org/rocket_i18n"
@ -48,14 +48,6 @@ branch = "go-async"
default-features = false default-features = false
features = ["rocket"] features = ["rocket"]
[dependencies.lettre]
version = "0.10.0-pre"
default-features = false
# smtp-transport doesn't build (openssl problem)
features = ["builder", "file-transport", "sendmail-transport"]
git = "https://github.com/lettre/lettre"
rev = "245c600c82ee18b766e8729f005ff453a55dce34"
[build-dependencies] [build-dependencies]
vergen = "3" vergen = "3"

View File

@ -2,16 +2,14 @@ use std::path::{Path, PathBuf};
use crate::counters; use crate::counters;
use handlebars::Handlebars; use handlebars::Handlebars;
use lettre::builder::{EmailBuilder, Mailbox, MimeMultipartType, PartBuilder}; use lettre::message::{Mailbox, MultiPart, SinglePart, header};
use lettre::{file::FileTransport, SendmailTransport, Transport as LettreTransport}; use lettre::{FileTransport, SendmailTransport, Transport as LettreTransport};
use serde::Serialize; use serde::Serialize;
use uuid::Uuid; use uuid::Uuid;
use gettext_macros::i18n; use gettext_macros::i18n;
use rocket_i18n::I18n; use rocket_i18n::I18n;
use rfc2047::rfc2047_encode;
use crate::template_helpers; use crate::template_helpers;
use crate::database::types::Email; use crate::database::types::Email;
@ -81,8 +79,9 @@ impl Service {
.host_str() .host_str()
.ok_or_else(|| anyhow!("No host in base-URI"))? .ok_or_else(|| anyhow!("No host in base-URI"))?
.to_string(); .to_string();
let from = from.parse().map_err(|_| anyhow!("From must be valid email address"))?;
Ok(Self { Ok(Self {
from: from.into(), from,
domain, domain,
templates, templates,
transport, transport,
@ -203,7 +202,7 @@ impl Service {
fn send( fn send(
&self, &self,
to: &[&Email], tos: &[&Email],
subject: &str, subject: &str,
template: &str, template: &str,
locale: &str, locale: &str,
@ -212,46 +211,44 @@ impl Service {
let (html, txt) = self.render_template(template, locale, ctx)?; let (html, txt) = self.render_template(template, locale, ctx)?;
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
for recipient in to.iter() { for recipient in tos.iter() {
println!("To: {}", recipient); println!("To: {}", recipient);
} }
println!("{}", &txt); println!("{}", &txt);
} }
// build this ourselves, as a temporary workaround for https://github.com/lettre/lettre/issues/400 let mut email = lettre::Message::builder()
let text = PartBuilder::new()
.body(txt)
.header(("Content-Type", "text/plain; charset=utf-8"))
.header(("Content-Transfer-Encoding", "8bit"))
.build();
let html = PartBuilder::new()
.body(html)
.header(("Content-Type", "text/html; charset=utf-8"))
.header(("Content-Transfer-Encoding", "8bit"))
.build();
let email = EmailBuilder::new()
.from(self.from.clone()) .from(self.from.clone())
.subject(rfc2047_encode(subject)) .subject(subject)
.message_id(format!("<{}@{}>", Uuid::new_v4(), self.domain)) .message_id(Some(format!("<{}@{}>", Uuid::new_v4(), self.domain)))
.message_type(MimeMultipartType::Alternative) .header(header::ContentTransferEncoding::EightBit);
.header(("Content-Transfer-Encoding", "8bit"))
.child(text)
.child(html);
let email = to.iter().fold(email, |email, to| email.to(to.to_string())); for to in tos.iter() {
email = email.to(to.as_str().parse().unwrap());
}
let email = email.build()?; let email = email.multipart(
MultiPart::alternative()
.singlepart(
SinglePart::builder()
.header(header::ContentTransferEncoding::EightBit)
.header(header::ContentType::TEXT_PLAIN)
.body(txt)
)
.singlepart(SinglePart::builder()
.header(header::ContentTransferEncoding::EightBit)
.header(header::ContentType::TEXT_HTML)
.body(html)),
)?;
match self.transport { match self.transport {
Transport::Sendmail => { Transport::Sendmail => {
let mut transport = SendmailTransport::new(); let transport = SendmailTransport::new();
transport.send(email)?; transport.send(&email)?;
} }
Transport::Filemail(ref path) => { Transport::Filemail(ref path) => {
let mut transport = FileTransport::new(path); let transport = FileTransport::new(path);
transport.send(email)?; transport.send(&email)?;
} }
} }
@ -259,31 +256,17 @@ impl Service {
} }
} }
// for some reason, this is no longer public in lettre itself
// FIXME replace with builtin struct on lettre update
// see https://github.com/lettre/lettre/blob/master/lettre/src/file/mod.rs#L41
#[cfg(test)]
#[derive(Deserialize)]
struct SerializableEmail {
#[serde(alias = "envelope")]
_envelope: lettre::Envelope,
#[serde(alias = "message_id")]
_message_id: String,
message: Vec<u8>,
}
/// Returns and removes the first mail it finds from the given /// Returns and removes the first mail it finds from the given
/// directory. /// directory.
#[cfg(test)] #[cfg(test)]
pub fn pop_mail(dir: &Path) -> Result<Option<String>> { pub fn pop_mail(dir: &Path) -> Result<Option<String>> {
use std::fs; use std::{fs, fs::read_to_string};
for entry in fs::read_dir(dir)? { for entry in fs::read_dir(dir)? {
let entry = entry?; let entry = entry?;
if entry.file_type()?.is_file() { if entry.file_type()?.is_file() {
let fh = fs::File::open(entry.path())?; let body = read_to_string(entry.path())?.replace("\r\n", "\n");
fs::remove_file(entry.path())?; fs::remove_file(entry.path())?;
let mail: SerializableEmail = ::serde_json::from_reader(fh)?; println!("{}", body);
let body = String::from_utf8_lossy(&mail.message).to_string();
return Ok(Some(body)); return Ok(Some(body));
} }
} }
@ -346,15 +329,14 @@ mod test {
(h, v) (h, v)
}) })
.collect(); .collect();
assert!(headers.contains(&("Content-Transfer-Encoding", "8bit")));
assert!(headers.contains(&("Content-Type", "text/plain; charset=utf-8"))); assert!(headers.contains(&("Content-Type", "text/plain; charset=utf-8")));
assert!(headers.contains(&("Content-Type", "text/html; charset=utf-8"))); assert!(headers.contains(&("Content-Type", "text/html; charset=utf-8")));
assert!(headers.contains(&("From", "<test@localhost>"))); assert!(headers.contains(&("From", "test@localhost")));
assert!(headers.contains(&("To", "<recipient@example.org>"))); assert!(headers.contains(&("To", "recipient@example.org")));
assert_header(&headers, "Content-Type", |v| { assert_header(&headers, "Content-Type", |v| {
v.starts_with("multipart/alternative") v.starts_with("multipart/alternative")
}); });
assert_header(&headers, "Date", |v| v.contains("+0000")); assert_header(&headers, "Date", |v| v.contains("-0000"));
assert_header(&headers, "Message-ID", |v| v.contains("@localhost>")); assert_header(&headers, "Message-ID", |v| v.contains("@localhost>"));
} }
@ -413,7 +395,7 @@ mod test {
assert!(mail_content.contains("test/about")); assert!(mail_content.contains("test/about"));
assert!(mail_content.contains("あなたのメールアド")); assert!(mail_content.contains("あなたのメールアド"));
assert!(mail_content.contains( assert!(mail_content.contains(
"Subject: =?utf-8?q?localhost=E3=81=AE=E3=81=82=E3=81=AA=E3=81=9F=E3=81=AE?=" "Subject: =?utf-8?b?bG9jYWxob3N044Gu44GC44Gq44Gf44Gu6Y2144Gu44Gf44KB44GrbG9jYWxob3N044KS5qSc6Ki844GZ44KL?="
)); ));
} }
@ -467,7 +449,7 @@ mod test {
assert!(mail_content.contains("test/about")); assert!(mail_content.contains("test/about"));
assert!(mail_content.contains("この鍵の掲示されたア")); assert!(mail_content.contains("この鍵の掲示されたア"));
assert!(mail_content.contains( assert!(mail_content.contains(
"Subject: =?utf-8?q?localhost=E3=81=AE=E9=8D=B5=E3=82=92=E7=AE=A1=E7=90=86?=" "Subject: =?utf-8?b?bG9jYWxob3N044Gu6Y2144KS566h55CG44GZ44KL?="
)); ));
} }

View File

@ -887,7 +887,7 @@ pub mod tests {
check_verify_link(&client, &token, "foo@invalid.example.com", "de"); check_verify_link(&client, &token, "foo@invalid.example.com", "de");
let mail_content = pop_mail(&filemail_into).unwrap().unwrap(); let mail_content = pop_mail(&filemail_into).unwrap().unwrap();
assert!(mail_content.contains("Dies ist eine automatisierte Nachricht")); assert!(mail_content.contains("Dies ist eine automatisierte Nachricht"));
assert!(mail_content.contains("Subject: =?utf-8?q?Best=C3=A4tige?= foo@invalid.example.com\r\n\t=?utf-8?q?f=C3=BCr?= deinen =?utf-8?q?Schl=C3=BCssel?= auf local.connection")); assert!(mail_content.contains("Subject: =?utf-8?b?QmVzdMOkdGlnZQ==?= foo@invalid.example.com \n =?utf-8?b?ZsO8cg==?= deinen =?utf-8?b?U2NobMO8c3NlbA==?= auf \n local.connection"));
} }
#[test] #[test]