normalize email from

This commit is contained in:
Mateusz Gruszczyński
2026-07-27 18:24:42 +02:00
parent 3e4cb910c2
commit cc3b172e56
7 changed files with 57 additions and 14 deletions
+13 -9
View File
@@ -25,7 +25,7 @@ use tracing::{debug, info, warn};
use crate::{
queries,
state::{SharedState, SmtpConfig},
state::{SharedState, SmtpConfig, SmtpSecurity},
};
const MIN_PASSWORD: usize = 8;
@@ -2098,15 +2098,19 @@ async fn send_share_invitation(
}
async fn send_message(smtp: &SmtpConfig, message: Message, label: &str) -> Result<(), AuthError> {
let mut builder = if smtp.port == 465 {
AsyncSmtpTransport::<Tokio1Executor>::relay(&smtp.host)
} else {
AsyncSmtpTransport::<Tokio1Executor>::starttls_relay(&smtp.host)
let mut builder = match smtp.security {
SmtpSecurity::None => AsyncSmtpTransport::<Tokio1Executor>::builder_dangerous(&smtp.host),
SmtpSecurity::StartTls => AsyncSmtpTransport::<Tokio1Executor>::starttls_relay(&smtp.host)
.map_err(|error| {
tracing::error!(error = %error, host = %smtp.host, port = smtp.port, security = ?smtp.security, "invalid SMTP configuration");
AuthError::internal("Invalid SMTP configuration.")
})?,
SmtpSecurity::Tls => AsyncSmtpTransport::<Tokio1Executor>::relay(&smtp.host)
.map_err(|error| {
tracing::error!(error = %error, host = %smtp.host, port = smtp.port, security = ?smtp.security, "invalid SMTP configuration");
AuthError::internal("Invalid SMTP configuration.")
})?,
}
.map_err(|error| {
tracing::error!(error = %error, host = %smtp.host, port = smtp.port, "invalid SMTP configuration");
AuthError::internal("Invalid SMTP configuration.")
})?
.port(smtp.port);
if !smtp.username.is_empty() {
+28 -2
View File
@@ -121,6 +121,10 @@ impl Config {
Some(crate::state::SmtpConfig {
host,
port: values.get("SMTP_PORT", "587").parse()?,
security: parse_smtp_security(&values.get(
"SMTP_SECURITY",
if values.get("SMTP_PORT", "587") == "465" { "tls" } else { "starttls" },
))?,
username: values.get("SMTP_USERNAME", ""),
password: values.get("SMTP_PASSWORD", ""),
from: normalize_smtp_from(
@@ -187,6 +191,15 @@ impl Config {
fn parse_smtp_security(value: &str) -> Result<crate::state::SmtpSecurity, Box<dyn std::error::Error>> {
match value.trim().to_ascii_lowercase().as_str() {
"none" | "plain" => Ok(crate::state::SmtpSecurity::None),
"starttls" => Ok(crate::state::SmtpSecurity::StartTls),
"tls" | "ssl" | "smtps" => Ok(crate::state::SmtpSecurity::Tls),
_ => Err("SMTP_SECURITY must be one of: none, starttls, tls".into()),
}
}
fn normalize_smtp_from(value: String) -> Result<String, Box<dyn std::error::Error>> {
let trimmed = value.trim();
if trimmed.is_empty() {
@@ -225,7 +238,7 @@ const KNOWN_CONFIG_KEYS: &[&str] = &[
"FRONTEND_LOG_LEVEL", "ANONYMOUS_ACCESS_TOKEN_TTL_DAYS", "USER_SESSION_TTL_DAYS",
"UNCONFIRMED_ACCOUNT_TTL_DAYS", "AUTHORIZATION_TYPE",
"S3_ENDPOINT", "S3_REGION", "S3_BUCKET", "S3_ACCESS_KEY", "S3_SECRET_KEY",
"S3_FORCE_PATH_STYLE", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD",
"S3_FORCE_PATH_STYLE", "SMTP_HOST", "SMTP_PORT", "SMTP_SECURITY", "SMTP_USERNAME", "SMTP_PASSWORD",
"SMTP_FROM", "PUBLIC_URL", "LDAP_URL", "LDAP_STARTTLS", "LDAP_BIND_DN",
"LDAP_BIND_PASSWORD", "LDAP_BASE_DN", "LDAP_USER_FILTER", "LDAP_USERNAME_ATTRIBUTE",
"LDAP_EMAIL_ATTRIBUTE", "LDAP_DISPLAY_NAME_ATTRIBUTE", "LDAP_EXTERNAL_ID_ATTRIBUTE",
@@ -387,7 +400,20 @@ fn parse_yaml_scalar(value: &str) -> Result<String, String> {
#[cfg(test)]
mod tests {
use super::normalize_smtp_from;
use super::{normalize_smtp_from, parse_smtp_security};
use crate::state::SmtpSecurity;
#[test]
fn smtp_security_accepts_supported_modes() {
assert_eq!(parse_smtp_security("none").unwrap(), SmtpSecurity::None);
assert_eq!(parse_smtp_security("starttls").unwrap(), SmtpSecurity::StartTls);
assert_eq!(parse_smtp_security("tls").unwrap(), SmtpSecurity::Tls);
}
#[test]
fn smtp_security_rejects_unknown_mode() {
assert!(parse_smtp_security("auto").is_err());
}
#[test]
fn smtp_from_accepts_unquoted_value() {
+8
View File
@@ -11,10 +11,18 @@ use tokio::sync::{RwLock, broadcast};
const CHANNEL_CAPACITY: usize = 256;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SmtpSecurity {
None,
StartTls,
Tls,
}
#[derive(Debug, Clone)]
pub struct SmtpConfig {
pub host: String,
pub port: u16,
pub security: SmtpSecurity,
pub username: String,
pub password: String,
pub from: String,