diff --git a/filtermail/src/inbound.rs b/filtermail/src/inbound.rs index 90d91ff2..7b4c28cd 100644 --- a/filtermail/src/inbound.rs +++ b/filtermail/src/inbound.rs @@ -72,7 +72,7 @@ impl SmtpHandler for IncomingBeforeQueueHandler { Ok(()) } - async fn check_data(&self, envelope: &Envelope) -> Result<(), String> { + async fn check_data(&self, envelope: &mut Envelope) -> Result<(), String> { let message = match parse_mail(&envelope.data) { Ok(m) => m, Err(e) => return Err(format!("500 Failed to parse message: {}", e)), @@ -91,6 +91,15 @@ impl SmtpHandler for IncomingBeforeQueueHandler { log::debug!("Processing DATA message from {from_addr}"); + if !envelope.mail_from.eq_ignore_ascii_case(&from_addr) { + // If the MAIL FROM doesn't match the From header, we do not reject the mail, + // as this can be caused by e.g. SRS forwarding. + // Instead, we reset the envelope address, so it is reinjected as + // `MAIL FROM:<>` to prevent sending a bounce message. + // + envelope.mail_from = String::new(); + } + let mail_encrypted = check_encrypted(&message, false); log::debug!("mail_encrypted: {mail_encrypted}"); log::debug!("is_securejoin: {}", is_securejoin(&message)); diff --git a/filtermail/src/outbound.rs b/filtermail/src/outbound.rs index a654fe52..6614da66 100644 --- a/filtermail/src/outbound.rs +++ b/filtermail/src/outbound.rs @@ -55,7 +55,7 @@ impl SmtpHandler for OutgoingBeforeQueueHandler { Ok(()) } - async fn check_data(&self, envelope: &Envelope) -> Result<(), String> { + async fn check_data(&self, envelope: &mut Envelope) -> Result<(), String> { let message = match parse_mail(&envelope.data) { Ok(m) => m, Err(e) => return Err(format!("500 Failed to parse message: {}", e)), diff --git a/filtermail/src/smtp_server.rs b/filtermail/src/smtp_server.rs index ddb3d9fb..e3411590 100644 --- a/filtermail/src/smtp_server.rs +++ b/filtermail/src/smtp_server.rs @@ -22,13 +22,15 @@ pub trait SmtpHandler: Send + Sync { fn handle_mail(&self, address: &str) -> Result<(), String>; /// Checks the DATA command before reinjection. - async fn check_data(&self, envelope: &Envelope) -> Result<(), String>; + /// + /// Can optionally modify the envelope before reinjection. + async fn check_data(&self, envelope: &mut Envelope) -> Result<(), String>; /// Reinjects the mail back to postfix. async fn reinject_mail(&self, envelope: &Envelope) -> Result<(), String>; /// Handles the DATA command. - async fn handle_data(&self, envelope: &Envelope) -> Result { + async fn handle_data(&self, envelope: &mut Envelope) -> Result { log::debug!("handle_DATA before-queue"); self.check_data(envelope).await?; self.reinject_mail(envelope).await.map_err(|e| { @@ -182,7 +184,7 @@ where envelope.data = data; // Process the message - match handler.handle_data(&envelope).await { + match handler.handle_data(&mut envelope).await { Ok(response) => { log::debug!("Sent: {response}"); writer