feat: Check incoming email return address (#72)

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.

Closes #67

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
This commit is contained in:
Jagoda Estera Ślązak
2026-02-25 16:20:08 +01:00
committed by GitHub
parent a5c6880ceb
commit 82618de311
3 changed files with 16 additions and 5 deletions
+10 -1
View File
@@ -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.
// <https://github.com/chatmail/filtermail/issues/67>
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));