2 error::{LemmyError, LemmyErrorExt, LemmyErrorType},
3 settings::structs::Settings,
7 message::{Mailbox, MultiPart},
8 transport::smtp::{authentication::Credentials, extension::ClientId},
13 use std::str::FromStr;
16 pub mod translations {
17 rosetta_i18n::include_translations!();
20 type AsyncSmtpTransport = lettre::AsyncSmtpTransport<lettre::Tokio1Executor>;
22 pub async fn send_email(
28 ) -> Result<(), LemmyError> {
29 let email_config = settings.email.clone().ok_or(LemmyErrorType::NoEmailSetup)?;
30 let domain = settings.hostname.clone();
32 let (smtp_server, smtp_port) = {
33 let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
34 let email = *email_and_port
36 .ok_or(LemmyErrorType::MissingAnEmail)?;
37 let port = email_and_port
39 .ok_or(LemmyErrorType::EmailSmtpServerNeedsAPort)?
45 // use usize::MAX as the line wrap length, since lettre handles the wrapping for us
46 let plain_text = html2text::from_read(html.as_bytes(), usize::MAX);
48 let email = Message::builder()
53 .expect("email from address isn't valid"),
56 Some(to_username.to_string()),
57 Address::from_str(to_email).expect("email to address isn't valid"),
59 .message_id(Some(format!("<{}@{}>", Uuid::new_v4(), settings.hostname)))
61 .multipart(MultiPart::alternative_plain_html(
65 .expect("email built incorrectly");
67 // don't worry about 'dangeous'. it's just that leaving it at the default configuration
71 let builder_dangerous = AsyncSmtpTransport::builder_dangerous(smtp_server).port(smtp_port);
73 let mut builder = match email_config.tls_type.as_str() {
74 "starttls" => AsyncSmtpTransport::starttls_relay(smtp_server)?,
75 "tls" => AsyncSmtpTransport::relay(smtp_server)?,
76 _ => builder_dangerous,
79 // Set the creds if they exist
80 let smtp_password = std::env::var("LEMMY_SMTP_PASSWORD")
82 .or(email_config.smtp_password);
84 if let (Some(username), Some(password)) = (email_config.smtp_login, smtp_password) {
85 builder = builder.credentials(Credentials::new(username, password));
88 let mailer = builder.hello_name(ClientId::Domain(domain)).build();
93 .with_lemmy_type(LemmyErrorType::EmailSendFailed)?;