2023-07-10 14:50:07 +00:00
|
|
|
use crate::{
|
|
|
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
|
|
|
settings::structs::Settings,
|
|
|
|
};
|
2022-03-01 14:28:18 +00:00
|
|
|
use html2text;
|
2020-09-14 15:29:50 +00:00
|
|
|
use lettre::{
|
2022-05-08 17:00:12 +00:00
|
|
|
message::{Mailbox, MultiPart},
|
2022-01-26 16:42:43 +00:00
|
|
|
transport::smtp::{authentication::Credentials, extension::ClientId},
|
2020-10-30 17:19:00 +00:00
|
|
|
Address,
|
2023-07-10 12:04:39 +00:00
|
|
|
AsyncTransport,
|
2020-10-30 17:19:00 +00:00
|
|
|
Message,
|
2020-09-14 15:29:50 +00:00
|
|
|
};
|
2020-10-30 17:19:00 +00:00
|
|
|
use std::str::FromStr;
|
2021-10-12 11:38:55 +00:00
|
|
|
use uuid::Uuid;
|
2020-09-14 15:29:50 +00:00
|
|
|
|
2022-03-24 15:25:51 +00:00
|
|
|
pub mod translations {
|
|
|
|
rosetta_i18n::include_translations!();
|
|
|
|
}
|
|
|
|
|
2023-07-10 12:04:39 +00:00
|
|
|
type AsyncSmtpTransport = lettre::AsyncSmtpTransport<lettre::Tokio1Executor>;
|
|
|
|
|
|
|
|
pub async fn send_email(
|
2020-09-14 15:29:50 +00:00
|
|
|
subject: &str,
|
|
|
|
to_email: &str,
|
|
|
|
to_username: &str,
|
|
|
|
html: &str,
|
2021-09-22 15:57:09 +00:00
|
|
|
settings: &Settings,
|
2021-12-15 19:49:59 +00:00
|
|
|
) -> Result<(), LemmyError> {
|
2023-07-10 14:50:07 +00:00
|
|
|
let email_config = settings.email.clone().ok_or(LemmyErrorType::NoEmailSetup)?;
|
2022-11-19 04:33:54 +00:00
|
|
|
let domain = settings.hostname.clone();
|
2020-09-14 15:29:50 +00:00
|
|
|
|
2020-10-30 17:19:00 +00:00
|
|
|
let (smtp_server, smtp_port) = {
|
|
|
|
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
|
2023-02-28 11:34:50 +00:00
|
|
|
let email = *email_and_port
|
|
|
|
.first()
|
2023-07-10 14:50:07 +00:00
|
|
|
.ok_or(LemmyErrorType::MissingAnEmail)?;
|
2023-02-28 11:34:50 +00:00
|
|
|
let port = email_and_port
|
|
|
|
.get(1)
|
2023-07-10 14:50:07 +00:00
|
|
|
.ok_or(LemmyErrorType::EmailSmtpServerNeedsAPort)?
|
2023-02-28 11:34:50 +00:00
|
|
|
.parse::<u16>()?;
|
2021-12-15 19:49:59 +00:00
|
|
|
|
2023-02-28 11:34:50 +00:00
|
|
|
(email, port)
|
2020-10-30 17:19:00 +00:00
|
|
|
};
|
|
|
|
|
2023-06-12 13:29:15 +00:00
|
|
|
// use usize::MAX as the line wrap length, since lettre handles the wrapping for us
|
|
|
|
let plain_text = html2text::from_read(html.as_bytes(), usize::MAX);
|
2022-03-01 14:28:18 +00:00
|
|
|
|
2020-10-30 17:19:00 +00:00
|
|
|
let email = Message::builder()
|
|
|
|
.from(
|
|
|
|
email_config
|
|
|
|
.smtp_from_address
|
|
|
|
.parse()
|
|
|
|
.expect("email from address isn't valid"),
|
|
|
|
)
|
|
|
|
.to(Mailbox::new(
|
|
|
|
Some(to_username.to_string()),
|
|
|
|
Address::from_str(to_email).expect("email to address isn't valid"),
|
|
|
|
))
|
2023-01-30 16:10:51 +00:00
|
|
|
.message_id(Some(format!("<{}@{}>", Uuid::new_v4(), settings.hostname)))
|
2020-09-14 15:29:50 +00:00
|
|
|
.subject(subject)
|
2022-05-08 17:00:12 +00:00
|
|
|
.multipart(MultiPart::alternative_plain_html(
|
|
|
|
plain_text,
|
|
|
|
html.to_string(),
|
|
|
|
))
|
2020-10-30 17:19:00 +00:00
|
|
|
.expect("email built incorrectly");
|
|
|
|
|
|
|
|
// don't worry about 'dangeous'. it's just that leaving it at the default configuration
|
|
|
|
// is bad.
|
|
|
|
|
|
|
|
// Set the TLS
|
2023-07-10 12:04:39 +00:00
|
|
|
let builder_dangerous = AsyncSmtpTransport::builder_dangerous(smtp_server).port(smtp_port);
|
2022-01-26 16:42:43 +00:00
|
|
|
|
|
|
|
let mut builder = match email_config.tls_type.as_str() {
|
2023-07-10 12:04:39 +00:00
|
|
|
"starttls" => AsyncSmtpTransport::starttls_relay(smtp_server)?,
|
|
|
|
"tls" => AsyncSmtpTransport::relay(smtp_server)?,
|
2022-01-26 16:42:43 +00:00
|
|
|
_ => builder_dangerous,
|
|
|
|
};
|
2020-09-14 15:29:50 +00:00
|
|
|
|
2020-10-30 17:19:00 +00:00
|
|
|
// Set the creds if they exist
|
2023-06-21 17:36:42 +00:00
|
|
|
let smtp_password = std::env::var("LEMMY_SMTP_PASSWORD")
|
|
|
|
.ok()
|
|
|
|
.or(email_config.smtp_password);
|
|
|
|
|
|
|
|
if let (Some(username), Some(password)) = (email_config.smtp_login, smtp_password) {
|
2020-10-30 17:19:00 +00:00
|
|
|
builder = builder.credentials(Credentials::new(username, password));
|
|
|
|
}
|
|
|
|
|
|
|
|
let mailer = builder.hello_name(ClientId::Domain(domain)).build();
|
|
|
|
|
2023-07-10 14:50:07 +00:00
|
|
|
mailer
|
|
|
|
.send(email)
|
|
|
|
.await
|
|
|
|
.with_lemmy_type(LemmyErrorType::EmailSendFailed)?;
|
2020-09-14 15:29:50 +00:00
|
|
|
|
2023-07-10 14:50:07 +00:00
|
|
|
Ok(())
|
2020-09-14 15:29:50 +00:00
|
|
|
}
|