Add --reply-text option
This commit is contained in:
parent
40b9f4920c
commit
17eeb8da4b
7 changed files with 44 additions and 5 deletions
|
@ -1,5 +1,10 @@
|
|||
# SpamAssassin Milter changelog
|
||||
|
||||
## unreleased
|
||||
|
||||
* Add `--reply-text` option to allow customising the reply text when rejecting
|
||||
spam.
|
||||
|
||||
## 0.1.2 (2020-06-07)
|
||||
|
||||
* Bump milter dependency to version 0.2.1.
|
||||
|
|
|
@ -7,6 +7,7 @@ spamassassin-milter \- milter for spam filtering with SpamAssassin
|
|||
.RB [ \-B ]
|
||||
.RB [ \-H ]
|
||||
.RB [ \-n ]
|
||||
[\fB\-R\fR \fIMSG\fR]
|
||||
.RB [ \-r ]
|
||||
[\fB\-s\fR \fIBYTES\fR]
|
||||
[\fB\-t\fR \fINETS\fR]
|
||||
|
@ -114,6 +115,12 @@ Reject messages flagged as spam at the SMTP level.
|
|||
Rejection results in a permanent SMTP error being returned to the client, and
|
||||
the message is not delivered.
|
||||
.TP
|
||||
.BR \-R ", " \-\-reply-text " \fIMSG\fR"
|
||||
Reply with SMTP reply text
|
||||
.I MSG
|
||||
when rejecting a message flagged as spam.
|
||||
For multiline replies, use an ASCII newline character as the line separator.
|
||||
.TP
|
||||
.BR \-t ", " \-\-trusted-networks " \fINETS\fR"
|
||||
Trust connections coming from the IP networks or addresses
|
||||
.IR NETS .
|
||||
|
|
|
@ -266,8 +266,8 @@ fn reject_spam(id: &str, actions: &impl SetErrorReply, config: &Config) -> milte
|
|||
Status::Accept
|
||||
} else {
|
||||
// These reply codes are the most appropriate according to RFCs 5321 and
|
||||
// 3463. The text is kept generic and makes no mention of SpamAssassin.
|
||||
actions.set_error_reply("550", Some("5.7.1"), vec!["Spam message refused"])?;
|
||||
// 3463. The default text is generic and does not mention SpamAssassin.
|
||||
actions.set_error_reply("550", Some("5.7.1"), config.reply_text().lines().collect())?;
|
||||
|
||||
verbose!(config, "{}: rejected message flagged as spam", id);
|
||||
Status::Reject
|
||||
|
|
|
@ -13,6 +13,7 @@ pub struct ConfigBuilder {
|
|||
max_message_size: usize,
|
||||
dry_run: bool,
|
||||
reject_spam: bool,
|
||||
reply_text: String,
|
||||
preserve_headers: bool,
|
||||
preserve_body: bool,
|
||||
verbose: bool,
|
||||
|
@ -64,6 +65,11 @@ impl ConfigBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn reply_text(&mut self, value: String) -> &mut Self {
|
||||
self.reply_text = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn preserve_headers(&mut self, value: bool) -> &mut Self {
|
||||
self.preserve_headers = value;
|
||||
self
|
||||
|
@ -94,6 +100,7 @@ impl ConfigBuilder {
|
|||
max_message_size: self.max_message_size,
|
||||
dry_run: self.dry_run,
|
||||
reject_spam: self.reject_spam,
|
||||
reply_text: self.reply_text,
|
||||
preserve_headers: self.preserve_headers,
|
||||
preserve_body: self.preserve_body,
|
||||
verbose: self.verbose,
|
||||
|
@ -112,6 +119,8 @@ impl Default for ConfigBuilder {
|
|||
max_message_size: 512_000, // same as in `spamc`
|
||||
dry_run: Default::default(),
|
||||
reject_spam: Default::default(),
|
||||
// Generic default reply text that makes no mention of SpamAssassin.
|
||||
reply_text: String::from("Spam message refused"),
|
||||
preserve_headers: Default::default(),
|
||||
preserve_body: Default::default(),
|
||||
verbose: Default::default(),
|
||||
|
@ -130,6 +139,7 @@ pub struct Config {
|
|||
max_message_size: usize,
|
||||
dry_run: bool,
|
||||
reject_spam: bool,
|
||||
reply_text: String,
|
||||
preserve_headers: bool,
|
||||
preserve_body: bool,
|
||||
verbose: bool,
|
||||
|
@ -172,6 +182,10 @@ impl Config {
|
|||
self.reject_spam
|
||||
}
|
||||
|
||||
pub fn reply_text(&self) -> &str {
|
||||
&self.reply_text
|
||||
}
|
||||
|
||||
pub fn preserve_headers(&self) -> bool {
|
||||
self.preserve_headers
|
||||
}
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -9,6 +9,7 @@ const ARG_MILTER_DEBUG_LEVEL: &str = "MILTER_DEBUG_LEVEL";
|
|||
const ARG_PRESERVE_BODY: &str = "PRESERVE_BODY";
|
||||
const ARG_PRESERVE_HEADERS: &str = "PRESERVE_HEADERS";
|
||||
const ARG_REJECT_SPAM: &str = "REJECT_SPAM";
|
||||
const ARG_REPLY_TEXT: &str = "REPLY_TEXT";
|
||||
const ARG_TRUSTED_NETWORKS: &str = "TRUSTED_NETWORKS";
|
||||
const ARG_VERBOSE: &str = "VERBOSE";
|
||||
const ARG_SOCKET: &str = "SOCKET";
|
||||
|
@ -52,6 +53,12 @@ fn main() {
|
|||
.long("reject-spam")
|
||||
.conflicts_with_all(&[ARG_PRESERVE_BODY, ARG_PRESERVE_HEADERS])
|
||||
.help("Reject messages flagged as spam"))
|
||||
.arg(Arg::with_name(ARG_REPLY_TEXT)
|
||||
.short("R")
|
||||
.long("reply-text")
|
||||
.value_name("MSG")
|
||||
.requires(ARG_REJECT_SPAM)
|
||||
.help("Reply text when rejecting messages"))
|
||||
.arg(Arg::with_name(ARG_TRUSTED_NETWORKS)
|
||||
.short("t")
|
||||
.long("trusted-networks")
|
||||
|
@ -147,6 +154,10 @@ fn build_config(matches: &ArgMatches<'_>) -> Result<Config> {
|
|||
config.verbose(true);
|
||||
}
|
||||
|
||||
if let Some(msg) = matches.value_of(ARG_REPLY_TEXT) {
|
||||
config.reply_text(msg.to_owned());
|
||||
}
|
||||
|
||||
if let Some(level) = matches.value_of(ARG_MILTER_DEBUG_LEVEL) {
|
||||
config.milter_debug_level(level.parse().unwrap());
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ local err = mt.eom(conn)
|
|||
assert(err == nil, err)
|
||||
assert(mt.getreply(conn) == SMFIR_REPLYCODE)
|
||||
|
||||
assert(mt.eom_check(conn, MT_SMTPREPLY, "550", "5.7.1", "Spam message refused"))
|
||||
assert(mt.eom_check(conn, MT_SMTPREPLY, "550", "5.7.1", "Not allowed!"))
|
||||
|
||||
local err = mt.disconnect(conn)
|
||||
assert(err == nil, err)
|
||||
|
|
|
@ -6,8 +6,10 @@ use spamassassin_milter::*;
|
|||
#[test]
|
||||
fn reject_spam() {
|
||||
let mut builder = Config::builder();
|
||||
builder.reject_spam(true);
|
||||
builder.spamc_args(vec![format!("--port={}", SPAMD_PORT)]);
|
||||
builder
|
||||
.reject_spam(true)
|
||||
.reply_text("Not allowed!".into())
|
||||
.spamc_args(vec![format!("--port={}", SPAMD_PORT)]);
|
||||
let config = builder.build();
|
||||
|
||||
let server = spawn_mock_spamd_server(SPAMD_PORT, |spam| {
|
||||
|
|
Loading…
Reference in a new issue