152 lines
5.1 KiB
Rust
152 lines
5.1 KiB
Rust
use lettre::{
|
|
transport::smtp::authentication::Credentials,
|
|
AsyncSmtpTransport,
|
|
AsyncTransport,
|
|
Tokio1Executor,
|
|
// Address,
|
|
message::{
|
|
Mailbox,
|
|
header::ContentType,
|
|
MultiPart,
|
|
SinglePart,
|
|
},
|
|
Message,
|
|
};
|
|
|
|
use crate::defs::AppDBs;
|
|
use pasetoken_lib::ConfigPaSeToken;
|
|
use serde_json::json;
|
|
|
|
#[derive(Clone,Debug)]
|
|
pub struct MailMessage {
|
|
pub from: Mailbox,
|
|
pub to: Mailbox,
|
|
pub reply_to: Mailbox,
|
|
}
|
|
|
|
impl MailMessage {
|
|
pub fn new(from: &str, to: &str, reply: &str) -> anyhow::Result<Self> {
|
|
let reply_to = if reply.is_empty() {
|
|
to
|
|
} else {
|
|
reply
|
|
};
|
|
Ok(
|
|
Self {
|
|
from: from.parse()?,
|
|
to: to.parse()?,
|
|
reply_to: reply_to.parse()?,
|
|
}
|
|
)
|
|
}
|
|
pub fn check(app_dbs: &AppDBs) -> String {
|
|
if app_dbs.config.smtp.is_empty() {
|
|
String::from("Error: no mail server")
|
|
} else if app_dbs.config.mail_from.is_empty() {
|
|
String::from("Error: no mail from address")
|
|
} else {
|
|
String::from("")
|
|
}
|
|
}
|
|
#[allow(dead_code)]
|
|
pub async fn send_message(&self, subject: &str, body: &str, app_dbs: &AppDBs) -> std::io::Result<()> {
|
|
match Message::builder()
|
|
.from(self.from.to_owned())
|
|
.reply_to(self.reply_to.to_owned())
|
|
.to(self.to.to_owned())
|
|
.subject(subject)
|
|
.header(ContentType::TEXT_PLAIN)
|
|
.body(body.to_owned())
|
|
{
|
|
Ok(message) => self.mail_message(message, app_dbs).await,
|
|
Err(e) =>
|
|
return Err(std::io::Error::new(
|
|
std::io::ErrorKind::NotFound,
|
|
format!("ERROR: Invalid mail: {}",e)
|
|
))
|
|
}
|
|
}
|
|
pub async fn send_html_message(&self, subject: &str, body: &str, html_body: &str, app_dbs: &AppDBs) -> std::io::Result<()> {
|
|
match Message::builder()
|
|
.from(self.from.to_owned())
|
|
.reply_to(self.reply_to.to_owned())
|
|
.to(self.to.to_owned())
|
|
.subject(subject)
|
|
.multipart(
|
|
MultiPart::alternative() // This is composed of two parts.
|
|
.singlepart(
|
|
SinglePart::builder()
|
|
.header(ContentType::TEXT_PLAIN)
|
|
.body(body.to_owned()),
|
|
)
|
|
.singlepart(
|
|
SinglePart::builder()
|
|
.header(ContentType::TEXT_HTML)
|
|
.body(html_body.to_owned()),
|
|
),
|
|
)
|
|
{
|
|
Ok(message) => self.mail_message(message, app_dbs).await,
|
|
Err(e) =>
|
|
return Err(std::io::Error::new(
|
|
std::io::ErrorKind::NotFound,
|
|
format!("ERROR: Invalid mail: {}",e)
|
|
))
|
|
}
|
|
}
|
|
pub async fn mail_message(&self, message: Message, app_dbs: &AppDBs) -> std::io::Result<()> {
|
|
let mail_cred = crate::defs::MailMessage::get_credentials(&app_dbs.config.smtp_auth, &app_dbs.config.paseto);
|
|
if ! mail_cred.contains("|") {
|
|
return Err(std::io::Error::new(
|
|
std::io::ErrorKind::NotFound,
|
|
format!("ERROR: Invalid mail credentials")
|
|
));
|
|
}
|
|
let auth_data: Vec<String> = mail_cred.split("|").map(|s| s.to_string()).collect();
|
|
if auth_data.len() < 2 {
|
|
return Err(std::io::Error::new(
|
|
std::io::ErrorKind::NotFound,
|
|
format!("ERROR: Invalid mail credentials")
|
|
));
|
|
}
|
|
let creds = Credentials::new(auth_data[0].to_owned(), auth_data[1].to_owned());
|
|
// Open a remote connection to gmail
|
|
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
|
AsyncSmtpTransport::<Tokio1Executor>::relay(&app_dbs.config.smtp)
|
|
.unwrap()
|
|
.credentials(creds)
|
|
.build();
|
|
|
|
// Send the email
|
|
match mailer.send(message).await {
|
|
Ok(_) => Ok(()),
|
|
Err(e) => Err(std::io::Error::new(
|
|
std::io::ErrorKind::NotConnected,
|
|
format!("ERROR: Could not send email: {e:?}")
|
|
))
|
|
}
|
|
}
|
|
pub fn get_credentials(token: &str, paseto_config: &ConfigPaSeToken) -> String {
|
|
match paseto_config.pasetoken() {
|
|
Ok(paseto) => {
|
|
match paseto.trusted(token, false) {
|
|
Ok(trusted_token) => {
|
|
if let Some(claims) = trusted_token.payload_claims() {
|
|
claims.get_claim("smtp_auth").unwrap_or(&json!("")).to_string().replace("\"","")
|
|
} else {
|
|
String::from("")
|
|
}
|
|
},
|
|
Err(e) => {
|
|
println!("Token not trusted: {}",e);
|
|
String::from("")
|
|
},
|
|
}
|
|
},
|
|
Err(e) => {
|
|
println!("Error collecting notify data: {}",e);
|
|
String::from("")
|
|
}
|
|
}
|
|
}
|
|
} |