mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-03-25 21:02:40 +00:00
* Use connection url for configure email (fixes #5472) * clippy
This commit is contained in:
parent
a6507c169d
commit
1e02dea397
5 changed files with 19 additions and 63 deletions
|
@ -70,16 +70,10 @@
|
||||||
}
|
}
|
||||||
# Email sending configuration. All options except login/password are mandatory
|
# Email sending configuration. All options except login/password are mandatory
|
||||||
email: {
|
email: {
|
||||||
# Hostname and port of the smtp server
|
# https://docs.rs/lettre/0.11.14/lettre/transport/smtp/struct.AsyncSmtpTransport.html#method.from_url
|
||||||
smtp_server: "localhost:25"
|
connection: "smtps://user:pass@hostname:port"
|
||||||
# Login name for smtp server
|
|
||||||
smtp_login: "string"
|
|
||||||
# Password to login to the smtp server
|
|
||||||
smtp_password: "string"
|
|
||||||
# Address to send emails from, eg "noreply@your-instance.com"
|
# Address to send emails from, eg "noreply@your-instance.com"
|
||||||
smtp_from_address: "noreply@example.com"
|
smtp_from_address: "noreply@example.com"
|
||||||
# Whether or not smtp connections should use tls. Can be none, tls, or starttls
|
|
||||||
tls_type: "none"
|
|
||||||
}
|
}
|
||||||
# Parameters for automatic configuration of new instance (only used at first start)
|
# Parameters for automatic configuration of new instance (only used at first start)
|
||||||
setup: {
|
setup: {
|
||||||
|
|
|
@ -79,6 +79,7 @@ lettre = { version = "0.11.12", default-features = false, features = [
|
||||||
"builder",
|
"builder",
|
||||||
"smtp-transport",
|
"smtp-transport",
|
||||||
"tokio1-rustls-tls",
|
"tokio1-rustls-tls",
|
||||||
|
"pool",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
markdown-it = { version = "0.6.1", optional = true }
|
markdown-it = { version = "0.6.1", optional = true }
|
||||||
ts-rs = { workspace = true, optional = true }
|
ts-rs = { workspace = true, optional = true }
|
||||||
|
|
|
@ -5,13 +5,13 @@ use crate::{
|
||||||
use html2text;
|
use html2text;
|
||||||
use lettre::{
|
use lettre::{
|
||||||
message::{Mailbox, MultiPart},
|
message::{Mailbox, MultiPart},
|
||||||
transport::smtp::{authentication::Credentials, extension::ClientId},
|
transport::smtp::extension::ClientId,
|
||||||
Address,
|
Address,
|
||||||
AsyncTransport,
|
AsyncTransport,
|
||||||
Message,
|
Message,
|
||||||
};
|
};
|
||||||
use rosetta_i18n::{Language, LanguageId};
|
use rosetta_i18n::{Language, LanguageId};
|
||||||
use std::str::FromStr;
|
use std::{str::FromStr, sync::OnceLock};
|
||||||
use translations::Lang;
|
use translations::Lang;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -28,21 +28,16 @@ pub async fn send_email(
|
||||||
html: &str,
|
html: &str,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
|
static MAILER: OnceLock<AsyncSmtpTransport> = OnceLock::new();
|
||||||
let email_config = settings.email.clone().ok_or(LemmyErrorType::NoEmailSetup)?;
|
let email_config = settings.email.clone().ok_or(LemmyErrorType::NoEmailSetup)?;
|
||||||
let domain = settings.hostname.clone();
|
|
||||||
|
|
||||||
let (smtp_server, smtp_port) = {
|
#[expect(clippy::expect_used)]
|
||||||
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
|
let mailer = MAILER.get_or_init(|| {
|
||||||
let email = *email_and_port
|
AsyncSmtpTransport::from_url(&email_config.connection)
|
||||||
.first()
|
.expect("init email transport")
|
||||||
.ok_or(LemmyErrorType::EmailRequired)?;
|
.hello_name(ClientId::Domain(settings.hostname.clone()))
|
||||||
let port = email_and_port
|
.build()
|
||||||
.get(1)
|
});
|
||||||
.ok_or(LemmyErrorType::EmailSmtpServerNeedsAPort)?
|
|
||||||
.parse::<u16>()?;
|
|
||||||
|
|
||||||
(email, port)
|
|
||||||
};
|
|
||||||
|
|
||||||
// use usize::MAX as the line wrap length, since lettre handles the wrapping for us
|
// 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)?;
|
let plain_text = html2text::from_read(html.as_bytes(), usize::MAX)?;
|
||||||
|
@ -70,24 +65,6 @@ pub async fn send_email(
|
||||||
))
|
))
|
||||||
.with_lemmy_type(LemmyErrorType::EmailSendFailed)?;
|
.with_lemmy_type(LemmyErrorType::EmailSendFailed)?;
|
||||||
|
|
||||||
// don't worry about 'dangeous'. it's just that leaving it at the default configuration
|
|
||||||
// is bad.
|
|
||||||
|
|
||||||
// Set the TLS
|
|
||||||
let mut builder = match email_config.tls_type.as_str() {
|
|
||||||
"starttls" => AsyncSmtpTransport::starttls_relay(smtp_server)?.port(smtp_port),
|
|
||||||
"tls" => AsyncSmtpTransport::relay(smtp_server)?.port(smtp_port),
|
|
||||||
_ => AsyncSmtpTransport::builder_dangerous(smtp_server).port(smtp_port),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the creds if they exist
|
|
||||||
let smtp_password = email_config.smtp_password();
|
|
||||||
if let (Some(username), Some(password)) = (email_config.smtp_login, smtp_password) {
|
|
||||||
builder = builder.credentials(Credentials::new(username, password));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mailer = builder.hello_name(ClientId::Domain(domain)).build();
|
|
||||||
|
|
||||||
mailer
|
mailer
|
||||||
.send(email)
|
.send(email)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -74,7 +74,6 @@ pub enum LemmyErrorType {
|
||||||
ObjectNotLocal,
|
ObjectNotLocal,
|
||||||
NoEmailSetup,
|
NoEmailSetup,
|
||||||
LocalSiteNotSetup,
|
LocalSiteNotSetup,
|
||||||
EmailSmtpServerNeedsAPort,
|
|
||||||
InvalidEmailAddress(String),
|
InvalidEmailAddress(String),
|
||||||
RateLimitError,
|
RateLimitError,
|
||||||
InvalidName,
|
InvalidName,
|
||||||
|
|
|
@ -156,28 +156,13 @@ pub struct DatabaseConfig {
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, Document, SmartDefault)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Document, SmartDefault)]
|
||||||
#[serde(default, deny_unknown_fields)]
|
#[serde(default, deny_unknown_fields)]
|
||||||
pub struct EmailConfig {
|
pub struct EmailConfig {
|
||||||
/// Hostname and port of the smtp server
|
/// https://docs.rs/lettre/0.11.14/lettre/transport/smtp/struct.AsyncSmtpTransport.html#method.from_url
|
||||||
#[doku(example = "localhost:25")]
|
#[default("smtp://localhost:25")]
|
||||||
pub smtp_server: String,
|
#[doku(example = "smtps://user:pass@hostname:port")]
|
||||||
/// Login name for smtp server
|
pub(crate) connection: String,
|
||||||
pub smtp_login: Option<String>,
|
|
||||||
/// Password to login to the smtp server
|
|
||||||
smtp_password: Option<String>,
|
|
||||||
#[doku(example = "noreply@example.com")]
|
|
||||||
/// Address to send emails from, eg "noreply@your-instance.com"
|
/// Address to send emails from, eg "noreply@your-instance.com"
|
||||||
pub smtp_from_address: String,
|
#[doku(example = "noreply@example.com")]
|
||||||
/// Whether or not smtp connections should use tls. Can be none, tls, or starttls
|
pub(crate) smtp_from_address: String,
|
||||||
#[default("none")]
|
|
||||||
#[doku(example = "none")]
|
|
||||||
pub tls_type: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EmailConfig {
|
|
||||||
pub fn smtp_password(&self) -> Option<String> {
|
|
||||||
std::env::var("LEMMY_SMTP_PASSWORD")
|
|
||||||
.ok()
|
|
||||||
.or(self.smtp_password.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, Default, Document)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Default, Document)]
|
||||||
|
|
Loading…
Reference in a new issue