MTA: Implement spamtest in trusted Sieve scripts

This commit is contained in:
Maurus Decimus
2026-05-26 21:08:06 +02:00
parent 0e655828b3
commit 1fb87eda64
4 changed files with 27 additions and 4 deletions

View File

@@ -36,7 +36,7 @@ use mail_auth::{
use mail_builder::headers::{date::Date, message_id::generate_message_id_header};
use mail_parser::{MessageParser, parsers::fields::thread::thread_name};
use registry::schema::structs::Rate;
use sieve::runtime::Variable;
use sieve::{SpamStatus, runtime::Variable};
use smtp_proto::{
MAIL_BY_RETURN, RCPT_NOTIFY_DELAY, RCPT_NOTIFY_FAILURE, RCPT_NOTIFY_NEVER, RCPT_NOTIFY_SUCCESS,
};
@@ -416,6 +416,7 @@ impl<T: SessionStream> Session<T> {
// Run SPAM filter
let mut train_spam = None;
let mut spam_status = None;
if self.server.core.spam.enabled
&& self
.server
@@ -442,6 +443,11 @@ impl<T: SessionStream> Session<T> {
thread_name(parsed_message.subject().unwrap_or_default()).to_string(),
)
});
spam_status = Some(if score.is_spam {
SpamStatus::Spam
} else {
SpamStatus::Ham
});
// Add scores for local recipients
for (is_spam, recipient) in
@@ -532,9 +538,13 @@ impl<T: SessionStream> Session<T> {
.map(|s| (s, name))
})
{
let params = self
let mut params = self
.build_script_parameters("data")
.with_auth_headers(&headers)
.with_auth_headers(&headers);
if let Some(spam_status) = spam_status {
params = params.with_spam_status(spam_status);
}
let params = params
.set_variable(
"arc.result",
arc_output

View File

@@ -63,6 +63,9 @@ impl RunScript for Server {
.with_envelope_list(params.envelope)
.with_user_address(&params.from_addr)
.with_user_full_name(&params.from_name);
if let Some(spam_status) = params.spam_status {
instance.set_spam_status(spam_status);
}
let mut input = Input::script("__script", script);
let mut messages: Vec<Vec<u8>> = Vec::new();
let session_id = params.session_id;

View File

@@ -12,7 +12,7 @@ use common::{
};
use mail_parser::Message;
use sieve::{Envelope, runtime::Variable};
use sieve::{Envelope, SpamStatus, runtime::Variable};
pub mod envelope;
pub mod event_loop;
@@ -41,6 +41,7 @@ pub struct ScriptParameters<'x> {
return_path: String,
sign_domain: Option<String>,
access_token: Option<&'x AccessToken>,
spam_status: Option<SpamStatus>,
session_id: u64,
}
@@ -56,6 +57,7 @@ impl<'x> ScriptParameters<'x> {
return_path: Default::default(),
sign_domain: Default::default(),
access_token: None,
spam_status: None,
session_id: Default::default(),
}
}
@@ -95,6 +97,13 @@ impl<'x> ScriptParameters<'x> {
}
}
pub fn with_spam_status(self, status: SpamStatus) -> Self {
Self {
spam_status: status.into(),
..self
}
}
pub fn set_variable(
mut self,
name: impl Into<Cow<'static, str>>,