diff --git a/.env.template b/.env.template index 74b78547..80eb4756 100644 --- a/.env.template +++ b/.env.template @@ -534,6 +534,8 @@ # Whether to send mail via the `sendmail` command # USE_SENDMAIL=false +# Which sendmail command to use. The one found in the $PATH is used if not specified. +# SENDMAIL_COMMAND="/path/to/sendmail" ## Defaults for SSL is "Plain" and "Login" and nothing for Non-SSL connections. ## Possible values: ["Plain", "Login", "Xoauth2"]. diff --git a/src/api/admin.rs b/src/api/admin.rs index c2e747e2..a5a12e8a 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -747,7 +747,7 @@ fn get_diagnostics_http(code: u16, _token: AdminToken) -> EmptyResult { #[post("/config", format = "application/json", data = "")] fn post_config(data: Json, _token: AdminToken) -> EmptyResult { let data: ConfigBuilder = data.into_inner(); - if let Err(e) = CONFIG.update_config(data) { + if let Err(e) = CONFIG.update_config(data, true) { err!(format!("Unable to save config: {e:?}")) } Ok(()) diff --git a/src/config.rs b/src/config.rs index 0b93c216..da3bbd44 100644 --- a/src/config.rs +++ b/src/config.rs @@ -116,6 +116,14 @@ macro_rules! make_config { serde_json::from_str(&config_str).map_err(Into::into) } + fn clear_non_editable(&mut self) { + $($( + if !$editable { + self.$name = None; + } + )+)+ + } + /// Merges the values of both builders into a new builder. /// If both have the same element, `other` wins. fn merge(&self, other: &Self, show_overrides: bool, overrides: &mut Vec) -> Self { @@ -678,6 +686,8 @@ make_config! { _enable_smtp: bool, true, def, true; /// Use Sendmail |> Whether to send mail via the `sendmail` command use_sendmail: bool, true, def, false; + /// Sendmail Command |> Which sendmail command to use. The one found in the $PATH is used if not specified. + sendmail_command: String, false, option; /// Host smtp_host: String, true, option; /// DEPRECATED smtp_ssl |> DEPRECATED - Please use SMTP_SECURITY @@ -890,12 +900,16 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { } if cfg.use_sendmail { - let command = format!("sendmail{EXE_SUFFIX}"); + let command = cfg.sendmail_command.clone().unwrap_or_else(|| format!("sendmail{EXE_SUFFIX}")); - // Check if we can find the sendmail command to execute - let Ok(path) = which::which(&command) else { - err!(format!("sendmail command {command} not found in $PATH")) - }; + let mut path = std::path::PathBuf::from(&command); + // Check if we can find the sendmail command to execute when no absolute path is given + if !path.is_absolute() { + let Ok(which_path) = which::which(&command) else { + err!(format!("sendmail command {command} not found in $PATH")) + }; + path = which_path; + } match path.metadata() { Err(err) if err.kind() == std::io::ErrorKind::NotFound => { @@ -1142,12 +1156,17 @@ impl Config { }) } - pub fn update_config(&self, other: ConfigBuilder) -> Result<(), Error> { + pub fn update_config(&self, other: ConfigBuilder, ignore_non_editable: bool) -> Result<(), Error> { // Remove default values //let builder = other.remove(&self.inner.read().unwrap()._env); // TODO: Remove values that are defaults, above only checks those set by env and not the defaults - let builder = other; + let mut builder = other; + + // Remove values that are not editable + if ignore_non_editable { + builder.clear_non_editable(); + } // Serialize now before we consume the builder let config_str = serde_json::to_string_pretty(&builder)?; @@ -1182,7 +1201,7 @@ impl Config { let mut _overrides = Vec::new(); usr.merge(&other, false, &mut _overrides) }; - self.update_config(builder) + self.update_config(builder, false) } /// Tests whether an email's domain is allowed. A domain is allowed if it diff --git a/src/mail.rs b/src/mail.rs index 2a8e182e..d074995a 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -22,7 +22,11 @@ use crate::{ }; fn sendmail_transport() -> AsyncSendmailTransport { - AsyncSendmailTransport::new_with_command(format!("sendmail{EXE_SUFFIX}")) + if let Some(command) = CONFIG.sendmail_command() { + AsyncSendmailTransport::new_with_command(command) + } else { + AsyncSendmailTransport::new_with_command(format!("sendmail{EXE_SUFFIX}")) + } } fn smtp_transport() -> AsyncSmtpTransport {