From 57885e6db61cd51dee3c78d238766f967ca8da1c Mon Sep 17 00:00:00 2001 From: mdecimus Date: Thu, 21 Dec 2023 10:56:28 +0100 Subject: [PATCH] Move spam messages to Junk folders when spam headers are present --- crates/jmap/src/api/config.rs | 8 ++++++++ crates/jmap/src/email/ingest.rs | 19 +++++++++++++++++-- crates/jmap/src/lib.rs | 3 +++ resources/config/jmap/store.toml | 3 +++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/crates/jmap/src/api/config.rs b/crates/jmap/src/api/config.rs index ed35893e..d1422709 100644 --- a/crates/jmap/src/api/config.rs +++ b/crates/jmap/src/api/config.rs @@ -141,6 +141,14 @@ impl crate::Config { .unwrap_or(true), encrypt: settings.property_or_static("jmap.encryption.enable", "true")?, encrypt_append: settings.property_or_static("jmap.encryption.append", "false")?, + spam_header: settings.value("jmap.spam.header").and_then(|v| { + v.split_once(':').map(|(k, v)| { + ( + mail_parser::HeaderName::parse(k.trim().to_string()).unwrap(), + v.trim().to_string(), + ) + }) + }), http_headers: settings .values("jmap.http.headers") .map(|(_, v)| { diff --git a/crates/jmap/src/email/ingest.rs b/crates/jmap/src/email/ingest.rs index d5931168..69b9ed32 100644 --- a/crates/jmap/src/email/ingest.rs +++ b/crates/jmap/src/email/ingest.rs @@ -48,7 +48,7 @@ use utils::map::vec_map::VecMap; use crate::{ email::index::{IndexMessage, VisitValues, MAX_ID_LENGTH}, - mailbox::UidMailbox, + mailbox::{UidMailbox, INBOX_ID, JUNK_ID}, services::housekeeper::Event, IngestError, JMAP, }; @@ -84,7 +84,7 @@ impl JMAP { #[allow(clippy::blocks_in_if_conditions)] pub async fn email_ingest( &self, - params: IngestEmail<'_>, + mut params: IngestEmail<'_>, ) -> Result { // Check quota let mut raw_message_len = params.raw_message.len() as i64; @@ -106,6 +106,21 @@ impl JMAP { reason: "Failed to parse e-mail message.".to_string(), })?; + // Check for Spam headers + if let Some((header_name, header_value)) = &self.config.spam_header { + if params.mailbox_ids == [INBOX_ID] + && message.root_part().headers().iter().any(|header| { + &header.name == header_name + && header + .value() + .as_text() + .map_or(false, |value| value.contains(header_value)) + }) + { + params.mailbox_ids[0] = JUNK_ID; + } + } + // Obtain message references and thread name let thread_id = { let mut references = Vec::with_capacity(5); diff --git a/crates/jmap/src/lib.rs b/crates/jmap/src/lib.rs index b3b478e2..eb49f8b8 100644 --- a/crates/jmap/src/lib.rs +++ b/crates/jmap/src/lib.rs @@ -40,6 +40,7 @@ use jmap_proto::{ }, types::{collection::Collection, property::Property}, }; +use mail_parser::HeaderName; use nlp::language::Language; use services::{ delivery::spawn_delivery_manager, @@ -157,6 +158,8 @@ pub struct Config { pub oauth_expiry_refresh_token_renew: u64, pub oauth_max_auth_attempts: u32, + pub spam_header: Option<(HeaderName<'static>, String)>, + pub http_headers: Vec<(hyper::header::HeaderName, hyper::header::HeaderValue)>, pub encrypt: bool, diff --git a/resources/config/jmap/store.toml b/resources/config/jmap/store.toml index ff9e67c2..f639bccd 100644 --- a/resources/config/jmap/store.toml +++ b/resources/config/jmap/store.toml @@ -11,6 +11,9 @@ blob = "__BLOB_STORE__" enable = true append = false +[jmap.spam] +header = "X-Spam-Status: Yes" + [jmap.fts] default-language = "en"