Document mailer and use async lettre
This commit is contained in:
parent
164094c42f
commit
2143da1766
4 changed files with 51 additions and 20 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -541,10 +541,12 @@ version = "0.10.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8033576bf9f051fce6cb92b6264114b4340896c352a9ff38b67bd4cde924635"
|
checksum = "d8033576bf9f051fce6cb92b6264114b4340896c352a9ff38b67bd4cde924635"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
"base64 0.21.0",
|
"base64 0.21.0",
|
||||||
"email-encoding",
|
"email-encoding",
|
||||||
"email_address",
|
"email_address",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
|
"futures-io",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hostname",
|
"hostname",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
|
@ -557,6 +559,7 @@ dependencies = [
|
||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1087,6 +1090,17 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.23.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
"webpki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
|
|
|
@ -12,7 +12,7 @@ askama = { git = "https://github.com/djc/askama.git" }
|
||||||
askama_axum = { git = "https://github.com/djc/askama.git", package = "askama_axum" }
|
askama_axum = { git = "https://github.com/djc/askama.git", package = "askama_axum" }
|
||||||
axum = { version = "0.6", default-features = false, features = ["http1", "form", "tokio", "macros"] }
|
axum = { version = "0.6", default-features = false, features = ["http1", "form", "tokio", "macros"] }
|
||||||
captcha = { version = "0.0.9", default-features = false }
|
captcha = { version = "0.0.9", default-features = false }
|
||||||
lettre = { version = "0.10", default-features = false, features = ["smtp-transport", "hostname", "rustls-tls", "pool", "builder"] }
|
lettre = { version = "0.10", default-features = false, features = ["smtp-transport", "hostname", "tokio1-rustls-tls", "pool", "builder"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
|
|
|
@ -1,29 +1,39 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use lettre::{
|
use lettre::{
|
||||||
message::{Mailbox, MessageBuilder},
|
message::{Mailbox, Message, MessageBuilder},
|
||||||
transport::smtp::authentication::Credentials,
|
transport::{
|
||||||
Message, SmtpTransport, Transport,
|
smtp::{authentication::Credentials, AsyncSmtpTransport},
|
||||||
|
AsyncTransport,
|
||||||
|
},
|
||||||
|
Tokio1Executor,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
|
type ASmtpTransport = AsyncSmtpTransport<Tokio1Executor>;
|
||||||
|
|
||||||
|
/// Mail sender.
|
||||||
pub struct Mailer {
|
pub struct Mailer {
|
||||||
mailer: SmtpTransport,
|
mailer: ASmtpTransport,
|
||||||
message_builder: MessageBuilder,
|
message_builder: MessageBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mailer {
|
impl Mailer {
|
||||||
|
/// Tries to initialize the mailer.
|
||||||
pub fn build(config: &Config) -> Result<Self> {
|
pub fn build(config: &Config) -> Result<Self> {
|
||||||
let creds = Credentials::new(
|
// Mail server credentials for login.
|
||||||
|
let credentials = Credentials::new(
|
||||||
config.email_server.email.clone(),
|
config.email_server.email.clone(),
|
||||||
config.email_server.password.clone(),
|
config.email_server.password.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mailer = SmtpTransport::relay(&config.email_server.server_name)
|
// Establish the connection.
|
||||||
|
let mailer = ASmtpTransport::relay(&config.email_server.server_name)
|
||||||
.context("Failed to connect to the email server!")?
|
.context("Failed to connect to the email server!")?
|
||||||
.credentials(creds)
|
.credentials(credentials)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Set the From and To mailboxes for every sent mail.
|
||||||
let message_builder = Message::builder()
|
let message_builder = Message::builder()
|
||||||
.from(
|
.from(
|
||||||
config
|
config
|
||||||
|
@ -42,13 +52,19 @@ impl Mailer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&self, name: &str, email: &str, telefon: &str, message: &str) -> Result<()> {
|
/// Sends a mail with data from the contact form.
|
||||||
|
pub async fn send(&self, name: &str, email: &str, telefon: &str, message: &str) -> Result<()> {
|
||||||
let name = name.trim().to_string();
|
let name = name.trim().to_string();
|
||||||
|
let subject = "Message from ".to_string() + &name;
|
||||||
|
let reply_to = Mailbox::new(
|
||||||
|
Some(name),
|
||||||
|
email
|
||||||
|
.parse()
|
||||||
|
.context("Failed to parse the email from the form to an address!")?,
|
||||||
|
);
|
||||||
|
|
||||||
let telefon = telefon.trim();
|
let telefon = telefon.trim();
|
||||||
let message = message.trim().to_string();
|
let message = message.trim().to_string();
|
||||||
|
|
||||||
let subject = "Message from ".to_string() + &name;
|
|
||||||
|
|
||||||
let body = if !telefon.is_empty() {
|
let body = if !telefon.is_empty() {
|
||||||
message + "\n\nTelefon: " + telefon
|
message + "\n\nTelefon: " + telefon
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,17 +74,15 @@ impl Mailer {
|
||||||
let email = self
|
let email = self
|
||||||
.message_builder
|
.message_builder
|
||||||
.clone()
|
.clone()
|
||||||
.reply_to(Mailbox::new(
|
.reply_to(reply_to)
|
||||||
Some(name),
|
|
||||||
email
|
|
||||||
.parse()
|
|
||||||
.context("Failed to parse the email from the form to an address!")?,
|
|
||||||
))
|
|
||||||
.subject(subject)
|
.subject(subject)
|
||||||
.body(body)
|
.body(body)
|
||||||
.context("Failed to build email!")?;
|
.context("Failed to build email!")?;
|
||||||
|
|
||||||
self.mailer.send(&email).context("Failed to send email!")?;
|
self.mailer
|
||||||
|
.send(email)
|
||||||
|
.await
|
||||||
|
.context("Failed to send email!")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,10 @@ pub async fn submit(
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
match mailer.send(&form.name, &form.email, &form.telefon, &form.message) {
|
match mailer
|
||||||
|
.send(&form.name, &form.email, &form.telefon, &form.message)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("{e:?}");
|
error!("{e:?}");
|
||||||
|
|
Loading…
Reference in a new issue