diff --git a/Cargo.lock b/Cargo.lock index b4c65dba..975197ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,6 +170,13 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "antispam" +version = "0.1.0" +dependencies = [ + "fancy-regex", +] + [[package]] name = "anyhow" version = "1.0.72" @@ -495,6 +502,21 @@ dependencies = [ "which", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitfield" version = "0.14.0" @@ -1520,6 +1542,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + [[package]] name = "farmhash" version = "1.1.5" diff --git a/Cargo.toml b/Cargo.toml index dac97be2..b9dea6d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "crates/managesieve", "crates/store", "crates/directory", + "crates/antispam", "crates/utils", "crates/maybe-async", "crates/cli", diff --git a/crates/antispam/Cargo.toml b/crates/antispam/Cargo.toml new file mode 100644 index 00000000..c0348da6 --- /dev/null +++ b/crates/antispam/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "antispam" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fancy-regex = "0.11.0" diff --git a/crates/antispam/src/import/meta.rs b/crates/antispam/src/import/meta.rs new file mode 100644 index 00000000..1aab7a35 --- /dev/null +++ b/crates/antispam/src/import/meta.rs @@ -0,0 +1,364 @@ +use std::collections::{HashMap, HashSet}; + +use super::Token; + +#[derive(Debug, Clone)] +pub struct MetaExpression { + pub tokens: Vec, + pub token_depth: Vec, +} + +impl MetaExpression { + pub fn from_meta(meta: &str) -> Self { + let mut tokens = Vec::new(); + let mut token_depth = Vec::new(); + let mut seen_comp = false; + let mut buf = String::new(); + let mut pc = 0; + let mut iter = meta.chars().peekable(); + + while let Some(ch) = iter.next() { + match ch { + 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' => { + buf.push(ch); + } + _ => { + if !buf.is_empty() { + let token = Token::from(buf); + buf = String::new(); + if matches!(token, Token::Tag(_)) + && !seen_comp + && matches!( + iter.clone() + .find(|t| { ['&', '|', '>', '<', '='].contains(t) }), + None | Some('&' | '|') + ) + { + tokens.push(token); + tokens.push(Token::Gt); + tokens.push(Token::Number(0)); + token_depth.extend_from_slice(&[pc, pc, pc]); + seen_comp = true; + } else { + token_depth.push(pc); + tokens.push(token); + } + } + + match ch { + '&' => { + seen_comp = false; + if matches!(iter.next(), Some('&')) { + tokens.push(Token::And); + token_depth.push(pc); + } else { + eprintln!("Warning: Single & in meta expression {meta} at {pc}",); + } + } + '|' => { + seen_comp = false; + if matches!(iter.next(), Some('|')) { + tokens.push(Token::Or); + token_depth.push(pc); + } else { + eprintln!("Warning: Single | in meta expression {meta} at {pc}",); + } + } + '!' => { + seen_comp = false; + token_depth.push(pc); + tokens.push(Token::Not) + } + '=' => { + seen_comp = true; + token_depth.push(pc); + tokens.push(match iter.next() { + Some('=') => Token::Eq, + Some('>') => Token::Ge, + Some('<') => Token::Le, + _ => { + eprintln!( + "Warning: Single = in meta expression {meta} at {pc}", + ); + Token::Eq + } + }); + } + '>' => { + seen_comp = true; + token_depth.push(pc); + tokens.push(match iter.peek() { + Some('=') => { + iter.next(); + Token::Ge + } + _ => Token::Gt, + }) + } + '<' => { + seen_comp = true; + token_depth.push(pc); + tokens.push(match iter.peek() { + Some('=') => { + iter.next(); + Token::Le + } + _ => Token::Lt, + }) + } + '(' => { + token_depth.push(pc); + pc += 1; + tokens.push(Token::OpenParen) + } + ')' => { + if pc > 0 { + pc -= 1; + } else { + eprintln!( + "Warning: Unmatched close parenthesis in meta expression {meta}" + ); + } + token_depth.push(pc); + tokens.push(Token::CloseParen) + } + '+' => { + token_depth.push(pc); + tokens.push(Token::Add) + } + '*' => { + token_depth.push(pc); + tokens.push(Token::Multiply) + } + '/' => { + token_depth.push(pc); + tokens.push(Token::Divide) + } + ' ' => {} + _ => { + eprintln!("Warning: Invalid character {ch} in meta expression {meta}"); + break; + } + } + } + } + } + + if pc > 0 { + eprintln!("Warning: Unmatched open parenthesis in meta expression {meta}"); + } + + if !buf.is_empty() { + token_depth.push(pc); + tokens.push(Token::from(buf)); + if !seen_comp { + tokens.push(Token::Gt); + tokens.push(Token::Number(0)); + token_depth.push(pc); + token_depth.push(pc); + } + } + + MetaExpression { + tokens, + token_depth, + } + } +} + +impl From for Token { + fn from(value: String) -> Self { + if let Ok(value) = value.parse() { + Token::Number(value) + } else { + Token::Tag(value) + } + } +} + +impl From for String { + fn from(meta: MetaExpression) -> Self { + let mut script = String::from("if "); + let mut tokens = meta.tokens.iter().zip(meta.token_depth.iter()).enumerate(); + let mut expr_end = None; + + // Find start and end of logical expressions + let mut logical_pos_start: HashMap = HashMap::new(); + let mut logical_pos_end: HashSet = HashSet::new(); + let mut depth_starts: HashMap = HashMap::new(); + for (pos, (token, depth)) in tokens.clone() { + if !depth_starts.contains_key(depth) { + depth_starts.insert(*depth, pos); + } + if matches!(token, Token::And | Token::Or) { + let block_start = *depth_starts.get(depth).unwrap(); + + if let std::collections::hash_map::Entry::Vacant(e) = + logical_pos_start.entry(block_start) + { + e.insert(token.clone()); + // Find end + let mut logical_end = usize::MAX; + for (p, (_, d)) in tokens.clone() { + if depth == d { + logical_end = p; + } + } + logical_pos_end.insert(logical_end); + } + } + } + + while let Some((pos, (token, depth))) = tokens.next() { + // Add blocks + if let Some(token) = logical_pos_start.remove(&pos) { + match token { + Token::And => script.push_str("allof("), + Token::Or => script.push_str("anyof("), + _ => unreachable!(), + } + } else { + match token { + Token::And | Token::Or => script.push_str(", "), + Token::Not => script.push_str("not "), + _ => (), + } + } + + // Find expression type + if expr_end.is_none() { + if let Some(( + pos, + (token @ (Token::Eq | Token::Gt | Token::Lt | Token::Ge | Token::Le), _), + )) = tokens.clone().find(|(_, (t, d))| { + depth == *d + && matches!( + t, + Token::Eq + | Token::Gt + | Token::Lt + | Token::Ge + | Token::Le + | Token::Not + | Token::And + | Token::Or + ) + }) { + script.push_str("string :"); + match token { + Token::Eq => script.push_str("eq"), + Token::Gt => script.push_str("gt"), + Token::Lt => script.push_str("lt"), + Token::Ge => script.push_str("ge"), + Token::Le => script.push_str("gt"), + _ => unreachable!(), + } + script.push_str(" \""); + + // Find expression end + for (p, (token, d)) in tokens.clone() { + if p > pos { + if depth <= d { + if matches!(token, Token::And | Token::Or) { + expr_end = Some(p - 1); + break; + } else { + expr_end = Some(p); + } + } else { + break; + } + } + } + } + } + + match token { + Token::Tag(tag) => { + script.push_str(tag); + } + Token::Number(number) => { + script.push_str(&number.to_string()); + } + Token::And | Token::Or | Token::Not => {} + Token::Gt | Token::Lt | Token::Eq | Token::Ge | Token::Le => { + script.push_str("\" \""); + } + Token::OpenParen => { + script.push('('); + } + Token::CloseParen => { + script.push(')'); + } + Token::Add => { + script.push_str(" + "); + } + Token::Multiply => { + script.push_str(" * "); + } + Token::Divide => { + script.push_str(" / "); + } + } + + // Add end of expression + if expr_end == Some(pos) { + script.push_str("\""); + expr_end = None; + } + + // Add end of logical block + if logical_pos_end.contains(&pos) { + script.push(')'); + } + } + + script + } +} + +#[cfg(test)] +mod test { + use super::MetaExpression; + + #[test] + fn parse_meta() { + for (expr, expected) in [ + ( + concat!( + "( ! HTML_IMAGE_ONLY_16 ) && ", + "( __LOWER_E > 20 ) && ", + "( __E_LIKE_LETTER > ( (__LOWER_E * 14 ) / 10) ) && ", + "( __E_LIKE_LETTER < ( 10 * __LOWER_E ) )" + ), + "", + ), + ("(__DRUGS_ERECTILE1 || __DRUGS_ERECTILE2)", ""), + ("(__HELO_DYNAMIC_IPADDR && !HELO_STATIC_HOST)", ""), + ("__ML2 || __ML4", ""), + ("(__AT_HOTMAIL_MSGID && (!__FROM_HOTMAIL_COM && !__FROM_MSN_COM && !__FROM_YAHOO_COM))", ""), + ("(0)", ""), + ("RAZOR2_CHECK + DCC_CHECK + PYZOR_CHECK > 1", ""), + /*(("", ""), + ("", ""), + ("", ""), + ("", ""), + ("", ""), + ("", ""), + ("", ""),*/ + ] { + let meta = MetaExpression::from_meta(expr); + //println!("{:?}", meta.tokens); + let result = String::from(meta); + + //println!("{}", expected); + println!("{}", result); + + /*assert_eq!( + result, + expected, + "failed for {expr}" + );*/ + } + } +} diff --git a/crates/antispam/src/import/mod.rs b/crates/antispam/src/import/mod.rs new file mode 100644 index 00000000..41f341c0 --- /dev/null +++ b/crates/antispam/src/import/mod.rs @@ -0,0 +1,192 @@ +use std::collections::HashMap; + +pub mod meta; +pub mod spamassassin; +pub mod utils; + +#[derive(Debug, Default)] +struct Rule { + name: String, + t: RuleType, + scores: Vec, + description: HashMap, + priority: i32, + flags: Vec, +} + +#[derive(Debug, Default)] +enum RuleType { + Header { + matches: HeaderMatches, + header: Header, + if_unset: Option, + pattern: String, + }, + Body { + pattern: String, + raw: bool, + }, + Full { + pattern: String, + }, + Uri { + pattern: String, + }, + Eval { + function: String, + params: Vec, + }, + Meta { + tokens: Vec, + }, + + #[default] + None, +} + +impl RuleType { + pub fn pattern(&mut self) -> Option<&mut String> { + match self { + RuleType::Header { pattern, .. } => Some(pattern), + RuleType::Body { pattern, .. } => Some(pattern), + RuleType::Full { pattern, .. } => Some(pattern), + RuleType::Uri { pattern, .. } => Some(pattern), + _ => None, + } + } +} + +#[derive(Debug)] +enum TestFlag { + Net, + Nice, + UserConf, + Learn, + NoAutoLearn, + Publish, + Multiple, + NoTrim, + DomainsOnly, + NoSubject, + AutoLearnBody, + A, + MaxHits(u32), + DnsBlockRule(String), +} + +#[derive(Debug, Default)] +enum Header { + #[default] + All, + MessageId, + AllExternal, + EnvelopeFrom, + ToCc, + Name { + name: String, + part: Vec, + }, +} + +#[derive(Debug, Default)] +enum HeaderMatches { + #[default] + Matches, + NotMatches, + Exists, +} + +#[derive(Debug, Default)] +enum HeaderPart { + Name, + Addr, + #[default] + Raw, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Token { + Tag(String), + Number(u32), + And, + Or, + Not, + Gt, + Lt, + Eq, + Ge, + Le, + OpenParen, + CloseParen, + Add, + Multiply, + Divide, +} + +impl Rule { + fn score(&self) -> f64 { + self.scores.last().copied().unwrap_or_else(|| { + if self.name.starts_with("__") { + 0.0 + } else if self.name.starts_with("T_") { + 0.01 + } else { + 1.0 + } + }) + } +} + +impl Ord for Rule { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match self.priority.cmp(&other.priority) { + std::cmp::Ordering::Equal => match self.score().partial_cmp(&other.score()).unwrap() { + std::cmp::Ordering::Equal => other.name.cmp(&self.name), + x => x, + }, + x => x, + } + } +} + +impl PartialOrd for Rule { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Rule { + fn eq(&self, other: &Self) -> bool { + self.name == other.name && self.priority == other.priority && self.scores == other.scores + } +} + +impl Eq for Rule {} + +pub trait UnwrapResult { + fn unwrap_result(self, action: &str) -> T; +} + +impl UnwrapResult for Option { + fn unwrap_result(self, message: &str) -> T { + match self { + Some(result) => result, + None => { + eprintln!("Failed to {}", message); + std::process::exit(1); + } + } + } +} + +impl UnwrapResult for Result { + fn unwrap_result(self, message: &str) -> T { + match self { + Ok(result) => result, + Err(err) => { + eprintln!("Failed to {}: {}", message, err); + std::process::exit(1); + } + } + } +} diff --git a/crates/antispam/src/import/spamassassin.rs b/crates/antispam/src/import/spamassassin.rs new file mode 100644 index 00000000..760ef239 --- /dev/null +++ b/crates/antispam/src/import/spamassassin.rs @@ -0,0 +1,1073 @@ +use std::{ + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, + default, + fmt::format, + fs, + path::PathBuf, +}; + +use super::{ + meta::MetaExpression, + utils::{fix_broken_regex, replace_tags}, + Header, HeaderMatches, HeaderPart, Rule, RuleType, TestFlag, Token, UnwrapResult, +}; + +static SUPPORTED_PLUGINS: [&str; 37] = [ + "Mail::SpamAssassin::Plugin::DKIM", + "Mail::SpamAssassin::Plugin::SPF", + "Mail::SpamAssassin::Plugin::ASN", + "Mail::SpamAssassin::Plugin::AWL", + "Mail::SpamAssassin::Plugin::AccessDB", + "Mail::SpamAssassin::Plugin::AntiVirus", + "Mail::SpamAssassin::Plugin::AskDNS", + "Mail::SpamAssassin::Plugin::AutoLearnThreshold", + "Mail::SpamAssassin::Plugin::Bayes", + "Mail::SpamAssassin::Plugin::BodyEval", + "Mail::SpamAssassin::Plugin::DCC", + "Mail::SpamAssassin::Plugin::DMARC", + "Mail::SpamAssassin::Plugin::DNSEval", + "Mail::SpamAssassin::Plugin::Dmarc", + "Mail::SpamAssassin::Plugin::FreeMail", + "Mail::SpamAssassin::Plugin::FromNameSpoof", + "Mail::SpamAssassin::Plugin::HTMLEval", + "Mail::SpamAssassin::Plugin::HTTPSMismatch", + "Mail::SpamAssassin::Plugin::HashBL", + "Mail::SpamAssassin::Plugin::HeaderEval", + "Mail::SpamAssassin::Plugin::ImageInfo", + "Mail::SpamAssassin::Plugin::MIMEEval", + "Mail::SpamAssassin::Plugin::MIMEHeader", + "Mail::SpamAssassin::Plugin::PDFInfo", + "Mail::SpamAssassin::Plugin::Pyzor", + "Mail::SpamAssassin::Plugin::Razor2", + "Mail::SpamAssassin::Plugin::RelayEval", + "Mail::SpamAssassin::Plugin::ReplaceTags", + "Mail::SpamAssassin::Plugin::Shortcircuit", + "Mail::SpamAssassin::Plugin::TextCat", + "Mail::SpamAssassin::Plugin::TxRep", + "Mail::SpamAssassin::Plugin::URIDNSBL", + "Mail::SpamAssassin::Plugin::URIEval", + "Mail::SpamAssassin::Plugin::VBounce", + "Mail::SpamAssassin::Plugin::WLBLEval", + "Mail::SpamAssassin::Plugin::WelcomeListSubject", + "Mail::SpamAssassin::Plugin::WhiteListSubject", +]; + +static SUPPORTED_FUNCTIONS: [&str; 162] = [ + "check_abundant_unicode_ratio", + "check_access_database", + "check_all_trusted", + "check_arc_signed", + "check_arc_valid", + "check_base64_length", + "check_bayes", + "check_blank_line_ratio", + "check_body_8bits", + "check_body_length", + "check_dcc", + "check_dcc_reputation_range", + "check_dkim_adsp", + "check_dkim_dependable", + "check_dkim_signall", + "check_dkim_signed", + "check_dkim_signsome", + "check_dkim_testing", + "check_dkim_valid", + "check_dkim_valid_author_sig", + "check_dkim_valid_envelopefrom", + "check_dmarc_missing", + "check_dmarc_none", + "check_dmarc_pass", + "check_dmarc_quarantine", + "check_dmarc_reject", + "check_dns_sender", + "check_equal_from_domains", + "check_for_ascii_text_illegal", + "check_for_def_dkim_welcomelist_from", + "check_for_def_dkim_whitelist_from", + "check_for_def_spf_welcomelist_from", + "check_for_def_spf_whitelist_from", + "check_for_dkim_welcomelist_from", + "check_for_dkim_whitelist_from", + "check_for_fake_aol_relay_in_rcvd", + "check_for_faraway_charset", + "check_for_faraway_charset_in_headers", + "check_for_forged_eudoramail_received_headers", + "check_for_forged_gmail_received_headers", + "check_for_forged_hotmail_received_headers", + "check_for_forged_juno_received_headers", + "check_for_forged_received_trail", + "check_for_forged_yahoo_received_headers", + "check_for_matching_env_and_hdr_from", + "check_for_mime", + "check_for_mime_html", + "check_for_mime_html_only", + "check_for_missing_to_header", + "check_for_no_hotmail_received_headers", + "check_for_no_rdns_dotcom_helo", + "check_for_shifted_date", + "check_for_spf_fail", + "check_for_spf_helo_fail", + "check_for_spf_helo_neutral", + "check_for_spf_helo_none", + "check_for_spf_helo_pass", + "check_for_spf_helo_permerror", + "check_for_spf_helo_softfail", + "check_for_spf_helo_temperror", + "check_for_spf_neutral", + "check_for_spf_none", + "check_for_spf_pass", + "check_for_spf_permerror", + "check_for_spf_softfail", + "check_for_spf_temperror", + "check_for_spf_welcomelist_from", + "check_for_spf_whitelist_from", + "check_for_to_in_subject", + "check_for_uppercase", + "check_freemail_from", + "check_freemail_header", + "check_freemail_replyto", + "check_from_in_auto_welcomelist", + "check_from_in_auto_whitelist", + "check_from_in_blacklist", + "check_from_in_blocklist", + "check_from_in_default_welcomelist", + "check_from_in_default_whitelist", + "check_from_in_list", + "check_from_in_welcomelist", + "check_from_in_whitelist", + "check_fromname_equals_replyto", + "check_fromname_equals_to", + "check_fromname_spoof", + "check_hashbl_bodyre", + "check_header_count_range", + "check_https_http_mismatch", + "check_https_ip_mismatch", + "check_iframe_src", + "check_illegal_chars", + "check_language", + "check_ma_non_text", + "check_mailfrom_matches_rcvd", + "check_microsoft_executable", + "check_mime_multipart_ratio", + "check_msg_parse_flags", + "check_no_relays", + "check_outlook_message_id", + "check_pyzor", + "check_ratware_envelope_from", + "check_ratware_name_id", + "check_razor2", + "check_razor2_range", + "check_rbl", + "check_rbl_sub", + "check_rbl_txt", + "check_relays_unparseable", + "check_replyto_in_list", + "check_senders_reputation", + "check_shortcircuit", + "check_stock_info", + "check_subject_in_blacklist", + "check_subject_in_blocklist", + "check_subject_in_welcomelist", + "check_subject_in_whitelist", + "check_suspect_name", + "check_to_in_all_spam", + "check_to_in_blacklist", + "check_to_in_blocklist", + "check_to_in_more_spam", + "check_to_in_welcomelist", + "check_to_in_whitelist", + "check_unresolved_template", + "check_uri_host_in_blacklist", + "check_uri_host_in_blocklist", + "check_uri_host_in_welcomelist", + "check_uri_host_in_whitelist", + "check_uri_host_listed", + "check_uri_truncated", + "check_uridnsbl", + "check_welcomelist_bounce_relays", + "check_whitelist_bounce_relays", + "gated_through_received_hdr_remover", + "have_any_bounce_relays", + "helo_ip_mismatch", + "html_charset_faraway", + "html_eval", + "html_image_only", + "html_image_ratio", + "html_range", + "html_tag_balance", + "html_tag_exists", + "html_test", + "html_text_match", + "html_title_subject_ratio", + "image_count", + "image_to_text_ratio", + "multipart_alternative_difference", + "multipart_alternative_difference_count", + "pdf_image_size_range", + "pdf_image_to_text_ratio", + "pdf_is_empty_body", + "pdf_is_encrypted", + "pdf_match_details", + "pixel_coverage", + "short_url", + "short_url_chained", + "similar_recipients", + "sorted_recipients", + "subject_is_all_caps", + "tvd_vertical_words", +]; + +static IF_TRUE: [&str; 25] = [ + "!(!plugin(Mail::SpamAssassin::Plugin::DKIM))", + "(version >= 3.003000)", + "(version >= 3.004000)", + "(version >= 3.004001)", + "(version >= 3.004002)", + "(version >= 3.004003)", + "(version >= 4.000000)", + "can(Mail::SpamAssassin::Conf::feature_bayes_stopwords)", + "can(Mail::SpamAssassin::Conf::feature_bug6558_free)", + "can(Mail::SpamAssassin::Conf::feature_capture_rules)", + "can(Mail::SpamAssassin::Conf::feature_dns_local_ports_permit_avoid)", + "can(Mail::SpamAssassin::Conf::feature_originating_ip_headers)", + "can(Mail::SpamAssassin::Conf::feature_registryboundaries)", + "can(Mail::SpamAssassin::Conf::feature_welcomelist_blocklist)", + "can(Mail::SpamAssassin::Conf::feature_yesno_takes_args)", + "can(Mail::SpamAssassin::Conf::perl_min_version_5010000)", + "can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length)", + "can(Mail::SpamAssassin::Plugin::DKIM::has_arc)", + "can(Mail::SpamAssassin::Plugin::DecodeShortURLs::has_get)", + "can(Mail::SpamAssassin::Plugin::DecodeShortURLs::has_short_url_redir)", + "can(Mail::SpamAssassin::Plugin::MIMEEval::has_check_abundant_unicode_ratio)", + "can(Mail::SpamAssassin::Plugin::MIMEEval::has_check_for_ascii_text_illegal)", + "can(Mail::SpamAssassin::Plugin::SPF::has_check_for_spf_errors)", + "can(Mail::SpamAssassin::Plugin::URIDNSBL::has_tflags_domains_only)", + "can(Mail::SpamAssassin::Plugin::URIDNSBL::has_uridnsbl_for_a)", +]; + +static IF_FALSE: [&str; 22] = [ + "(version < 4.000000)", + "!((version >= 3.003000))", + "!((version >= 3.004000))", + "can(Mail::SpamAssassin::Conf::feature_dns_block_rule)", + "!plugin(Mail::SpamAssassin::Plugin::BodyEval)", + "!plugin(Mail::SpamAssassin::Plugin::DKIM)", + "!plugin(Mail::SpamAssassin::Plugin::FreeMail)", + "!plugin(Mail::SpamAssassin::Plugin::HTMLEval)", + "!plugin(Mail::SpamAssassin::Plugin::HeaderEval)", + "!plugin(Mail::SpamAssassin::Plugin::ImageInfo)", + "!plugin(Mail::SpamAssassin::Plugin::MIMEEval)", + "!plugin(Mail::SpamAssassin::Plugin::MIMEHeader)", + "!plugin(Mail::SpamAssassin::Plugin::ReplaceTags)", + "!plugin(Mail::SpamAssassin::Plugin::SPF)", + "!plugin(Mail::SpamAssassin::Plugin::WLBLEval)", + "!plugin(Mail::SpamAssassin::Plugin::WelcomeListSubject)", + "!(can(Mail::SpamAssassin::Conf::feature_bug6558_free))", + "!(can(Mail::SpamAssassin::Plugin::ASN::has_check_asn))", + "!(can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length))", + "!can(Mail::SpamAssassin::Conf::compat_welcomelist_blocklist)", + "!can(Mail::SpamAssassin::Conf::feature_welcomelist_blocklist)", + "!can(Mail::SpamAssassin::Plugin::DecodeShortURLs::has_short_url_redir)", +]; + +pub fn import_spamassassin(path: PathBuf, extension: String, do_warn: bool, validate_regex: bool) { + let mut paths: Vec<_> = fs::read_dir(&path) + .unwrap_result("read directory") + .map(|r| r.unwrap_result("read directory entry")) + .collect(); + paths.sort_by_key(|dir| dir.path()); + + let mut rules: HashMap = HashMap::new(); + let mut lists: HashMap> = HashMap::new(); + + let mut replace_start = '<'; + let mut replace_end = '>'; + let mut replace_rules: HashSet = HashSet::new(); + let mut tags: HashMap = HashMap::new(); + + let mut unsupported_plugins: BTreeMap>> = BTreeMap::new(); + let mut unsupported_commands: BTreeMap>> = BTreeMap::new(); + + for path in paths { + let path = path.path(); + + if path + .extension() + .unwrap_or_default() + .to_str() + .unwrap_or_default() + != extension + { + continue; + } + + /*if !path + .file_name() + .unwrap() + .to_str() + .unwrap() + .contains("23_bayes") + { + continue; + }*/ + + let mut is_supported_block = true; + let mut is_supported_stack = Vec::new(); + + for (line_num, line_) in fs::read_to_string(&path) + .unwrap_or_else(|_| { + let bytes = fs::read(&path).unwrap_result(&format!("read file {}", path.display())); + if do_warn { + eprintln!( + "Warning: file {} opened using ISO-8859-1 encoding", + path.display() + ); + } + bytes.iter().map(|&c| c as char).collect() + }) + .lines() + .enumerate() + { + let mut line = String::with_capacity(line_.len()); + let mut last_ch = ' '; + for ch in line_.chars() { + if ch.is_ascii_whitespace() { + if line.is_empty() { + continue; + } else { + line.push(' '); + } + } else if ch == '#' && last_ch != '\\' { + break; + } else { + line.push(ch); + } + last_ch = ch; + } + + let (cmd, params) = line + .split_once(' ') + .map(|(k, v)| (k.trim(), v.trim())) + .unwrap_or((line.as_str().trim(), "")); + + if cmd.is_empty() { + continue; + } + let todo = "GB_TO_ADDR caca"; + + match cmd { + "ifplugin" => { + is_supported_stack.push(is_supported_block); + is_supported_block = SUPPORTED_PLUGINS.contains(¶ms); + + if !is_supported_block { + unsupported_plugins + .entry(params.to_string()) + .or_default() + .entry(path.clone()) + .or_default() + .push(line_num.to_string()); + } + } + "if" => { + is_supported_stack.push(is_supported_block); + is_supported_block = IF_TRUE.contains(¶ms); + if !is_supported_block && !IF_FALSE.contains(¶ms) { + eprintln!( + "Warning: Unknown if condition on {}, line {}", + path.display(), + line_num + ); + } + } + "endif" => { + if let Some(last_if) = is_supported_stack.pop() { + is_supported_block = last_if; + } else { + eprintln!( + "Warning: Unmatched endif on {}, line {}", + path.display(), + line_num + ); + } + } + _ if !is_supported_block => {} + + "describe" => { + if let Some((name, description)) = params.split_once(' ') { + let description = description.trim(); + if !description.is_empty() { + rules + .entry(name.to_string()) + .or_default() + .description + .insert("en".to_string(), description.to_string()); + } + } + } + + "header" | "body" | "rawbody" | "full" | "mimeheader" | "uri" => { + if let Some((name, value)) = + params.split_once(' ').map(|(k, v)| (k.trim(), v.trim())) + { + let mut rule = rules.entry(name.to_string()).or_default(); + + if let Some(function) = value.strip_prefix("eval:") { + if let Some((fnc_name, params_)) = function + .split_once('(') + .and_then(|(k, v)| (k.trim(), v.trim().strip_suffix(')')?).into()) + { + if SUPPORTED_FUNCTIONS.contains(&fnc_name) { + let mut params = Vec::new(); + let mut in_quote = false; + let mut is_escaped = false; + let mut buf = String::new(); + + for ch in params_.chars() { + match ch { + '"' | '\'' if !is_escaped => { + buf.push('\"'); + if in_quote { + params.push(buf); + buf = String::new(); + in_quote = false; + } else { + in_quote = true; + } + } + ' ' if !in_quote => {} + ',' if !in_quote => { + if !buf.is_empty() { + params.push(buf); + buf = String::new(); + } + } + _ => { + if is_escaped { + is_escaped = false; + } else if ch == '\\' { + is_escaped = true; + } + + buf.push(ch); + } + } + } + if !buf.is_empty() { + params.push(buf); + } + rule.t = RuleType::Eval { + function: fnc_name.to_string(), + params, + }; + } else { + eprintln!( + "Warning: Unsupported function {function:?} on {}, line {}", + path.display(), + line_num + ); + } + } else { + eprintln!( + "Warning: Invalid function {function:?} on {}, line {}", + path.display(), + line_num + ); + } + } else if cmd == "header" || cmd == "mimeheader" { + if let Some(exists) = value.strip_prefix("exists:") { + rule.t = RuleType::Header { + matches: HeaderMatches::Exists, + header: Header::Name { + name: exists.to_string(), + part: vec![], + }, + if_unset: None, + pattern: String::new(), + }; + } else if let Some((header, (op, mut pattern))) = value + .split_once(' ') + .and_then(|(k, v)| (k.trim(), v.trim().split_once(' ')?).into()) + { + rule.t = RuleType::Header { + matches: match op { + "=~" => HeaderMatches::Matches, + "!~" => HeaderMatches::NotMatches, + _ => { + eprintln!( + "Warning: Invalid operator {op:?} on {}, line {}", + path.display(), + line_num + ); + continue; + } + }, + header: if let Some((header, part)) = header.split_once(':') { + Header::Name { + name: header.to_string(), + part: part.split(':').filter_map(|part| { + match part { + "name" => {Some(HeaderPart::Name)} + "addr" => {Some(HeaderPart::Addr)} + "raw" => {Some(HeaderPart::Raw)} + _ => { + eprintln!( + "Warning: Invalid header part {part:?} on {}, line {}", + path.display(), + line_num + ); + None + } + } + + }).collect::>() + } + } else { + match header { + "ALL" => Header::All, + "MESSAGEID" => Header::MessageId, + "ALL-EXTERNAL" => Header::AllExternal, + "EnvelopeFrom" => Header::EnvelopeFrom, + "ToCc" => Header::ToCc, + _ => Header::Name { + name: header.to_string(), + part: vec![], + }, + } + }, + if_unset: pattern.rsplit_once("[if-unset:").and_then( + |(new_pattern, if_unset)| { + pattern = new_pattern.trim(); + if let Some(if_unset) = + if_unset.strip_suffix(']').map(|v| v.trim()) + { + if_unset.to_string().into() + } else { + eprintln!( + "Warning: Failed to parse if_unset for header command on {}, line {}", + path.display(), + line_num + ); + None + } + }, + ), + pattern: fix_broken_regex(pattern).to_string(), + }; + } else { + eprintln!( + "Warning: Invalid header command on {}, line {}", + path.display(), + line_num + ); + } + } else if value.starts_with('/') || value.starts_with('m') { + let pattern = fix_broken_regex(value).to_string(); + rule.t = match cmd { + "body" | "rawbody" => RuleType::Body { + pattern, + raw: cmd == "rawbody", + }, + "full" => RuleType::Full { pattern }, + "uri" => RuleType::Uri { pattern }, + + _ => unreachable!(), + } + } else { + eprintln!( + "Warning: Invalid header command on {}, line {}", + path.display(), + line_num + ); + } + } else { + eprintln!( + "Warning: Invalid header command on {}, line {}", + path.display(), + line_num + ); + } + } + "lang" => { + if let Some((lang, (command, params))) = params.split_once(' ').map(|(k, v)| { + (k.trim(), v.trim().split_once(' ').unwrap_or((v.trim(), ""))) + }) { + if command == "describe" { + if let Some((id, description)) = params.trim().split_once(' ') { + let description = description.trim(); + if !description.is_empty() { + rules + .entry(id.to_string()) + .or_default() + .description + .insert(lang.to_string(), description.to_string()); + } + } else { + eprintln!( + "Warning: Invalid lang command on {}, line {}", + path.display(), + line_num + ); + } + } + } else { + eprintln!( + "Warning: Invalid lang command on {}, line {}", + path.display(), + line_num + ); + } + } + "meta" => { + if let Some((test_name, expression)) = params.split_once(' ') { + let tokens = MetaExpression::from_meta(expression); + if tokens.tokens.contains(&Token::Divide) { + println!( + "->: {expression}\n{:?}\n<-: {}", + tokens + .tokens + .iter() + .zip(tokens.token_depth.iter()) + .collect::>(), + String::from(tokens.clone()) + ); + std::process::exit(1); + } + rules.entry(test_name.to_string()).or_default().t = RuleType::Meta { + tokens: tokens.tokens, + }; + } else { + eprintln!( + "Warning: Invalid meta command on {}, line {}", + path.display(), + line_num + ); + } + } + + "priority" => { + let mut params = params.split_ascii_whitespace(); + if let (Some(id), Some(priority)) = ( + params.next(), + params.next().and_then(|v| v.trim().parse::().ok()), + ) { + rules.entry(id.to_string()).or_default().priority = priority; + } else { + eprintln!( + "Warning: Invalid priority command on {}, line {}", + path.display(), + line_num + ); + } + } + + "score" => { + let mut params = params.split_ascii_whitespace(); + if let Some(id) = params.next() { + let mut score_list = Vec::new(); + for score in params { + if let Ok(score) = score.parse::() { + score_list.push(score); + } else { + eprintln!( + "Warning: Failed to parse score on {}, line {}", + path.display(), + line_num + ); + } + } + + if score_list.len() > 4 { + eprintln!( + "Warning: Too many scores on {}, line {}", + path.display(), + line_num + ); + } else if score_list.is_empty() { + eprintln!( + "Warning: No scores found on {}, line {}", + path.display(), + line_num + ); + } + + rules.entry(id.to_string()).or_default().scores = score_list; + } else { + eprintln!( + "Warning: Invalid score command on {}, line {}", + path.display(), + line_num + ); + } + } + "tflags" => { + let mut params = params.split_ascii_whitespace(); + if let Some(test_name) = params.next() { + let test_flags = &mut rules.entry(test_name.to_string()).or_default().flags; + for flag in params { + test_flags.push(match flag { + "net" => { + TestFlag::Net + } + "nice" => {TestFlag::Nice} + "userconf" => {TestFlag::UserConf} + "learn" => {TestFlag::Learn} + "noautolearn" => {TestFlag::NoAutoLearn} + "publish" => {TestFlag::Publish} + "multiple" => {TestFlag::Multiple} + "notrim" => {TestFlag::NoTrim} + "domains_only" => {TestFlag::DomainsOnly} + "nosubject" => {TestFlag::NoSubject} + "autolearn_body" => {TestFlag::AutoLearnBody} + "a" => {TestFlag::A} + _ => { + match flag.split_once('=').and_then(|(k, v)| { + (k.trim(), v.trim().parse::().ok()?).into() + }) { + Some(("maxhits", value)) => {TestFlag::MaxHits(value)} + _ => { + eprintln!( + "Warning: Invalid tflags value {flag} on {}, line {}", + path.display(), + line_num + ); + continue; + } + } + } + }); + } + } else { + eprintln!( + "Warning: Invalid tflags command on {}, line {}", + path.display(), + line_num + ); + } + } + + "replace_rules" => { + for test_name in params.split_ascii_whitespace() { + replace_rules.insert(test_name.to_string()); + } + } + "replace_tag" | "replace_inter" | "replace_post" | "replace_pre" => { + if let Some((tag, pattern)) = params.split_once(' ') { + let pattern = replace_tags(pattern, replace_start, replace_end, &tags); + if validate_regex { + if let Err(err) = fancy_regex::Regex::new(&pattern) { + eprintln!( + "Warning: Invalid regex {pattern:?} on {}, line {}: {}", + path.display(), + line_num, + err + ); + } + } + let tag_class = cmd.strip_prefix("replace_").unwrap(); + let tag = if tag_class != "tag" { + format!("{} {}", tag_class, tag) + } else { + tag.to_string() + }; + tags.insert(tag, pattern); + } else { + eprintln!( + "Warning: Invalid replace_tag command on {}, line {}", + path.display(), + line_num + ); + } + } + "replace_start" => { + if let Some(ch) = params.chars().next() { + replace_start = ch; + } + } + "replace_end" => { + if let Some(ch) = params.chars().next() { + replace_end = ch; + } + } + + "askdns" => { + if let Some((test_name, query, (record_type, pattern))) = params + .split_once(' ') + .and_then(|(a, b)| (a.trim(), b.trim().split_once(' ')?).into()) + .and_then(|(a, (b, c))| (a, b.trim(), c.trim().split_once(' ')?).into()) + { + rules.entry(test_name.to_string()).or_default().t = RuleType::Eval { + function: "askdns".to_string(), + params: vec![ + query.to_string(), + record_type.to_string(), + pattern.to_string(), + ], + }; + } else { + eprintln!( + "Warning: Invalid askdns command on {}, line {}", + path.display(), + line_num + ); + } + } + "def_welcomelist_auth" + | "def_welcomelist_from_dkim" + | "def_welcomelist_from_spf" => { + let list = lists + .entry( + cmd.strip_prefix("def_welcomelist_") + .unwrap() + .replace('_', "-"), + ) + .or_default(); + for item in params.split_ascii_whitespace() { + list.insert(item.to_string()); + } + } + "else" => { + is_supported_block = !is_supported_block; + } + "enlist_addrlist" | "enlist_uri_host" => { + let mut params = params.split_ascii_whitespace(); + if let Some(list_name) = params + .next() + .and_then(|s| s.strip_prefix('(')) + .and_then(|s| s.strip_suffix(')')) + { + let list = lists + .entry(format!( + "{}-{}", + cmd.strip_prefix("enlist_").unwrap().replace('_', "-"), + list_name.to_lowercase() + )) + .or_default(); + for item in params { + list.insert(item.to_string()); + } + } else { + eprintln!( + "Warning: Invalid enlist command on {}, line {}", + path.display(), + line_num + ); + } + } + "freemail_domains" + | "uridnsbl_skip_domain" + | "url_shortener" + | "url_shortener_get" + | "util_rb_2tld" + | "util_rb_3tld" + | "util_rb_tld" + | "originating_ip_headers" + | "redirector_pattern" + | "bayes_ignore_header" => { + let list = lists.entry(cmd.replace('_', "-")).or_default(); + for item in params.split_ascii_whitespace() { + list.insert(item.to_string()); + } + } + "uridnssub" | "urirhssub" => { + if let Some((test_name, queryhost, (record_type, result))) = params + .split_once(' ') + .and_then(|(a, b)| (a.trim(), b.trim().split_once(' ')?).into()) + .and_then(|(a, (b, c))| (a, b.trim(), c.trim().split_once(' ')?).into()) + { + rules.entry(test_name.to_string()).or_default().t = RuleType::Eval { + function: cmd.to_string(), + params: vec![ + queryhost.to_string(), + record_type.to_string(), + result.to_string(), + ], + }; + } else { + eprintln!( + "Warning: Invalid {cmd} command on {}, line {}", + path.display(), + line_num + ); + } + } + "dns_block_rule" => { + if let Some((test_name, host)) = params.split_once(' ') { + rules + .entry(test_name.to_string()) + .or_default() + .flags + .push(TestFlag::DnsBlockRule(host.trim().to_string())); + } else { + eprintln!( + "Warning: Invalid {cmd} command on {}, line {}", + path.display(), + line_num + ); + } + } + + "fns_check" + | "fns_ignore_dkim" + | "fns_ignore_headers" + | "dns_local_ports_avoid" + | "def_whitelist_auth" + | "def_whitelist_from_dkim" + | "def_whitelist_from_spf" + | "asn_lookup" + | "adsp_override" + | "reuse" + | "test" + | "report" + | "report_contact" + | "report_safe" + | "require_version" + | "required_score" + | "ok_languages" + | "ok_locales" + | "unsafe_report" + | "add_header" + | "clear_headers" + | "clear_originating_ip_headers" + | "clear_report_template" + | "clear_unsafe_report_template" + | "clear_util_rb" => {} // Ignored + + _ => { + if !cmd.starts_with("bayes_") { + unsupported_commands + .entry(cmd.to_string()) + .or_default() + .entry(path.clone()) + .or_default() + .push(line_num.to_string()); + } + } + } + } + + if !is_supported_stack.is_empty() { + eprintln!("Warning: Unmatched if on {}", path.display(),); + } + } + + //println!("description: {:#?}", descriptions); + //println!("scores: {:#?}", ifs); + + for test_name in replace_rules { + if let Some(rule) = rules.get_mut(&test_name) { + match rule.t.pattern() { + Some(pattern) if !pattern.is_empty() => { + *pattern = replace_tags(pattern, replace_start, replace_end, &tags); + } + _ => { + eprintln!("Warning: Empty pattern for replace_rules command.",); + } + } + } else { + eprintln!("Warning: Test {test_name:?} not found for replace_rules command.",); + } + } + + let mut rules = rules + .into_iter() + .filter_map(|(name, mut rule)| { + if !matches!(rule.t, RuleType::None) { + if validate_regex { + if let Some(pattern) = rule.t.pattern() { + if let Err(err) = fancy_regex::Regex::new(pattern) { + eprintln!( + "Warning: Invalid regex {} for test {}: {}", + pattern, name, err + ); + } + } + } + rule.name = name; + rule.into() + } else { + if do_warn { + eprintln!("Warning: Test {name} has no type: {rule:?}"); + } + None + } + }) + .collect::>(); + rules.sort_unstable_by(|a, b| b.cmp(a)); + + let no_meta: Vec = vec![]; + let mut meta = &no_meta; + + let mut tests_done = HashSet::new(); + let mut rules_iter = rules.iter(); + let mut rules_stack = Vec::new(); + + loop { + while let Some(rule) = rules_iter.next() { + if tests_done.contains(&rule.name) + || (!meta.is_empty() + && !meta + .iter() + .any(|t| matches!(t, Token::Tag(n) if n == &rule.name))) + { + continue; + } + + match &rule.t { + RuleType::Meta { tokens } => { + meta = tokens; + rules_stack.push((meta, rules_iter)); + rules_iter = rules.iter(); + } + RuleType::Header { + matches, + header, + if_unset, + pattern, + } => todo!(), + RuleType::Body { pattern, raw } => todo!(), + RuleType::Full { pattern } => todo!(), + RuleType::Uri { pattern } => todo!(), + RuleType::Eval { function, params } => todo!(), + RuleType::None => (), + } + + tests_done.insert(&rule.name); + } + + if let Some((prev_meta, prev_rules_iter)) = rules_stack.pop() { + for token in meta { + //TODO + } + + rules_iter = prev_rules_iter; + meta = prev_meta; + } else { + break; + } + } + + for (message, unsupported) in [ + ("commands", unsupported_commands), + ("plugins", unsupported_plugins), + ] { + if !unsupported.is_empty() { + eprintln!("Unsupported {}:", message); + for (cmd, paths) in unsupported { + eprintln!( + " {} in {}", + cmd, + paths + .into_iter() + .map(|(k, v)| format!( + "{}:[{}]", + k.file_name().unwrap().to_str().unwrap(), + v.into_iter().take(5).collect::>().join(",") + )) + .collect::>() + .join(", ") + ); + } + } + } +} diff --git a/crates/antispam/src/import/utils.rs b/crates/antispam/src/import/utils.rs new file mode 100644 index 00000000..660bf089 --- /dev/null +++ b/crates/antispam/src/import/utils.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; + +pub fn replace_tags( + pattern: &str, + tag_start: char, + tag_end: char, + patterns: &HashMap, +) -> String { + //print!("replacing {} ", pattern); + let mut result = String::with_capacity(pattern.len()); + let mut chars = fix_broken_regex(pattern.trim()).chars(); + let mut tag_pre = String::new(); + let mut tag_inter = String::new(); + let mut tag_post = String::new(); + let mut is_adjacent = false; + + 'outer: while let Some(ch) = chars.next() { + if ch == tag_start { + let mut buf = String::new(); + for ch in chars.by_ref() { + if ch == tag_end { + break; + } else if ch.is_ascii_alphanumeric() || ch.is_ascii_whitespace() { + buf.push(ch); + } else { + result.push(tag_start); + result.push_str(&buf); + result.push(ch); + continue 'outer; + } + } + if let Some(pattern) = patterns.get(&buf) { + if buf.starts_with("pre ") { + tag_pre = pattern.to_string(); + } else if buf.starts_with("inter ") { + tag_inter = pattern.to_string(); + } else if buf.starts_with("post ") { + tag_post = pattern.to_string(); + } else { + if !tag_pre.is_empty() { + result.push_str(&tag_pre); + } + if !tag_inter.is_empty() && is_adjacent { + result.push_str(&tag_inter); + } + result.push_str(pattern); + if !tag_post.is_empty() { + result.push_str(&tag_post); + } + is_adjacent = true; + } + } else { + eprintln!("Warning: Unknown tag {}", buf); + } + } else { + result.push(ch); + is_adjacent = false; + } + } + + //println!("to {}", result); + + result +} + +pub fn fix_broken_regex(value: &str) -> &str { + match value { + r#"/[\042\223\224\262\263\271]{2}\S{0,16}[\042\223\224\262\263\271]{2}/"# => { + //r#"[\"\u{93}\u{94}\u{B2}\u{B3}\u{B9}]{2}\S{0,16}[\"\u{93}\u{94}\u{B2}\u{B3}\u{B9}]{2}"# + r#"/[\x22\x93\x94\xB2\xB3\xB9]{2}\S{0,16}[\x22\x93\x94\xB2\xB3\xB9]{2}/"# + } + r#"/\b_{0,3}d[_\W]?[i1!|l\xEC-\xEF][_\W]?d[_\W]?r[_\W][e3\xE8-\xEB[_\W]?xx?_{0,3}\b/i"# => { + r#"/\b_{0,3}d[_\W]?[i1!|l\xEC-\xEF][_\W]?d[_\W]?r[_\W][e3\xE8-\xEB][_\W]?xx?_{0,3}\b/i"# + } + r#"/\w/ + tflags __HTML_SHRT_CMNT_OBFU multiple maxhits=10 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __HTML_SHRT_CMNT_OBFU_MANY __HTML_SHRT_CMNT_OBFU > 5 && HTML_MESSAGE +endif + +rawbody __HTML_SINGLET />\s*(?:[a-z"]|&\#(?:\d+|x[0-9a-f]+);)\s* 10 + +meta __HTML_SINGLET_MANY __HTML_SINGLET > 20 + +ifplugin Mail::SpamAssassin::Plugin::HTMLEval + body __HTML_TAG_BALANCE_CENTER eval:html_tag_balance('center', '!= 0') +endif + +body __HUSH_HUSH /\b(?:confiden[tc]i[ae]l(?:\b|ity\b|it(?:=E9|[\xe9]|[\xc3][\xa9]))|private\b|secr[e\xe8](?:te?|cy)\b|sensitive\b|concealed\b|obscured?\b|discre(?:et|tion)\b|very\sdiscrete|top\ssecret|vertraulich(?:en)?\b|geheim\b|priv(?:e|=E9|[\xe9]|[\xc3][\xa9]))/i + +uri __IMGUR_IMG m,^https?://(?:[^.]+\.)?imgur\.com/[a-z0-9]{7}\.(?:png|gif|jpe?g)$,i +tflags __IMGUR_IMG multiple maxhits=4 + +meta __IMGUR_IMG_2 __IMGUR_IMG == 2 + +meta __IMGUR_IMG_3 __IMGUR_IMG == 3 + +if !plugin(Mail::SpamAssassin::Plugin::ImageInfo) + meta __IMG_LE_300K 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ImageInfo + body __IMG_LE_300K eval:pixel_coverage('all',62500,300000) +endif + +body __INHERIT_PMT /\binheritance\spayment\s/i + +body __INTL_BANK /\b(?:international\s(?:\w+\s)?bank|banque\sinternationale)\b/i + +body __INVEST_COUNTRY /\binvest\sin\syour?\scountry\b/i + +body __INVEST_MONEY /\binvest(?:ir)?\s(?:this|ces|d[ae]s|sur ce|de ces)\s(?:money|f[ou]nds?)\b/i + +header __IP_IN_RELAY X-Spam-Relays-External =~ /^\[ ip=(\d+)\.(\d+)\.(\d+)\.(\d+) (?:[^\]]* )?(?:rdns|helo)=\S*(?:\1\D\2\D\3\D\4|\4\D\3\D\2\D\1)/ + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __ISO_ATTACH 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __ISO_ATTACH Content-Disposition =~ m,\bfilename="?[^"]+\.iso[";$],i +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __ISO_ATTACH_MT 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __ISO_ATTACH_MT Content-Type =~ m,\bapplication/x-iso9660-image\b,i +endif + +body __IS_LEGAL /\b(?:(?:(this|esta)\s(?:deal|offer|transac[tc]i(?:o|[\xc3][\xb3])n|proposal|exchange|arrangement|work)|it)?\s[ie]s\s(?:(?:guaranteed|completely|absolutely|perfectly|100%|very|fully)\s)?(?:legal|hitch-free|seguro|legitimate)|legitimate\sarrangement|toute?\sl(?:e|=E9|[\xe9]|[\xc3][\xa9])gale)\b/i + +body __IVORY_COAST /\b(?:Cote\s?D.Ivoire|Ivory\s?Coast|Costa\sde\sMarfil)\b/i + +body __I_INHERIT /\b(?:I|eu)\s[a-z\s]{0,30}(?:inherited|herdei)\b/i + +body __I_WILL_YOU /\bwill(?:ed)?\s(?:[a-z\s]{0,20}(?:fortune|money|\$[\d,]+[a-z]{0,9})\s)?to\syou\b/i + +header __JM_REACTOR_DATE Date =~ / \+0000$/ + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __JPEG_ATTACH Content-Type =~ /image\/jpe?g/i +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __KAM_BLOCK_UTF7_2 Content-Type =~ /charset=(?:unicode-\d+-\d+-)?utf-7/i +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + body __KAM_BODY_LENGTH_LT_1024 eval:check_body_length('1024') + describe __KAM_BODY_LENGTH_LT_1024 The length of the body of the email is less than 1024 bytes. +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + body __KAM_BODY_LENGTH_LT_128 eval:check_body_length('128') + describe __KAM_BODY_LENGTH_LT_128 The length of the body of the email is less than 128 bytes. +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + body __KAM_BODY_LENGTH_LT_256 eval:check_body_length('256') + describe __KAM_BODY_LENGTH_LT_256 The length of the body of the email is less than 256 bytes. +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + body __KAM_BODY_LENGTH_LT_512 eval:check_body_length('512') + describe __KAM_BODY_LENGTH_LT_512 The length of the body of the email is less than 512 bytes. +endif +endif + +if !plugin(Mail::SpamAssassin::Plugin::HTMLEval) +meta __KAM_HTML_FONT_INVALID 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::HTMLEval +body __KAM_HTML_FONT_INVALID eval:html_test('font_invalid_color') +endif + +body __KAM_LOTTO2 /((ticket|serial|lucky) number|secret pin ?code|batch number|reference number|promotion date)/is + +header __KB_DATE_CONTAINS_TAB Date:raw =~ /^\t/ + +header __KB_MSGID_OUTLOOK_888 Message-Id =~ /^<[0-9a-f]{8}(?:\$[0-9a-f]{8}){2}\@/ + +meta __KHOP_NO_FULL_NAME !(__NOT_A_PERSON || __FROM_ENCODED_QP || __FROM_NEEDS_MIME || __FROM_FULL_NAME) + +if !(can(Mail::SpamAssassin::Conf::feature_bug6558_free)) + meta __LARGE_PERCENT_AFTER 0 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + body __LARGE_PERCENT_AFTER /\d{3}% after/i + tflags __LARGE_PERCENT_AFTER multiple maxhits=4 +endif + +if !plugin(Mail::SpamAssassin::Plugin::HeaderEval) + meta __LCL__ENV_AND_HDR_FROM_MATCH 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::HeaderEval + meta __LCL__ENV_AND_HDR_FROM_MATCH __ENV_AND_HDR_FROM_MATCH +endif + +if !plugin(Mail::SpamAssassin::Plugin::BodyEval) + meta __LCL__KAM_BODY_LENGTH_LT_1024 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval +if !(can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length)) + meta __LCL__KAM_BODY_LENGTH_LT_1024 0 +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + meta __LCL__KAM_BODY_LENGTH_LT_1024 __KAM_BODY_LENGTH_LT_1024 +endif +endif + +if !plugin(Mail::SpamAssassin::Plugin::BodyEval) + meta __LCL__KAM_BODY_LENGTH_LT_128 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval +if !(can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length)) + meta __LCL__KAM_BODY_LENGTH_LT_128 0 +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + meta __LCL__KAM_BODY_LENGTH_LT_128 __KAM_BODY_LENGTH_LT_128 +endif +endif + +if !plugin(Mail::SpamAssassin::Plugin::BodyEval) + meta __LCL__KAM_BODY_LENGTH_LT_512 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval +if !(can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length)) + meta __LCL__KAM_BODY_LENGTH_LT_512 0 +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::BodyEval + if can(Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length) + meta __LCL__KAM_BODY_LENGTH_LT_512 __KAM_BODY_LENGTH_LT_512 +endif +endif + +meta __LINKED_IMG_NOT_RCVD_LINK __URI_IMG_LINKEDIN && !__HDR_RCVD_LINKEDIN + +meta __LIST_PARTIAL __DOS_HAS_LIST_UNSUB && !__DOS_HAS_LIST_ID + +meta __LIST_PRTL_PUMPDUMP __LIST_PARTIAL && __PD_CNT_1 + +meta __LIST_PRTL_SAME_USER __LIST_PARTIAL && __TO_EQ_FROM_USR + +body __LITECOIN_ID /\b(?[^<\s]{1400}/i + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __LONG_STY_INVIS __STY_INVIS && __LONGLINE +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __LOTSA_MONEY_00 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __LOTSA_MONEY_00 /[\s\.]?[\dOo][,\.][\dOo]{3}(?:(?!\d)|\b)/ +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __LOTSA_MONEY_01 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __LOTSA_MONEY_01 /(?:(?i:sum\sof\s)[\(\[]?|\s?)[\s\.]?[\d.,\sOo]{5,20}[\dOo](?[\d.,\sOo]{5,20}[\dOo][\)\]\(]?\s?(?:|Pounds|(?i:dollars?|bucks))\b/ +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __LOTSA_MONEY_03 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __LOTSA_MONEY_03 /(?:(?i:sum\sof\s)[\(\[]?|\s?)[\d.,\sOo]{0,5}[\)\]]?\s?(?i:M(?i:il+)?\b|mil+(?i:io|)n|hund?[re]+a?[dt]|thousand|tausend|milh[\xf5]es)/ +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __LOTSA_MONEY_04 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __LOTSA_MONEY_04 /(?:(?[\d\.,]{0,4}(?:M|\smilli?one?s|\s?mln)|million(?!s)|milln|hund?rea?d(?!s)[^\.]{1,25}thousand(?!s)|cents?[^\.]{1,25}mille|hundert[^\.]{1,30}tausend|ientos?[^\.]{1,20}mil|cent[a-z\s]{1,20}mil\s[a-z]{1,20}centos)[^\.\$]{0,50}?(?:(?:U\.?\s?S\.?\s?(?:A\.?\s?)?|united\s?states\s|E\.\s?U\.\s|canad(?:ian|a)\s|(?:ia\s)?de\s)?d(?:[o\xf3]|[\xc3][\xb3])l+are?s?|\bbucks|USD|GBP|\spounds?|(?:\s)?pounds?\ssterling|pounds(?!\sof)|(?:d'\s?)?euros?|francs?)\b/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __LOTSA_MONEY_05 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __LOTSA_MONEY_05 /(?:(?:sum|value|amount)\sof\s)[\d.,\sO]{7,20}[\dO\.][\)\]\(\s]{0,3}(?:pounds?|dollars?|euros?|bucks)\b/i +endif + +meta __LOTTO_ADMITS __LOTTO_ADMITS_1 || __LOTTO_ADMITS_2 || __LOTTO_ADMITS_3 || __LOTTO_ATTACH_1 || __LOTTO_ATTACH_2 + +body __LOTTO_ADMITS_1 /\b(?:on-?line|e-?mail|ballot|(?:inter)?national|state|(?:UK|euro)[- ]?(?:mil+ions?|PW)|Canada|Microsoft|MSN|internet|mega|jackpot+|Royal Heritage|foundation|cash\sgrant|mercato|univers|staatsloterij|bill\s?gates|Olympics?|swiss|this|est[ea]|internationaux de gagnants de)(?:\s(?!lot|swe|prom)\w{1,20}){0,3}\s?(?:lot(?:to|t+ery|eri[ea])|sweepstakes?|promo(?:tion|cao|cion)?|jackpot+)\b/i + +body __LOTTO_ADMITS_2 /\b(?:free)?(?:lot(?:to|tery|erie)|sweepstakes)\s(?:(?:inter)?na[tz]ional|department|bureau|group|award|microsoft)/i + +uri __LOTTO_ADMITS_3 /lott+ery/i + +meta __LOTTO_AGENT __LOTTO_AGENT_01 || __LOTTO_AGENT_02 + +body __LOTTO_AGENT_01 /\b(?:(?:(?:the|y?our)(?:\s\w{1,20})?|contact|accredited|listed)\sclaim(?:s|ing)?(?:\sprocessing)?|fiducia\w+|reimbursement|(?:prize|international|intl|foreign|win+ing)(?:[\s,.]+(?:rem+it+ance|settlement|payment|payout|award|transfer))+|payment|payout|immunity|(? 1 + +meta __MANY_SPAN_IN_TEXT (__SPAN_BEG_TEXT > 4) && (__SPAN_END_TEXT > 4) + +header __MAY_BE_FORGED Received =~ /\(may be forged\)/ + +header __MID_START_001C Message-ID =~ /^<000001c/ + +body __MILLIONS /\bmillions\sof\s(?:dollar|euro|pound)/i + +header __MIMEOLE_1106 X-MimeOLE =~ /^Produced By Microsoft MimeOLE V6.00.2800.1106$/ + +meta __MIMEOLE_DIRECT_TO_MX __HAS_MIMEOLE && __DOS_DIRECT_TO_MX + +header __MIME_BDRY_0D0D Content-Type =~ /boundary="-{12}(?:0[1-9]){12}/ + +if !((version >= 3.004000)) + meta __MIME_CTYPE_IN_BODY 0 +endif + +if (version >= 3.004000) + body __MIME_CTYPE_IN_BODY /^Content-Type:\s/ +endif + +if !((version >= 3.004000)) + meta __MIME_MALF 0 +endif + +if (version >= 3.004000) + meta __MIME_MALF __CTYPE_MULTIPART_ANY && __MIME_CTYPE_IN_BODY +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __MIME_NO_TEXT 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + meta __MIME_NO_TEXT (__CTYPE_MULTIPART_ANY && !__ANY_TEXT_ATTACH) +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEEval + rawbody __MIME_QPC eval:check_for_mime('mime_qp_count') +endif + +header __MISSING_REF References =~ /^UNSET$/ [if-unset: UNSET] + +header __MISSING_REPLY In-Reply-To =~ /^UNSET$/ [if-unset: UNSET] + +rawbody __MIXED_AREA_CASE /<(?!AREA|area)[Aa][Rr][Ee][Aa]\s/ + +rawbody __MIXED_CENTER_CASE /<(?!CENTER|center)[Cc][Ee][Nn][Tt][Ee][Rr]>/ + +rawbody __MIXED_FONT_CASE /<(?!FONT|font)[Ff][Oo][Nn][Tt]\s/ + +rawbody __MIXED_HREF_CASE_JH /<[Aa](?i:rea)?\s+(?!HREF|href)[Hh][Rr][Ee][Ff]=/ + +rawbody __MIXED_IMG_CASE_JH /<(?!IMG|img)[Ii][Mm][Gg]\s/ + +header __MOLE_2962 X-MimeOLE =~ /^Produced\ By\ Microsoft\ MimeOLE\ V6\.00\.2900\.2962$/ + +meta __MONERO (__MONERO_ID || __MONERO_CURNCY || __URI_MONERO || __FUZZY_MONERO) + +body __MONERO_CURNCY /Monero \(XMR\)/ + +body __MONERO_ID /\b4[0-9AB][1-9A-HJ-NP-Za-km-z]{93,104}\b/ + +meta __MONEY_ATM_CARD LOTS_OF_MONEY && __ATM_CARD + +meta __MONEY_FORM LOTS_OF_MONEY && __FILL_THIS_FORM + +meta __MONEY_FORM_SHORT LOTS_OF_MONEY && __FILL_THIS_FORM_SHORT + +meta __MONEY_FRAUD_3 LOTS_OF_MONEY && (__FRAUD_VQE + __FRAUD_KJV + __FRAUD_IRJ + __FRAUD_NEB + __FRAUD_XJR + __FRAUD_DPR + __FRAUD_BEP + __FRAUD_TDP + __FRAUD_GAN + __FRAUD_IRT + __FRAUD_AON + __FRAUD_WNY + __FRAUD_IPK + __FRAUD_QXX + __FRAUD_IOV + __FRAUD_MLY + __FRAUD_ULK + __FRAUD_BGP + __FRAUD_YWW + __FRAUD_JYG + __FRAUD_XWW + __FRAUD_UUY + __FRAUD_SNT + __FRAUD_JNB + __FRAUD_QFY + __FRAUD_WDR + __FRAUD_WFC + __FRAUD_AUM + __FRAUD_MCQ + __FRAUD_PVN + __FRAUD_FVU + __FRAUD_CKF + __FRAUD_MQO + __FRAUD_TCC + __FRAUD_GBW + __FRAUD_AXF + __FRAUD_THJ + __FRAUD_YQV + __FRAUD_YJA + __FRAUD_YPO + __FRAUD_UOQ + __AFRICAN_STATE + __AGREED_RATIO + __AM_DYING + __ATM_CARD + __BACK_SCRATCH + __BARRISTER + __BENEFICIARY + __COMPENSATION + __CONTACT_ATTY + __CONTACT_YOU + __COURIER + __DEAD_PARENT + __DEAL + DEAR_BENEFICIARY + DEAR_WINNER + __DECEASED + __DESTROY_ME + __DIED_IN + __DIPLOMATIC + __DORMANT_ACCT + __EARLY_DEMISE + EMRCP + __EX_CUSTOMER + __FEES + __FIFTY_FIFTY + __FOUND_YOU + __FRAUD + __FRAUD_PTX + __HUSH_HUSH + __I_INHERIT + __INHERIT_PMT + __INTL_BANK + __INVEST_COUNTRY + __INVEST_MONEY + __IS_LEGAL + __I_WILL_YOU + __KAM_LOTTO2 + __LOTTO_ADMITS + LOTTO_AGENT + __LOTTO_DEPT + __LOTTO_RELATED + __LOTTO_VERIFY + T_LOTTO_URI + __LOTTO_WIN_01 + __LOTTO_WINNINGS + __LUCKY_WINNER + __LUCRATIVE + __MILLIONS + __MY_FORTUNE + __NEXT_OF_KIN + __NOT_DEAD_YET + __NOT_SCAM + __OUR_BEHALF + __SCAM + __SHARE_IT + __SUM_OF_FUND + __SURVIVORS + __THEY_INHERIT + __TRTMT_DEFILED + __TRUNK_BOX + __UN + UNCLAIMED_MONEY + __WIDOW + __WILL_LEGAL + __XFER_MONEY + __YOU_ASSIST + __YOU_INHERIT + __YOUR_BANK + __YOUR_FUND + __YOUR_PERM + __YOUR_PROFIT + __YOU_WON + T_LOTTO_AGENT_FM + T_LOTTO_AGENT_RPLY + __PCT_FOR_YOU + __PCT_OF_PMTS + __RANDOM_PICK + __CHARITY > 3) + +meta __MONEY_FRAUD_5 LOTS_OF_MONEY && (__FRAUD_VQE + __FRAUD_KJV + __FRAUD_IRJ + __FRAUD_NEB + __FRAUD_XJR + __FRAUD_DPR + __FRAUD_BEP + __FRAUD_TDP + __FRAUD_GAN + __FRAUD_IRT + __FRAUD_AON + __FRAUD_WNY + __FRAUD_IPK + __FRAUD_QXX + __FRAUD_IOV + __FRAUD_MLY + __FRAUD_ULK + __FRAUD_BGP + __FRAUD_YWW + __FRAUD_JYG + __FRAUD_XWW + __FRAUD_UUY + __FRAUD_SNT + __FRAUD_JNB + __FRAUD_QFY + __FRAUD_WDR + __FRAUD_WFC + __FRAUD_AUM + __FRAUD_MCQ + __FRAUD_PVN + __FRAUD_FVU + __FRAUD_CKF + __FRAUD_MQO + __FRAUD_TCC + __FRAUD_GBW + __FRAUD_AXF + __FRAUD_THJ + __FRAUD_YQV + __FRAUD_YJA + __FRAUD_YPO + __FRAUD_UOQ + __AFRICAN_STATE + __AGREED_RATIO + __AM_DYING + __ATM_CARD + __BACK_SCRATCH + __BARRISTER + __BENEFICIARY + __COMPENSATION + __CONTACT_ATTY + __CONTACT_YOU + __COURIER + __DEAD_PARENT + __DEAL + DEAR_BENEFICIARY + DEAR_WINNER + __DECEASED + __DESTROY_ME + __DIED_IN + __DIPLOMATIC + __DORMANT_ACCT + __EARLY_DEMISE + EMRCP + __EX_CUSTOMER + __FEES + __FIFTY_FIFTY + __FOUND_YOU + __FRAUD + __FRAUD_PTX + __HUSH_HUSH + __I_INHERIT + __INHERIT_PMT + __INTL_BANK + __INVEST_COUNTRY + __INVEST_MONEY + __IS_LEGAL + __I_WILL_YOU + __KAM_LOTTO2 + __LOTTO_ADMITS + LOTTO_AGENT + __LOTTO_DEPT + __LOTTO_RELATED + __LOTTO_VERIFY + T_LOTTO_URI + __LOTTO_WIN_01 + __LOTTO_WINNINGS + __LUCKY_WINNER + __LUCRATIVE + __MILLIONS + __MY_FORTUNE + __NEXT_OF_KIN + __NOT_DEAD_YET + __NOT_SCAM + __OUR_BEHALF + __SCAM + __SHARE_IT + __SUM_OF_FUND + __SURVIVORS + __THEY_INHERIT + __TRTMT_DEFILED + __TRUNK_BOX + __UN + UNCLAIMED_MONEY + __WIDOW + __WILL_LEGAL + __XFER_MONEY + __YOU_ASSIST + __YOU_INHERIT + __YOUR_BANK + __YOUR_FUND + __YOUR_PERM + __YOUR_PROFIT + __YOU_WON + T_LOTTO_AGENT_FM + T_LOTTO_AGENT_RPLY + __PCT_FOR_YOU + __PCT_OF_PMTS + __RANDOM_PICK + __CHARITY > 5) + +meta __MONEY_FRAUD_8 LOTS_OF_MONEY && (__FRAUD_VQE + __FRAUD_KJV + __FRAUD_IRJ + __FRAUD_NEB + __FRAUD_XJR + __FRAUD_DPR + __FRAUD_BEP + __FRAUD_TDP + __FRAUD_GAN + __FRAUD_IRT + __FRAUD_AON + __FRAUD_WNY + __FRAUD_IPK + __FRAUD_QXX + __FRAUD_IOV + __FRAUD_MLY + __FRAUD_ULK + __FRAUD_BGP + __FRAUD_YWW + __FRAUD_JYG + __FRAUD_XWW + __FRAUD_UUY + __FRAUD_SNT + __FRAUD_JNB + __FRAUD_QFY + __FRAUD_WDR + __FRAUD_WFC + __FRAUD_AUM + __FRAUD_MCQ + __FRAUD_PVN + __FRAUD_FVU + __FRAUD_CKF + __FRAUD_MQO + __FRAUD_TCC + __FRAUD_GBW + __FRAUD_AXF + __FRAUD_THJ + __FRAUD_YQV + __FRAUD_YJA + __FRAUD_YPO + __FRAUD_UOQ + __AFRICAN_STATE + __AGREED_RATIO + __AM_DYING + __ATM_CARD + __BACK_SCRATCH + __BARRISTER + __BENEFICIARY + __COMPENSATION + __CONTACT_ATTY + __CONTACT_YOU + __COURIER + __DEAD_PARENT + __DEAL + DEAR_BENEFICIARY + DEAR_WINNER + __DECEASED + __DESTROY_ME + __DIED_IN + __DIPLOMATIC + __DORMANT_ACCT + __EARLY_DEMISE + EMRCP + __EX_CUSTOMER + __FEES + __FIFTY_FIFTY + __FOUND_YOU + __FRAUD + __FRAUD_PTX + __HUSH_HUSH + __I_INHERIT + __INHERIT_PMT + __INTL_BANK + __INVEST_COUNTRY + __INVEST_MONEY + __IS_LEGAL + __I_WILL_YOU + __KAM_LOTTO2 + __LOTTO_ADMITS + LOTTO_AGENT + __LOTTO_DEPT + __LOTTO_RELATED + __LOTTO_VERIFY + T_LOTTO_URI + __LOTTO_WIN_01 + __LOTTO_WINNINGS + __LUCKY_WINNER + __LUCRATIVE + __MILLIONS + __MY_FORTUNE + __NEXT_OF_KIN + __NOT_DEAD_YET + __NOT_SCAM + __OUR_BEHALF + __SCAM + __SHARE_IT + __SUM_OF_FUND + __SURVIVORS + __THEY_INHERIT + __TRTMT_DEFILED + __TRUNK_BOX + __UN + UNCLAIMED_MONEY + __WIDOW + __WILL_LEGAL + __XFER_MONEY + __YOU_ASSIST + __YOU_INHERIT + __YOUR_BANK + __YOUR_FUND + __YOUR_PERM + __YOUR_PROFIT + __YOU_WON + T_LOTTO_AGENT_FM + T_LOTTO_AGENT_RPLY + __PCT_FOR_YOU + __PCT_OF_PMTS + __RANDOM_PICK + __CHARITY > 8) + +ifplugin Mail::SpamAssassin::Plugin::FreeMail + meta __MONEY_FREEMAIL_REPTO LOTS_OF_MONEY && __freemail_hdr_replyto +endif + +meta __MONEY_FROM_41 __NSL_RCVD_FROM_41 && LOTS_OF_MONEY + +body __MOVE_MONEY /\b(?:(?:receive|re-?profile|transfer(?:ring|ir|t)?|release|repatriat(?:e|ion)|rapatrier|secure|r(?:e|=E9|[\xe9]|[\xc3][\xa9])clamation|possession|virer|dona(?:te|r)|depositante|dep[\xc3][\xb3]sito)\s(?:th(?:e(?:se)?|is)|d[ae]s|sur ce|de ce[st]|cet|est[eao]s?|del?)|re-?profiling|receive|re-?locat(?:e|ing)(?:\s\w{1,15})?)\s(?:of\s|your\s|the\s){0,2}(?:sums?\sof\s|inheritance\s)?(?:proceeds|funds?|money|balance|account|g[eo]ld|compte|fond[so]{1,2}|dinero|argent)\b/i + +meta __MSGID_DOLLARS_URI_IMG __MSGID_DOLLARS_MAYBE && __HAS_ANY_URI && __HTML_LINK_IMAGE + +header __MSGID_GUID Message-ID =~ /^/m + +meta __MSMAIL_PRI_ABNORMAL __HAS_MSMAIL_PRI && !__MSMAIL_PRI_NORMAL + +header __MSMAIL_PRI_HIGH X-MSMail-Priority =~ /^(?:high|urgent)$/i + +header __MSMAIL_PRI_NORMAL X-MSMail-Priority =~ /^normal$/i + +meta __MSM_PRIO_REPTO __HAS_MSMAIL_PRI && __HAS_REPLY_TO && __SUBJ_SHORT + +header __MSOE_MID_WRONG_CASE ALL =~ /\nMessage-Id: / + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __MSO_THEME_MT Content-Type =~ m,\bapplication/vnd.ms-officetheme\b,i +endif + +header __MTLANDROID_MUA X-Mailer =~ /\bMotorola android mail \d+\.\d/ + +header __MUA_TBIRD User-Agent =~ /^Mozilla\/(.*) Thunderbird/ + +body __MY_FORTUNE /\b(?:my|his|her)\s(?:fortune|heritage)\b/i + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __MY_MALWARE /\b(?:(?:I(?:'ve|\shave)?\s(?:put|set\s?up|installed|buil[td]\sin|placed)\s(?:a\s)?|my\s(?:personal\s|background\s|hidden\s)?)(?:mal+ware|virus|spy\s?ware|trojan|program\srecorded|expl[o0]it|backdoor|(?:sneaky\s|hidden\s|malicious\s)+(?:app|stuff))|(?:application|mal+ware)[^\.]{1,30}(?:enable[sd]|allow(?:s|ed))\sme\sto\s(?:access|control)|I\s(?:contaminated|infected|hacked|toxified|poisoned)\s(?:your|this)\s(?:machine|computer|gadget|(?:smart\s?)?phone|device|email)|Anwendung\s[^\.]{1,50}\sich\sauf\salle\sIhre\sdarauf\sgespeicherten\sDateien\szugreifen\skann|mein\shinterhältiges\sProgramm|I\s?am\s?a\s?hacker|(?:(?:trojan|virus|spyware|mal+ware)\s)+giv(?:es|ing)\sme)\b/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __MY_MALWARE /(?:^|\s)(?:(?:(?:'|\s)?\s(?:

<|>\s?

||(?:|)\s|

)\s(?:\s)?|\s(?:

\s|\s|\s)?)(?:+||

\s?||

\s|

(?:|0)||(?:\s|\s|\s)+(?:

|))|(?:

|+)[^\.]{1,30}(?:(?:|)|(?:|))\s\s\s(?:|)|\s(?:||||

)\s(?:|)\s(?:|

||(?:\s?)?

||)|Anwendung\s[^\.]{1,50}\sich\sauf\salle\sIhre\sdarauf\sgespeicherten\sDateien\szugreifen\skann|\s\s

+|\s?\s?\s?|(?:(?:||

|+)\s)+(?:|)\s)[\s\.,]/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __MY_VICTIM /\b(?:hi|hello),?(?:\smy)?\s(?:victim|prey)\b/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __MY_VICTIM /(?:|),?(?:\s)?\s(?:|

)/i +endif + +header __NAKED_TO To =~ /^[^\s<>]+\@[^\s<>]+$/ + +meta __NAME_EMAIL_DIFF __NAME_IS_EMAIL && ! __NAME_EQ_EMAIL + +header __NAME_EQ_EMAIL From:raw =~ /([\w+.-]+\@[\w.-]+\.\w\w+)["'`\s]*<\s*\1>/i + +header __NAME_IS_EMAIL From:raw =~ /\w\@[\w.-]+\.\w\w+["'`]*\s*<\w+\@\w/ + +body __NEVER_HEAR_EN /(never hear me again|destroy all your secrets|not bother you again|leave you alone)/i + +body __NEVER_HEAR_IT /eliminare tutti i tuoi segreti|Ti garantisco che non ti disturbe/i + +meta __NEWEGG_IMG_NOT_RCVD_NEGG __URI_IMG_NEWEGG && !__HDR_RCVD_NEWEGG + +body __NEW_PRODUCTS /\bhere are new products|\b(?:Our company|we) (?:has |have )?(?:(?:recently|just|newly) (?:introduce|release|launche)[ds](?: a| our| the)? (?:new|(?:\w+\s){1,5}below)|a new (?!cat\s|kitten\s|dog\s|puppy\s|pet\s|baby\s|child\s|boy\s|girl\s)(?:\w+\s){1,5} here)|recently,? our company (?:launch|releas)ed|\bI want to recommend a new (?:\w+ ){1,5}(?:we|our)\b|latest version of our (?:stock|product)|\b(?:our|a) new (?:\w+ ){1,3}has (?:recently|just) been released/i + +body __NEXT_OF_KIN /\bnext[-\s]of[-\s]kin\b/i + +body __NIGERIA /\bnigeria\b/i + +meta __NORDNS_LOW_CONTRAST HTML_FONT_LOW_CONTRAST && __RDNS_NONE + +meta __NOT_A_PERSON __VACATION || ANY_BOUNCE_MESSAGE || __CHALLENGE_RESPONSE || __VIA_ML || __DOS_HAS_LIST_UNSUB || __SENDER_BOT || __UNSUB_LINK || __UNSUB_EMAIL || __MSGID_LIST || __SUBSCRIPTION_INFO +tflags __NOT_A_PERSON nice + +body __NOT_DEAD_YET /\b(?:will\sinherit|que\sherede|your\sdeath|your?\sbeing\sdead)\b/i + +body __NOT_SCAM /\b(?:not\sa\sscam|(?:not|never)\sscam\syou)\b/i + +tflags __NOT_SPOOFED nice + +if !(!plugin(Mail::SpamAssassin::Plugin::DKIM)) +if !plugin(Mail::SpamAssassin::Plugin::SPF) + meta __NOT_SPOOFED DKIM_VALID || !__LAST_EXTERNAL_RELAY_NO_AUTH || ALL_TRUSTED # yes DKIM, no SPF +endif +endif + +if !(!plugin(Mail::SpamAssassin::Plugin::DKIM)) + ifplugin Mail::SpamAssassin::Plugin::SPF + meta __NOT_SPOOFED SPF_PASS || DKIM_VALID || !__LAST_EXTERNAL_RELAY_NO_AUTH || ALL_TRUSTED # yes DKIM, yes SPF +endif +endif + +if !plugin(Mail::SpamAssassin::Plugin::DKIM) +if !plugin(Mail::SpamAssassin::Plugin::SPF) + meta __NOT_SPOOFED __DKIM_EXISTS || !__LAST_EXTERNAL_RELAY_NO_AUTH || ALL_TRUSTED # no DKIM, no SPF. +endif +endif + +if !plugin(Mail::SpamAssassin::Plugin::DKIM) + ifplugin Mail::SpamAssassin::Plugin::SPF + meta __NOT_SPOOFED SPF_PASS || __DKIM_EXISTS || !__LAST_EXTERNAL_RELAY_NO_AUTH || ALL_TRUSTED # no DKIM, yes SPF +endif +endif + +meta __NO_INR_YES_REF (__XM_GNUS || __XM_MSOE5 || __XM_MSOE6 || __XM_MOZ4 || __XM_SKYRI || __XM_WWWMAIL || __UA_GNUS || __UA_KNODE || __UA_MUTT || __UA_PAN || __UA_XNEWS) + +header __NSL_ORIG_FROM_41 X-Originating-IP =~ /^(?:.+\[)?41\./ +describe __NSL_ORIG_FROM_41 Originates from 41.0.0.0/8 + +header __NSL_RCVD_FROM_41 X-Spam-Relays-External =~ / ip=41\./ +describe __NSL_RCVD_FROM_41 Received from 41.0.0.0/8 + +header __NUMBERONLY_TLD From:addr =~ /\@[0-9]{4,}(\.[a-z]{2,4})?\.[a-z]+$/i + +header __NUMBERS_IN_SUBJ Subject =~ /\d{3}/ + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __OBFU_BITCOIN ( __BITCOIN_ID && ( __BTC_OBFU_2 || __BTC_OBFU_3 || __BTC_OBFU_4 || __BTC_OBFU_5 ) ) +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + meta __OBFU_BITCOIN ( __BITCOIN_ID && ( __BTC_OBFU_2 || __BTC_OBFU_3 || FUZZY_BITCOIN || __BTC_OBFU_5 ) ) +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __OBFU_BITCOIN_NOID ( !__BITCOIN_ID && ( __BTC_OBFU_2 || __BTC_OBFU_3 || __BTC_OBFU_4 || __BTC_OBFU_5 ) ) +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + meta __OBFU_BITCOIN_NOID ( !__BITCOIN_ID && ( __BTC_OBFU_2 || __BTC_OBFU_3 || FUZZY_BITCOIN || __BTC_OBFU_5 ) ) +endif + +body __OBFU_UNSUB_UL /(?:click_here|remove_your|our_e?mail|this_list|to_unsubscribe|future_e?mail|our_list)/ + +if !plugin(Mail::SpamAssassin::Plugin::ImageInfo) + meta __ONE_IMG 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ImageInfo + body __ONE_IMG eval:image_count('all',1,1) +endif + +header __OPERA_MID_NON_OP Message-ID =~ /^<[^o][^p]\./ + +body __OUR_BEHALF /\b(?:on\s(?:my|our)\sbehalf|of\sbehalf\sof)\b/i + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __PART_CID_STOCK_LESS Content-ID =~ /^<00[a-f0-9]{10}\$[a-f0-9]{8}\$[a-f0-9]{8}\@[A-Za-z]+>$/ +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __PART_STOCK_CD_F Content-Disposition =~ /filename/ +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __PART_STOCK_CID Content-ID =~ /^<[a-f0-9]{12}\$[a-f0-9]{8}\$[a-f0-9]{8}\@[^\s\.]+>$/ +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __PART_STOCK_CL Content-Location =~ /./ +endif + +body __PASSIVE_INCOME /\bpassive income\b/i + +body __PASSWORD /\bp[-\s_]?a[-\s_]?s[-\s_]?s[-\s_]?w[-\s_]?o[-\s_]?r[-\s_]?d\b/i + +body __PASSWORD_EXP_CLUMSY /\bpassword is due for expiration yesterday\b/i + +body __PASSWORD_UPGRADE /\bpassword upgrade\b/i + +body __PAXFUL /\bp-?a+-?x+-?f-?u+-?l\b/i + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __PAY_ME /\b(?:pay\sme|(?:(?:send|transmit|give)\s(?:to\s)?me|(?:send(?:en\ssie)?|transfer)\s(?:the\samount\sof|exactly|genau)|I\swant|den\sbetrag\svon|payment\sof)\s(?:[\d,'.\$£]+\s?(?:usd?|eur?(?:os)?|gbp|BTC)?|bitcoin|BTC)|(?:make|perform|send|transmit)\sthe\spayment|amount\sfor\smy\ssilence|(?:pay|fund)\sthis\s(?:bitcoin|monero)[-\s](?:address|wallet|brieftasche)|my bribe(?:ry)?)\b/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __PAY_ME /(?:^|\s)(?:

\s|(?:(?:||)\s(?:\s)?|(?:(?:\s)?|)\s(?:\s\s||)|\s|\s\s|

\s)\s(?:[\d,'.\$£]+\s?(?:?|?(?:)?|

|)?||)|(?:|

||)\s\s

|\s\s\s|(?:

|)\s\s(?:|)[-\s](?:||| (?:)?))[\s\.,]/i +endif + +body __PAY_YOU /\bpay\syou\b/ + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __PCT_FOR_YOU 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + meta __PCT_FOR_YOU __PCT_FOR_YOU_1 || __PCT_FOR_YOU_2 || __PCT_FOR_YOU_3 || T_SHARE_50_50 +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __PCT_FOR_YOU_1 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __PCT_FOR_YOU_1 /[\s)]{0,3}(?:(?:of\s[\w\s]{0,35}?)?(?:for|to|as)\syour?|(?:[^\s.]{1,15}\s)?an uns beide)/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __PCT_FOR_YOU_2 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __PCT_FOR_YOU_2 /\b(?:(?:give|offer)\syou|vous\s(?:aurez\sdroit\s(?:=E0|[\xe0])|donnerai|all(?:e|=E9|[\xe9]|[\xc3][\xa9])\srecevoir\sautour\sde)|ihnen)\s/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __PCT_FOR_YOU_3 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __PCT_FOR_YOU_3 /\byour?\s(?!can)(?:(?!you)\w{1,15}\s){0,10}(?:(?:share|entiti?le(?:d|ment)?|percentage|fee|assist(?:ance)?|comp[ea]nsat(?:ed?|tion)|reward(?:ed)?|renumerat(?:e|tion)|com+is+ion|paid|deduct|account|tage|(?:will|shall|would|(?:are|stand|going)\sto)\s(?:be\s)?(?:tak(?:e|ing)|earn|get(?:ting)?|remit|subtract|with+old)|(?:deduct|taken?|subtract(?:ed)?)\syour|keep(?:ing)?|receiv(?:e|ing)|retain(?:ing)?|have|half|giv(?:en|ing)|paid|(?:give|pay|offer)\s(?:me|you|him)|bank\saccount|to\s(?:take|use)|(?:time|country)\sand|ratio\sof)(?:\s(?!you)\w{1,15}){0,10})\s(?/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + meta __PCT_OF_PMTS 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __PCT_OF_PMTS /[\s)]+(?:of\s[\w\s]{0,35}?)?(?:of|du|de)\s(?:(?:the|la)\s)?(?:total\s)?(?:payments?|rem+it+ances?|capital|chec(?:k|que)s?|mon(?:ey|ies)|suma?)/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __PDF_ATTACH 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + meta __PDF_ATTACH (__PDF_ATTACH_MT || __PDF_ATTACH_FN1 || __PDF_ATTACH_FN2) +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __PDF_ATTACH_FN1 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __PDF_ATTACH_FN1 Content-Type =~ /="[^"]+\.pdf"/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __PDF_ATTACH_FN2 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __PDF_ATTACH_FN2 Content-Disposition =~ /="[^"]+\.pdf"/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __PDF_ATTACH_MT 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __PDF_ATTACH_MT Content-Type =~ m,\bapplication/pdf\b,i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + header __PDS_BTC_ANON From:name =~ /\bAnon/ +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + meta __PDS_BTC_BADFROM ( __PDS_BTC_HACKER || __PDS_BTC_PIRATE ) +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + header __PDS_BTC_HACKER From:name =~ /hckr/i +endif + +meta __PDS_BTC_ID ( __BITCOIN_ID && !__URL_BTC_ID && !__HAS_IMG_SRC_DATA && !__BUGGED_IMG) + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + header __PDS_BTC_PIRATE From:name =~ /prt/i +endif + +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +if (version >= 3.004000) +header __PDS_CASHSHORTENER eval:check_uri_host_listed('PDS_CASHSHORTENER') +endif +endif + +uri __PDS_DOUBLE_URL m;https?://[\S]+(?:\?|=)https?://[\S]+[\w]+$; + +if (version >= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +body __PDS_EXPIRATION_NOTICE /\bexpiration (notice|alert|date)\b/i +endif +endif + +if can(Mail::SpamAssassin::Conf::perl_min_version_5010000) + header __PDS_FROM_2_EMAILS From =~ /(?:^|<|"| )([\w+.-]+\@[\w.-]+\.\w\w++)(?:[^\n\w<]{0,80})?<(?!\1)[^\n\s]*\@/i +endif + +header __PDS_FROM_GMAIL From:addr =~ /\@g(?:oogle)?mail\.com$/i + +header __PDS_FROM_NAME_TO_DOMAIN ALL =~ /From: ["']?([a-z0-9\.-]+\.[0-9a-z\.-]+)["']? [^\n]+\nTo:[^\n]+\@\1/ism + +header __PDS_GMAIL_MID Message-Id =~ /\@mail.gmail.com>$/ + +meta __PDS_GOOGLE_DRIVE_SHARE (__PDS_GOOGLE_DRIVE_SHARE_1 + __PDS_GOOGLE_DRIVE_SHARE_2 + __PDS_GOOGLE_DRIVE_SHARE_3 >= 2) + +header __PDS_GOOGLE_DRIVE_SHARE_1 References =~ /\@docs\-share\.google\.com\>/ + +header __PDS_GOOGLE_DRIVE_SHARE_2 From:addr =~ /^drive\-shares\-noreply\@google\.com$/ + +header __PDS_GOOGLE_DRIVE_SHARE_3 X-Envelope-From:addr =~ /\@doclist\.bounces\.google\.com$/ + +ifplugin Mail::SpamAssassin::Plugin::AskDNS +meta __PDS_HP_HELO_NODNS (__HELO_HIGHPROFILE && !__HELO_DNS) +tflags __PDS_HP_HELO_NODNS net +endif + +ifplugin Mail::SpamAssassin::Plugin::HTMLEval +meta __PDS_HTML_LENGTH_1024 __HTML_LENGTH_0000_1024 +endif + +ifplugin Mail::SpamAssassin::Plugin::HTMLEval +meta __PDS_HTML_LENGTH_2048 __HTML_LENGTH_0000_1024 || __HTML_LENGTH_1024_1536 || __HTML_LENGTH_1536_2048 +endif + +meta __PDS_LITECOIN_ID (__LITECOIN_ID && !__URL_LTC_ID && !__HAS_IMG_SRC_DATA && !__BUGGED_IMG) + +meta __PDS_MSG_1024 (__KAM_BODY_LENGTH_LT_1024 || __PDS_HTML_LENGTH_1024) + +meta __PDS_MSG_512 (__KAM_BODY_LENGTH_LT_512 || __HTML_LENGTH_512) + +if (version >= 3.004001) +ifplugin Mail::SpamAssassin::Plugin::AskDNS +meta __PDS_NEWDOMAIN (__FROM_FMBLA_NEWDOM || __FROM_FMBLA_NEWDOM14 || __FROM_FMBLA_NEWDOM28) +tflags __PDS_NEWDOMAIN net +endif +endif + +if (version >= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +body __PDS_OFFER_ONLY_AMERICA /This offer (?:is )?(?:only )?for (United States|USA)/i +endif +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEEval) + meta __PDS_QP_1024 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEEval + meta __PDS_QP_1024 (__MIME_QPC > 0) && (__MIME_QPC < 1024) +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEEval) + meta __PDS_QP_128 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEEval + meta __PDS_QP_128 (__MIME_QPC > 0) && (__MIME_QPC < 128) +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEEval) + meta __PDS_QP_512 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEEval + meta __PDS_QP_512 (__MIME_QPC > 0) && (__MIME_QPC < 512) +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEEval) + meta __PDS_QP_64 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEEval + meta __PDS_QP_64 (__MIME_QPC > 0) && (__MIME_QPC < 64) +endif + +header __PDS_RDNS_MTA X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*(mta|mail|mx|smtp)\b\S* /i + +if (version >= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +body __PDS_SENT_TO_EMAIL_ADDR /This message was sent to Email Address\./i +endif +endif + +if (version >= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +body __PDS_SEO1 /(?:top|first page|1st) (?:(?:results|rank(?:ing)?) )?(?:in|of|on) (?:Google|MSN|Yahoo|Bing)|rank number one|top page rank|guarantee you 1st|link.building/i +endif +endif + +if (version >= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +body __PDS_SEO2 /losing your (?:[a-z]+ )?(?:rank(?:ing)?|results)|rank well on [a-z]+\b/i +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +if (version >= 3.004000) +meta __PDS_SHORT_URL __SHORT_URL && !__URL_SHORTENER && !ALL_TRUSTED +endif +endif + +if (version >= 3.004001) +ifplugin Mail::SpamAssassin::Plugin::AskDNS +tflags __PDS_SPF_ONLYALL net +endif +endif + +meta __PDS_SPOOF_GMAIL_MID __PDS_FROM_GMAIL && !__PDS_GMAIL_MID && !__FSL_RELAY_GOOGLE + +header __PDS_TONAME_EQ_TOLOCAL To:raw =~ /^\s*['"]?([^'"]+)['"]? ]+)>?\n(?:[^\n]{1,100}\n)*From:\W+(\1)([^\n\w<]++<)?((?!\1)[^\n">]++)>?\n/ism +endif + +if can(Mail::SpamAssassin::Conf::perl_min_version_5010000) + header __PDS_TO_EQ_FROM_NAME_2 ALL =~ /\nFrom:\W+"([\w+.-]+\@[\w.-]+\.\w\w+)(?:[^\n\w<]{0,80}<)?((?!\1)[^\n">]++)>?\n(?:[^\n]{1,100}\n)*To:\s+(?:[^\n<]{0,80}<)?(\1)>?/ism +endif + +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +if (version >= 3.004000) +meta __PDS_TO_SUBJ_URISHRT __TO_IN_SUBJ && __URL_SHORTENER && __PDS_MSG_1024 +endif +endif + +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +if (version >= 3.004000) +meta __PDS_URISHORTENER __URL_SHORTENER +endif +endif + +meta __PD_CNT_1 (__PUMPDUMP_01+__PUMPDUMP_02+__PUMPDUMP_03+__PUMPDUMP_04+__PUMPDUMP_05+__PUMPDUMP_06+__PUMPDUMP_07+__PUMPDUMP_08+__PUMPDUMP_09+__PUMPDUMP_10) > 0 + +body __PENDING_MESSAGES /\b(?:messages pending|(?:your|\d+[\])}]?) (?:pending|un(?:delivered|received)) (?:messages|e?-?mails))\b/i + +body __PERFECT_BINARY /\bperfect binary option\b/i + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __PHISH_ATTACH_01_01 Content-Disposition =~ /\bfilename(?:="?[^"]*|\*(?:\d+\*)?=(?:UTF-8'')?\S*)(?:\.|%C2%B7|[\xc2][\xb7]|_)(?:pdf|docx?)\.html?[";$]/i +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __PHISH_ATTACH_01_02 Content-Type =~ /\bname="?[^"]*(?:\.|[\xc2][\xb7]|_)(?:pdf|docx?)\.html?[";$]/i +endif + +meta __PHISH_FBASE_01 (__URI_FIREBASEAPP || __URI_WEBAPP) && __PDS_FROM_NAME_TO_DOMAIN && __MAIL_LINK + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + body __PHOTO_RETOUCHING /\b(?:(?:retouching|(?:image|photo|pic)s? (?:[a-z]{1,15} ){0,3}(?:edit(?:ing|ors)|team|(?:cut+|mask|clip+|clean|crop+|resiz|enhanc|etch)ing|cut+(?:ing)?[-\s]?out|enhancement|manipulation|restoration|compositing|working|(?:color|contrast|brightnes+|background|make-?up) (?:cor+ection|change)|solution|work|services?)|(? 1 + +header __RAND_MKTG_HEADER ALL =~ /^X-(?:[a-z]{2}){1,2}-(?:EBS|(?:Tracking|Subscriber|Delivery|Customer|Campaign)-[DSU]?id):/ism + +header __RATWARE_BOUND_A ALL =~ /^Message-Id: <....([0-9a-f]{8})\$[0-9a-f]{8}\$.{10,400}boundary="----=_NextPart_000_...._\1\./msi # " + +header __RATWARE_BOUND_B ALL =~ /boundary="----=_NextPart_000_...._([0-9a-f]{8})\..{10,400}^Message-Id: <....\1\$[0-9a-f]{8}\$/msi # " + +header __RCD_RDNS_MAIL X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*\bmail[^a-z]/i +tflags __RCD_RDNS_MAIL nice + +header __RCD_RDNS_MAIL_MESSY X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*mail/i +tflags __RCD_RDNS_MAIL_MESSY nice + +header __RCD_RDNS_MTA X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*\bmta[^a-z]/i +tflags __RCD_RDNS_MTA nice + +header __RCD_RDNS_MTA_MESSY X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*mta/i +tflags __RCD_RDNS_MTA_MESSY nice + +header __RCD_RDNS_MX X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*\bmx[^a-z]/i +tflags __RCD_RDNS_MX nice + +header __RCD_RDNS_MX_MESSY X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*mx/ +tflags __RCD_RDNS_MX_MESSY nice + +header __RCD_RDNS_OB X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*\boutbounds?[^a-z]/i +tflags __RCD_RDNS_OB nice + +header __RCD_RDNS_SMTP X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*\bsmtps?[^a-z]/i +tflags __RCD_RDNS_SMTP nice + +header __RCD_RDNS_SMTP_MESSY X-Spam-Relays-External =~ /^[^\]]+ rdns=\S*smtp/ +tflags __RCD_RDNS_SMTP_MESSY nice + +header __RCVD_DOTEDU_EXT X-Spam-Relays-External =~ /\srdns=\S+\.edu\s/i + +meta __RCVD_DOTEDU_SHORT __RCVD_DOTEDU_EXT && ( __HTML_IMG_ONLY || __BODY_URI_ONLY || __HTML_LENGTH_1024_1536 ) + +meta __RCVD_DOTEDU_SUSP_URI __RCVD_DOTEDU_EXT && ( __45_ALNUM_URI || __45_ALNUM_URI_O || __64_ANY_URI ) + +header __RCVD_DOTGOV_EXT X-Spam-Relays-External =~ /\srdns=\S+\.gov\s/i + +header __RCVD_ZIXMAIL X-Spam-Relays-Untrusted =~ / helo=smtpout\.zixmail\.net / + +header __RDNS_LONG X-Spam-Relays-External =~ /^[^\]]+ rdns=\S{30}/ + +header __RDNS_NO_SUBDOM X-Spam-Relays-External =~ /^[^\]]+ rdns=[^. ]*\.\w+ / + +header __RDNS_NUMERIC_TLD X-Spam-Relays-External =~ /\srdns=\S+\.\d+\s/ + +header __RDNS_SHORT X-Spam-Relays-External =~ /^[^\]]+ rdns=\S{4,14} / + +body __RECEIVE_BONUS /\byou(?:'ll)?(?: also| will)* (?:rec[ei]*ve|get|earn|collect|be (?:awarded|handed|remitted|given|paid|(?:greeted|welcomed|started) with)) (?:an? )?(?:gift|bonus|extra)(?: of|:)? \$[\d,]+/i + +header __RELAY_THRU_WWW Received =~ /from (?:[^ \@]+\@)?www\./ + +body __RELEASE_MESSAGES /\b(?:release messages|(?:retrieve|release|download) your(?: undelivered|unreceived|held|pending)? e?-?mails|(?:e?-?mails|messages).{1,20}download them now)\b/i + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader # { + meta __REMOTE_IMAGE (__HTML_IMG_ONLY || __HTML_LINK_IMAGE) && !(__SUBSCRIPTION_INFO || __VIA_ML || __SENDER_BOT || __ANY_IMAGE_ATTACH) +endif + +if (version >= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +header __REPLYTO_ADDRLIST_SUSPNTLD eval:check_replyto_in_list('SUSP_NTLD') +endif +endif + +header __REPTO_419_FRAUD_AOL_LOOSE Reply-To:addr =~ /^(?=[^\s<>@]+\@aol\.com)(?:(?:a(?:f\.|ljaber)|c(?:hanprivacy|laimdept|ristinabruno|ustom_service)|dhodgkins|evelynjoshua|f(?:d\.|ernandezfernandez)|george_clifford|hernandezrosemary|k\.doreen|l(?:erynnewest|ynnpage)|m(?:_l\.wanczyk|asayohara|rsjanetedwards)|officework|paulpollard|royalpalace|spwalker|usembassy|yurdaaytarkan))\d+\@aol\.com$/i + +header __REPTO_419_FRAUD_GM_LOOSE Reply-To:addr =~ /^(?=[^\s<>@]+\@gmail\.com)(?:(?:9porssts|a(?:\.wafager|b(?:dullahmundani|u(?:lkareem|shadi))|cecere|l(?:an\.austin|ex(?:anderpeterson|hoffman)|ghafrij|kasimunadi|l(?:enholden|isoncluade)|ure\.wawrenka)|m(?:bassadormarybethleonardl|ericadeliverycomapny|ina(?:ltwaijiri|medjahed))|n(?:dyfox|na(?:llee|sigurlaug))|office1office|radka|shwestwood|ustinbillmark|zi(?:m(?:\.hpremji|hashim(?:donation)?)|z(?:dake|george)))|b(?:a(?:nkcentralasiahalobca|r(?:bersmadar|risterlordruben|teld\.huisman))|bongo|e(?:alitoniua|linekra|n(?:ezero|gatl|jaminsarah))|ill\.lawrence|mwautomobile|oarddept|rendalaporte|uffettwarrene)|c(?:h(?:a(?:ngching|r(?:itylisajohnrobinson|l(?:esluenga|tonnewmanus)))|e(?:mchung|nchung))|iticonsultantjohncg|laxtonpaul|o(?:lombasjuan|ntactad)|rist(?:brun?|davis|ydavisdonation)|ustomerservicelacaixa)|d(?:a(?:nnuar|vi(?:d(?:\.loanfirm|larbi|pere|ramirez\.luis)|scarolyn|yax))|e(?:nnisclark|partmentofstate)|minique|ona(?:ldwilliam|tionhelpercare)|rdavidrhama|unsilva)|e(?:benezero|christina|l(?:i(?:bethgomez|sabethmaria|zabethedw)|o(?:diesawadogo|tocashoffice))|m(?:efieleg?|ilyrichmond)|re(?:nakgeorge|zcelic)|stherkatherine|wynn)|f(?:\.mikhail|a(?:ithdesrie|tme\.mehmed)|blott|irstbank|r(?:a(?:100dub|n(?:c(?:espatrickconnolly|iscamendoza)|k(?:jane|linpiesie)))|eelottosweepstake)|spero|ulanlan)|g(?:00gleggewinner|a(?:briel(?:eschmitt|kalia)|rciavincent)|bill|e(?:neralwilliamstony|orgekwame|raldjhjh)|iidp|l(?:enmoore|oriachow)|oo(?:golteam|oglegwiinner)|r(?:aceobia|e(?:ant|energeoffrey)))|h(?:a(?:r(?:gate|ryebert)|sh(?:imyreem|mireem))|e(?:atherbrooeke|ctor(?:castillos|scastillo)|lengiggs)|gold|ildad|o(?:nmackjohn|rnbeckmajordennis|seoky))|i(?:bed|mfdeputyoff|n(?:fo\.annedouglas|gridrolle)|smail(?:eman|tarkan))|j(?:a(?:mesokoh|vierlesme)|efferydean|o(?:edward|hn(?:griffn|r(?:awlings|oxfordjr)|sonwilson|uba|walterlove|a)|n(?:athanhaskel|hugo)|sephacevedo|vannyanderson)|rawlings|uliewatson)|k(?:a(?:l(?:iaksandr|tschmidtdavid)|malnizar|rabo\.ramala|t(?:jamess|rinaziako))|ennedy\.sawadogo|halidbuhazza|kasbu|rnkl|un(?:gwei|ioue))|l(?:a(?:rrytoms|ursent|wrencefoundation)|e(?:enasinghs|rynne(?:0west|west))|i(?:amfinchus|fecshortt|liane\.bettencourt|nelink|sa(?:milner|robin))|john|oughreymargaret|u(?:ckywinners|sba\.moored)|y(?:\.cheapiseth|diawright|n(?:\.arthur|cmba|nmkl)))|m(?:a(?:incare|jor(?:dennishornbeck|townsend)|lletman|n(?:duesq|fran|uelfranco(?:(?:donation|foundation|spende))?)|r(?:i(?:ahhills|opabl)|kroth|shalh|tinamayer|y(?:franson|josen))|urhinck|viswan(?:czyk(?:(?:foundation|k))?)?)|c\.cheadychang|dredban|elvidabullock|gfrederick|i(?:c(?:h(?:ael\.woosley|ealwuu)|w)|k(?:e\.weirsky\.foundational|hai(?:\.fridman|lfridm))|ss\.yasmineibrahim)|k(?:ent|untjoro)|oham(?:edabdul|m(?:daljililati|edshamekh))|r(?:\.(?:elbahi\.mohammed\.|justinmaxwell)|cjames|ericschmid|hanimuhammad|jamesmc|richardanthony|s(?:\.susanread|a(?:ishaalqadafi|ngela)|dominiquethomas|evelynbrown|fatimaamiraqureshi|hamima|jackman|lisamilner|maureens|r(?:obinsanders|uthsmith)|sarahbenjamin|victoriaedmond))|s(?:\.ellagolan|agent|golaan|smadar)|ustadris)|n(?:aomiiwasaki|eilt(?:rotter)?|icholas\.jose|obuyuki\.hirano)|o(?:\.peace|fficerricherd|hallkenneth|xfaminternationa)|p(?:aul(?:eed|n)|b(?:ph202lay|rookk)|e(?:rezdonlorenzo|ter(?:\.waddell|guggi|kenin|stephen))|hillip\.richead)|q(?:iquanzhou|nzeng)|r(?:a(?:kidy|lhashimi|ymondaba)|e(?:beccagarang|em(?:has(?:himy|m)|n)|plyback|v(?:\.jamesabel|fr(?:ankjackson|paulwilliams)))|icha(?:miller|rdw(?:ahl|illis))|o(?:b(?:erthanandez|inf)|naldmorris|s(?:a\.gomes|ekipkalya))|raya|t\.rev\.ericmark)|s(?:a(?:l(?:ehhussienconsult|imzaid)|rfiafarfask)|cottpeters|e(?:cretservicce|rgeantrobertbrown)|gt(?:\.monicab|ireneb)|h(?:anemissler|ery(?:\.gtl|etr)|inawatrathaksin)|im(?:lkheng|onhei)|op(?:adam|hiajesse)|peelman|t(?:anleyjohn|ephentam)|u(?:iyang|n\.hor|sanneklatten)|weeneyjohnson)|t(?:a(?:mmywebster|y(?:ebsouami|lorcathy))|erryparkins|h(?:ailandbankoffice|e(?:ara\.choy|odorosloannis))|imothymetheny|lyerdonald|o(?:m(?:ander|c(?:hrist|rist(?:(?:donation|foundation))?)|spende)|ny(?:\.chung|zimpro)|shikazusendo))|u(?:marukareem|n(?:claimedfunds|itednation(?:organization|s))|s(?:alotery|departmentofjustice))|v(?:anderwesthuizen|e(?:enapatel|r(?:a(?:aellen|hollinkvan)|enichekaterinaekaterina))|i(?:ctoriaabraham|dalpamela|ngut))|w(?:a(?:dp|hlr(?:ichard)?|nczykm|rrenebuffett)|hatsappofficial|i(?:elandherzog\.sw\.herad|ll(?:clark|iamsmartyrs))|u\.office|ww\.moneygram)|y(?:\.oguzhan|anghoseok|doo|ousefzongo)|z(?:bank|enithbankplconline|kiaslan|minhong)))\d+\@gmail\.com$/i + +header __REPTO_419_FRAUD_YH_LOOSE Reply-To:addr =~ /^(?=[^\s<>@]+\@yahoo\.com)(?:(?:a(?:driantongson|ilmohammed|lesiakalina|nnhester\.usa)|b(?:ank\.phbng|en(?:jaminb|nicholas)|riceangela)|c(?:\.aroline|h(?:arlesscharf|jackson)|juan|ythiamiller\.un)|dhamilton|e(?:denvictor|ricalbert)|federal\.r|j(?:a(?:ckson\.davis|netemoon)|kimyong)|k(?:altschmidtdavid|elvinmark|im(?:\.leang|leang))|l(?:e(?:a_edem|hman)|isarobinson_|y_cheapiseth)|m(?:\.kogi|arie_avis|dzsesszika|elissalewis|o(?:hammedaahil|keye))|o(?:legkozyrev|mranshaalan)|peterlee|r(?:alphw(?:\.johnson|johnson)|o(?:bertbailey|serichard))|s(?:amthong|igurlauganna|leo|pwalker|te(?:fanopessina|vecox\.))|tylerhess\.|vanserge|will(?:clark|smi)|xianglongdai))\d+\@yahoo\.com$/i + +header __REPTO_CHN_FREEM Reply-To =~ /\@(?:sina|aliyun)\.com/i + +header __REPTO_INFONUMSCOM Reply-To:addr =~ /^info@\d{5,}\.com$/i + +header __REPTO_RUS_FREEM Reply-To =~ /\@mail\.ru/i + +if !((version >= 3.003000)) + meta __RP_MATCHES_RCVD 0 +endif + +if (version >= 3.003000) +if !plugin(Mail::SpamAssassin::Plugin::WLBLEval) + meta __RP_MATCHES_RCVD 0 +endif +endif + +if (version >= 3.003000) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval + header __RP_MATCHES_RCVD eval:check_mailfrom_matches_rcvd() +endif +endif + +body __SCAM /\bscam(?:m?e[dr])?s?\b/i + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __SCC_BOGUS_CTE_1 Content-Transfer-Encoding =~ /^Hexa/i +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __SCC_CTMPP Content-Type =~ /multipart\/parallel/ +endif + +body __SECURITY_DEPT /\bsecurity dep(?:artmen)?t\b/i + +header __SENDER_BOT ALL =~ /(?:not?\W?repl[yi]|bounce|contact|daemon|subscri|report|respon[ds]e?r?s?\b|\b(?:root|news|nobody|agent|(?:post|web)?master|manag|send(?:er|ing)?|out|(?:bot|web|www)\b))[^\@ >]{0,5}s?\@\w/i +tflags __SENDER_BOT nice + +uri __SENDGRID_REDIR m,://u\d+\.ct\.sendgrid\.net/ls/click\?upn=, + +meta __SENDGRID_REDIR_NOPHISH __SENDGRID_REDIR && !__SENDGRID_REDIR_PHISH + +meta __SENDGRID_REDIR_PHISH __SENDGRID_REDIR && ( __PDS_FROM_NAME_TO_DOMAIN || __FORGED_RELAY_MUA_TO_MX || __TO_IN_SUBJ ) + +body __SHARE_IT /\b(?:(?:share|allocate|teilen|parteger(?:ez|ons)?|partage)\s(?:th(?:e|is)|das|les?|des)\s(?:proceeds|funds?|money|balance|account|geld|compte|fonds)|partager(?:ez|ons)? (?:avec (?:vous|moi)|ratio|suivant un pourcentage))\b/i + +meta __SHOPIFY_IMG_NOT_RCVD_SFY __URI_IMG_SHOPIFY && !__HDR_RCVD_SHOPIFY && !__HDR_ENVFROM_SHOPIFY + +uri __SHORT_URL /^https?:\/\/[^\/]{3,6}\.\w\w\/[^\/]{3,8}\/?$/ + +body __SINGLE_WORD_LINE /^\s?\S{1,60}\s?$/ +tflags __SINGLE_WORD_LINE multiple maxhits=2 + +header __SINGLE_WORD_SUBJ Subject =~ /^\s*\S{1,60}\s*$/ + +header __SMIME_MESSAGE Content-Type =~ /application\/pkcs7-mime;/i + +rawbody __SPAN_BEG_TEXT /[a-z]{2}<(?i:span)\s/ +tflags __SPAN_BEG_TEXT multiple maxhits=5 + +rawbody __SPAN_END_TEXT /[^;>]<\/(?i:span)>[a-z]{3}/ +tflags __SPAN_END_TEXT multiple maxhits=5 + +if !plugin(Mail::SpamAssassin::Plugin::SPF) + meta __SPF_FULL_PASS 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::SPF + meta __SPF_FULL_PASS (SPF_PASS && SPF_HELO_PASS) + tflags __SPF_FULL_PASS net +endif + +if !plugin(Mail::SpamAssassin::Plugin::SPF) + meta __SPF_RANDOM_SENDER 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::SPF + meta __SPF_RANDOM_SENDER (SPF_HELO_PASS && !SPF_PASS) + tflags __SPF_RANDOM_SENDER net +endif + +meta __SPOOFED_FREEMAIL !__NOT_SPOOFED && FREEMAIL_FROM +tflags __SPOOFED_FREEMAIL net + +meta __SPOOFED_FREEM_REPTO __SPOOFED_FREEMAIL && FREEMAIL_REPLYTO +tflags __SPOOFED_FREEM_REPTO net + +rawbody __SPOOFED_URL m/]{0,2048}\bhref=(?:3D)?.?(https?:[^>"'\# ]{8,29}[^>"'\# :\/?&=])[^>]{0,2048}>(?:[^<]{0,1024}<(?!\/a)[^>]{1,1024}>){0,99}\s{0,10}(?!\1)https?[^\w<]{1,3}[^<]{5}/i + +meta __STATIC_XPRIO_OLE __XPRIO && __RDNS_STATIC && __HAS_MIMEOLE + +body __STAY_HOME /\b(?:going out of|leaving)(?: your)? (?:home|house|residence)\b/i + +body __STOCK_TIP /\bsto[ck]{2}\s?tip\b/i + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + rawbody __STY_INVIS /\bstyle\s*=\s*"[^">]{0,80}(?:(? 1 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __STY_INVIS_3 __STY_INVIS > 2 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __STY_INVIS_DIRECT __STY_INVIS && __DOS_DIRECT_TO_MX_UNTRUSTED +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __STY_INVIS_MANY __STY_INVIS > 5 +endif + +header __SUBJECT_EMPTY Subject:raw =~ /^\s*$/ + +meta __SUBJECT_PRESENT_EMPTY __HAS_SUBJECT && __SUBJECT_EMPTY + +header __SUBJ_ADMIN Subject =~ /\b(?:(?:sys)?admin(?:istrator)?|server|service|support)\b/i + +header __SUBJ_ATTENTION Subject =~ /ATTENTION/ + +meta __SUBJ_BRKN_WORDNUMS __SUBJ_BROKEN_WORD && __TVD_SUBJ_NUM_OBFU + +header __SUBJ_BROKEN_WORD Subject =~ /\s(?!i[PTM][aoh][bcdou]|e[MP]a[is])[a-z]{1,3}[A-Z][a-z]{2}/ +tflags __SUBJ_BROKEN_WORD multiple maxhits=2 + +meta __SUBJ_DOM_ADMIN __SUBJ_ADMIN && __PDS_FROM_NAME_TO_DOMAIN + +header __SUBJ_HAS_FROM_1 ALL =~ /\nFrom:\s+(?:[^\n<]{0,80}<)?([^\n\s>]+)>?\n(?:[^\n]{1,100}\n)*Subject:\s+[^\n]{0,100}\1[>,:\s\n]/ism + +header __SUBJ_HAS_TO_1 ALL =~ /\nTo:\s+(?:[^\n<]{0,80}<)?([^\n\s>,]+)>?\n(?:[^\n]{1,200}\n)*Subject:\s+[^\n]{0,100}\1[^a-z0-9]/ism + +header __SUBJ_HAS_TO_2 ALL =~ /\nReceived:[^\n]{0,200} for ;]+)>?;(?:[^\n]+\n)*Subject:\s+[^\n]{0,100}\1[^a-z0-9]/ism + +header __SUBJ_HAS_TO_3 ALL =~ /\nSubject:(?=[^\n]{0,200}@)[^\n]{0,200}([a-z][a-z0-9_.]{3,80}@(?:[a-z0-9_]{1,80}\.){1,4}[a-z]{2,30})(?:[^\n]+\n)*To:\s+[^\n]{0,100}\1[^a-z0-9.]/ism + +header __SUBJ_NOT_SHORT Subject =~ /^.{16}/ + +header __SUBJ_OBFU_PUNCT Subject =~ /(?:[-~`"!@\#$%^&*()_+={}|\\\/?<>,.:;][a-z][-~`"!@\#$%^&*()_+={}|\\\/?<>,.:;\s]|(?:[a-z][~`"!@\#$%^&*()_+={}|\\?<>,.:;][a-z](?![a-z])))/i +tflags __SUBJ_OBFU_PUNCT multiple maxhits=4 + +header __SUBJ_RE Subject =~ /^(?:R[eE]|S[vV]|V[sS]|A[wW]):/ + +header __SUBJ_SHORT Subject =~ /^.{0,8}$/ + +header __SUBJ_USB_DRIVES Subject =~ /\bUSB (?:[Ff]lash )?[Dd]rives\b/ + +body __SUBSCRIPTION_INFO /\b(?:e?newsletters?|(?:un)?(?:subscrib|register)|you(?:r| are) subscri(?:b|ption)|opt(?:.|ing)?out\b|further info|you do ?n[o']t w(?:ish|ant)|remov\w{1,3}.{1,9}\blists?\b|to your white.?list)/i +tflags __SUBSCRIPTION_INFO nice + +body __SUM_OF_FUND /\b(?:sum|release|freigabe)\s(?:of|der)\s(?:amount|fund|investment|mittel)\b/i + +body __SURVEY /\bsurvey\b/i + +body __SURVIVORS /\b(?:widow|son|daughter|husband|wife|brother|sister|attorney|vi(?:=FA|[\xfa]|[\xc3][\xba])va|esposa|veuve)\s(?:of|to|do|de)\s(?:the\s)?(?:late|falecido|finales|feu|d(?:e|=E9|[\xe9]|[\xc3][\xa9])funt|mr\.?)\s\w+\b/i + +body __SUSPICION_LOGIN /\bsuspicion login\b/i + +body __SYSADMIN /\b(?:help?[- ]?desk|(?:(?:web ?)?mail ?|sys(?:tem )?)admin(?:istrator)|local[- ]host|(?:support|upgrade|management|security|admin(?:istrat(?:or|ion))?) (?:team|center)|message from administrator|university mail server copyright|suporte t(?:=E9|[\xe9]|[\xc3][\xa9])cnico|administrador do sistema)\b/i + +meta __TAGSTAT_IMG_NOT_RCVD_TGST __URI_IMG_TAGSTAT && !__HDR_RCVD_TAGSTAT + +meta __TARINGANET_IMG_NOT_RCVD_TN __URI_IMG_TARINGANET && !__HDR_RCVD_TARINGANET + +header __TB_MIME_BDRY_NO_Z Content-Type =~ /boundary="-{8,}(?:[1-9]){16}/ + +rawbody __TENWORD_GIBBERISH /^\s*(?:[a-z]+\s+){10}\.$/m +tflags __TENWORD_GIBBERISH multiple maxhits=21 + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __TEXT_XML_MT Content-Type =~ m,\btext/xml\b,i +endif + +body __THEY_INHERIT /\b(?:inherit\sth(?:e|is)\smoney|herede\sest[ea]\sdinero)\b/i + +body __THIS_AD /(?:\b|_)this[- _]+(?:ad(?:vert[i1l]sement)?|promo(?:tion)?)s?(?:\b|_)/i + +meta __THREADED (!__MISSING_REPLY && !__NO_INR_YES_REF) || (__MISSING_REPLY && !__MISSING_REF) +tflags __THREADED nice + +header __THREAD_INDEX_GOOD Thread-Index =~ m,^A[a-z0-9][A-Za-z0-9+/]{27}(?:[A-Za-z0-9+/]{20})?(?:[AQgw]==|[A-Za-z0-9+/]{7}|[A-Za-z0-9+/]{13}[AEIMQUYcgkosw048]=)$, + +header __TO_ALL_NUMS To:addr =~ /^\d+@/ + +meta __TO_EQ_FM_DIRECT_MX __TO_EQ_FROM && __DOS_DIRECT_TO_MX + +if !plugin(Mail::SpamAssassin::Plugin::SPF) + meta __TO_EQ_FM_DOM_SPF_FAIL 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::SPF + meta __TO_EQ_FM_DOM_SPF_FAIL __TO_EQ_FROM_DOM && SPF_FAIL + tflags __TO_EQ_FM_DOM_SPF_FAIL net +endif + +if !plugin(Mail::SpamAssassin::Plugin::SPF) + meta __TO_EQ_FM_SPF_FAIL 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::SPF + meta __TO_EQ_FM_SPF_FAIL __TO_EQ_FROM && SPF_FAIL + tflags __TO_EQ_FM_SPF_FAIL net +endif + +meta __TO_EQ_FROM (__TO_EQ_FROM_1 || __TO_EQ_FROM_2) +describe __TO_EQ_FROM To: same as From: + +header __TO_EQ_FROM_1 ALL =~ /\nFrom:\s+(?:[^\n<]{0,80}<)?([^\n\s>]+)>?\n(?:[^\n]{1,100}\n)*To:\s+(?:[^\n]{0,80}<)?\1[>,\s\n]/ism + +header __TO_EQ_FROM_2 ALL =~ /\nTo:\s+(?:[^\n<]{0,80}<)?([^\n\s>]+)>?\n(?:[^\n]{1,100}\n)*From:\s+(?:[^\n]{0,80}<)?\1[>,\s\n]/ism + +meta __TO_EQ_FROM_DOM (__TO_EQ_FROM_DOM_1 || __TO_EQ_FROM_DOM_2) +describe __TO_EQ_FROM_DOM To: domain same as From: domain + +header __TO_EQ_FROM_DOM_1 ALL =~ /\nFrom:\s+[^\n@]{0,80}@([^\n\s>]+)>?\n(?:[^\n]{1,100}\n)*To:\s+[^\n]+@\1[>,\s\n]/ism + +header __TO_EQ_FROM_DOM_2 ALL =~ /\nTo:\s+[^\n@]{0,80}@([^\n\s>]+)>?\n(?:[^\n]{1,100}\n)*From:\s+[^\n]+@\1[>,\s\n]/ism + +meta __TO_EQ_FROM_USR (__TO_EQ_FROM_USR_1 || __TO_EQ_FROM_USR_2) && !(__FROM_DNS || __FROM_INFO || __SENDER_BOT) +describe __TO_EQ_FROM_USR To: username same as From: username + +header __TO_EQ_FROM_USR_1 ALL =~ /\nFrom:\s+(?:[^\n<]{0,80}<)?([^\n\s\@>]+)\@[^\n\s]+>?\n(?:[^\n]{1,100}\n)*To:\s+(?:[^\n]{0,80}<)?\1[\@>,\s\n]/ism + +header __TO_EQ_FROM_USR_2 ALL =~ /\nTo:\s+(?:[^\n<]{0,80}<)?([^\n\s\@>]+)\@[^\n\s]+>?\n(?:[^\n]{1,100}\n)*From:\s+(?:[^\n]{0,80}<)?\1[\@>,\s\n]/ism + +meta __TO_EQ_FROM_USR_NN (__TO_EQ_FROM_USR_NN_1 || __TO_EQ_FROM_USR_NN_2) && !(__FROM_DNS || __FROM_INFO || __SENDER_BOT) +describe __TO_EQ_FROM_USR_NN To: username same as From: username sans trailing nums + +header __TO_EQ_FROM_USR_NN_1 ALL =~ /\nFrom:\s+(?:[^\n<]{0,80}<)?([^\n\s\@>]{4,80}?)\d*\@[^\n\s]+>?\n(?:[^\n]{1,100}\n)*To:\s+(?:[^\n]{0,80}<)?\1\d*[\@>,\s\n]/ism + +header __TO_EQ_FROM_USR_NN_2 ALL =~ /\nTo:\s+(?:[^\n<]{0,80}<)?([^\n\s\@>]{4,80}?)\d*\@[^\n\s]+>?\n(?:[^\n]{1,100}\n)*From:\s+(?:[^\n]{0,80}<)?\1\d*[\@>,\s\n]/ism + +meta __TO_EQ_FROM_USR_NN_MINFP __TO_EQ_FROM_USR_NN && !__TO_EQ_FROM_USR_1 && !__TO_EQ_FROM && !__TO_EQ_FROM_DOM && !__LCL__ENV_AND_HDR_FROM_MATCH && !__DKIM_EXISTS && !__NOT_SPOOFED && !__RCD_RDNS_SMTP && !__RCD_RDNS_MX_MESSY && !__THREADED + +meta __TO_IN_SUBJ (__SUBJ_HAS_TO_1 || __SUBJ_HAS_TO_2 || __SUBJ_HAS_TO_3) + +header __TO_NO_ARROWS_R To !~ /(?:>$|>,)/ + +if !plugin(Mail::SpamAssassin::Plugin::FreeMail) + meta __TO_NO_BRKTS_FREEMAIL 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::FreeMail + meta __TO_NO_BRKTS_FREEMAIL __TO_NO_ARROWS_R && (FREEMAIL_FROM || FREEMAIL_REPLYTO) +endif + +meta __TO_NO_BRKTS_FROM_RUNON __TO_NO_ARROWS_R && !__TO_UNDISCLOSED && __FROM_RUNON + +meta __TO_NO_BRKTS_HTML_IMG __TO_NO_ARROWS_R && !__TO_UNDISCLOSED && HTML_MESSAGE && __ONE_IMG + +meta __TO_NO_BRKTS_HTML_ONLY __TO_NO_ARROWS_R && !__TO_UNDISCLOSED && MIME_HTML_ONLY + +meta __TO_NO_BRKTS_MSFT __TO_NO_ARROWS_R && !__TO_UNDISCLOSED && (__ANY_OUTLOOK_MUA || __MIMEOLE_MS) + +meta __TO_NO_BRKTS_NORDNS_HTML __TO_NO_BRKTS_HTML_ONLY && RDNS_NONE + +meta __TO_NO_BRKTS_PCNT __TO_NO_ARROWS_R && __FB_NUM_PERCNT + +meta __TO_TOO_MANY_WFH_01 __TO_WAY_TOO_MANY && __WFH_01 + +header __TO_UNDISCLOSED To =~ /\b(?:undisclosed[-\s]recipients|destinataires inconnus|destinatari nascosti)\b/i + +header __TO_WAY_TOO_MANY ToCc =~ /(?:,[^,]{1,90}){50}/ + +body __TO_YOUR_ACCT /\b(?:(?:f[uo]nds|money|f[uo]ndo|dinheiro|bank)\s(?:\w{1,10}\s){0,4}(?:transfer(?:red)?|transferido|sont)|\d+)\s(?:to|para|en)\s(?:your?|sua|votre)\s(?:account|conta|pos+es+ion)/i + +body __TO_YOUR_ORG /\b(?:to|for) your organi[sz]ation\b/i + +header __TO___LOWER ALL =~ /to:\s\S{5}/ + +body __TRANSFORM_LIFE /\b(transform|change) your (?:daily )?life(?:style)?\b/i + +body __TRAVEL_AGENT /\btravel\sagen(?:t|cy)\b/i + +body __TRAVEL_BUSINESS /\bbusiness\stravel\b/i + +body __TRAVEL_ITINERARY /(?:travel|ticketed|your|current) itinerary/i + +meta __TRAVEL_MANY (__TRAVEL_PROFILE + __TRAVEL_RESERV + __TRAVEL_BUSINESS + __TRAVEL_AGENT) > 2 + +body __TRAVEL_PROFILE /\btravel+er\sprofile\b/i + +body __TRAVEL_RESERV /\b(?:reservation\s(?:confirmed|number)|travel\sreservations?)\b/i + +body __TRTMT_DEFILED /\bdefiled\sall\s(?:forms\sof\s)?(?:medical\s)?treatments?\b/i + +body __TRUNK_BOX /\b(?:(?:trunk|metallic|proof|security|consignment)\sbox(?:es)?|sealed\ssafe|une mallette m(?:e|=E9|[\xe9]|[\xc3][\xa9])tallique)\b/i + +body __TRUSTED_CHECK /\b(?:cashier'?s?|certified)\sche(?:ck|que)/i + +rawbody __TR_JS_CONCATINATED_HTTP m@\b(?!http:/)h["'+]{0,3}(?:t["'+]{0,3}){2}p['"+]{0,3}:['"+]{0,3}/@ +describe __TR_JS_CONCATINATED_HTTP Contains concatenated URI like "htt"+"p://..." + +rawbody __TR_JS_EXTRA_CONCAT /[+=(]\s{0,9}["'][a-z0-9.]{1,32}["'] ?\+ ?["'][a-z0-9]{1,32}["']/i +describe __TR_JS_EXTRA_CONCAT JavaScript: Unnecessary string concatenation + +rawbody __TR_JS_EXTRA_UNESCAPE /[+=(]\s{0,9}unescape\s{0,9}\(\s{0,9}["']%(?i:6[1-9A-F]|7[0-9A])/ +describe __TR_JS_EXTRA_UNESCAPE JavaScript: Unnecessary URI escaping + +header __TT_BROKEN_VALIUM Subject =~ /V[:^."%()*\[\\]?A[:^."%()*\[\\]?L[:^."%()*\[\\]?I[:^."%()*\[\\]?U[:^."%()*\[\\]?M/i + +header __TT_BROKEN_VIAGRA Subject =~ /V[:^."%()*\[\\]?I[:^."%()*\[\\]?A[:^."%()*\[\\]?G[:^."%()*\[\\]?R[:^."%()*\[\\]?A/i + +header __TT_OBSCURED_VALIUM Subject =~ /(v|V|\\\/)(a|A|\(a\)|4|@)(l|L|\|)(i|I|1|\xef|\|)(u|U|\(u\))(m|M)/ + +header __TT_OBSCURED_VIAGRA Subject =~ /(v|V|\\\/)(i|I|1|\xef|\|)(a|A|\(a\)|4|@)(g|G)(r|R)(a|A|\(a\)|4|@)/ + +header __TT_VALIUM Subject =~ /VALIUM/i + +header __TT_VIAGRA Subject =~ /VIAGRA/i + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __TVD_FW_GRAPHIC_ID1 Content-Id =~ /<[0-9a-f]{12}(?:\$[0-9a-f]{8}){2}\@/ +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __TVD_MIME_ATT_AOPDF Content-Type =~ /^application\/octet-stream.*\.pdf/i +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __TVD_MIME_ATT_AP Content-Type =~ /^application\/pdf/i +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __TVD_MIME_ATT_TP Content-Type =~ /^text\/plain/i +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader +mimeheader __TVD_OUTLOOK_IMG Content-Id =~ / 9 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + body __UNICODE_OBFU_ZW /[a-z0-9\s](?:\x9d|\xe2\x80[\x8b\x8c\x8d]|\xef\xbb\xbf)+(?!\s)[a-z0-9\s]{1,8}(?:\x9d|\xe2\x80[\x8b\x8c\x8d]|\xef\xbb\xbf)+[a-z0-9\s]/i + tflags __UNICODE_OBFU_ZW multiple maxhits=10 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __UNICODE_OBFU_ZW_10 __UNICODE_OBFU_ZW > 9 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __UNICODE_OBFU_ZW_2 __UNICODE_OBFU_ZW > 1 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __UNICODE_OBFU_ZW_3 __UNICODE_OBFU_ZW > 2 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __UNICODE_OBFU_ZW_5 __UNICODE_OBFU_ZW > 4 +endif + +body __UNSUB_EMAIL /\b(?:(?:un)?subscri(?:ber?|ptions?)|abuses?|opt(?:ing)?.?out)\b[-a-z_0-9.+=]{0,60}\@[a-z0-9][-a-z_0-9.]{4,20}(?:[^a-z_0-9.-]|$)/i +tflags __UNSUB_EMAIL nice + +body __UNSUB_GOOG_FORM m,Unsub?sc?ribe\s= 3.004002) +ifplugin Mail::SpamAssassin::Plugin::WLBLEval +header __VPSNUMBERONLY_TLD From:addr =~ /\@vps[0-9]{4,}\.[a-z]+$/i +endif +endif + +meta __WALMART_IMG_NOT_RCVD_WAL __URI_IMG_WALMART && !__HDR_RCVD_WALMART + +body __WEBMAIL_ACCT /\byour web ?mail account/i + +body __WE_PAID /\bwe have (?:already )?(?:paid|sent|remitted|issued) \$?\d+(?:,\d+)* (?:thousand )?(?:dollars )?to our (?:users|subscribers|members|clients|affiliates|partners)\b/i + +meta __WFH_01 ( __PERFECT_BINARY + __WE_PAID + __MAKE_XTRA_DOLLAR + __BONUS_LAST_DAY + __PASSIVE_INCOME + __WITHOUT_EFFORT + __TRANSFORM_LIFE + __STAY_HOME + __RECEIVE_BONUS ) > 2 + +body __WIDOW /\b(?:widow(?:e[rd])'?s?|veuve)\b/i + +body __WILL_LEGAL /\b(?:codicil|last\stestament|probate|executor|intestate|bequest|mandamus)\b/i + +body __WIRE_XFR /\b(?:wire|telegraph(?:ic)?|bank)\s?transfer/i + +body __WITHOUT_EFFORT /\bwith(?:out(?: a(?:ny)?| the)?| no)(?: great| special| extra)? effort\b/i + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + rawbody __WORD_INVIS /<(?!style)[a-z]+\s[^>]{1,80}(?:font(?:-size)?\s*:\s*(?:0*[01](?:\.\d+)?(?:px|pt|Q|vw|vh|vmin)|0+(?:\.\d+)?(?:cm|mm|in|pc|em|ex|ch|rem|lh|vmax))\s*[;'a-z]|['"\s;]color\s*:\s*transparent\s*[;'])[^>]{0,80}>\w{1,20} 1 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __WORD_INVIS_5 __WORD_INVIS > 5 +endif + +if can(Mail::SpamAssassin::Conf::feature_bug6558_free) + meta __WORD_INVIS_MINFP __WORD_INVIS && !__SURVEY && !MIME_QP_LONG_LINE && !__FB_TOUR && !__MSGID_GUID +endif + +header __XEROXWORKCTR_MUA X-Mailer =~ /^WorkCentre \D?\d[\d\.]\d+/ + +meta __XFER_LOTSA_MONEY __XFER_MONEY && LOTS_OF_MONEY + +meta __XFER_MONEY (__WIRE_XFR || __TRUSTED_CHECK || __BANK_DRAFT || __MOVE_MONEY || __TO_YOUR_ACCT || __PAY_YOU || __GIVE_MONEY) + +ifplugin Mail::SpamAssassin::Plugin::FreeMail + header __XMAIL_CODEIGN X-Mailer =~ /CodeIgniter/ +endif + +ifplugin Mail::SpamAssassin::Plugin::FreeMail + header __XMAIL_PHPMAIL X-Mailer =~ /PHPMailer/ +endif + +header __XM_APPLEMAIL X-Mailer =~ /^Apple Mail/ + +header __XM_ASPQMAIL X-Mailer =~ /^AspQMail/ + +header __XM_BALSA X-Mailer =~ /^Balsa \d/ + +header __XM_CALYPSO X-Mailer =~ /^Calypso/ + +header __XM_DIGITS_ONLY X-Mailer =~ /^\s*\d+\s*$/ + +header __XM_EC_MESSENGER X-Mailer =~ /\beC-Messenger\b/ + +header __XM_FORTE X-Mailer =~ /^Forte Agent \d/ + +header __XM_GNUS X-Mailer =~ /^Gnus v/ + +header __XM_MHE X-Mailer =~ /^mh-e \d/ + +header __XM_MOZ4 X-Mailer =~ /^Mozilla 4/ + +header __XM_MSOE5 X-Mailer =~ /^Microsoft Outlook Express 5/ + +header __XM_MSOE6 X-Mailer =~ /^Microsoft Outlook Express 6/ + +header __XM_MS_IN_GENERAL X-Mailer =~ /\bMSCRM\b|Microsoft (?:CDO|Outlook|Office Outlook)\b/ + +header __XM_OL_10_0_4115 X-Mailer =~ /^Microsoft Outlook, Build 10.0.4115$/ + +header __XM_OL_28001441 X-Mailer =~ /^Microsoft Outlook Express 6.00.2800.1441$/ + +header __XM_OL_28004682 X-Mailer =~ /^Microsoft Outlook Express 6.00.2800.4682$/ + +header __XM_OL_48072300 X-Mailer =~ /^Microsoft Outlook Express 5.50.4807.2300$/ + +header __XM_OL_4_72_2106_4 X-Mailer =~ /^Microsoft Outlook Express 4.72.2106.4$/ + +header __XM_OUTLOOK_EXPRESS X-Mailer =~ /^Microsoft Outlook Express \d/ + +header __XM_PHPMAILER_FORGED X-Mailer =~ /PHPMailer\s.*version\D+$/ + +header __XM_RANDOM X-Mailer =~ /q(?!(?:q|box|i\s)?mail|\d|[-\w]*=+;)[^u]/i + +header __XM_SKYRI X-Mailer =~ /^SKYRiXgreen/ + +header __XM_SQRLMAIL X-Mailer =~ /^SquirrelMail/ + +header __XM_SYLPHEED X-Mailer =~ /^Sylpheed/ + +header __XM_UC_ONLY X-Mailer =~ /^[^a-z]+$/ + +header __XM_VERY_LONG X-Mailer =~ /.{50}/ + +header __XM_VM X-Mailer =~ /^VM \d/ + +header __XM_WWWMAIL X-Mailer =~ /^WWW-Mail \d/ + +header __XM_XIMEVOL X-Mailer =~ /^Ximian Evolution/ + +meta __XPRIO_MINFP __XPRIO && !__CT_ENCRYPTED && !ALL_TRUSTED && !__HAS_ERRORS_TO && !__HAS_IMG_SRC && !__RCD_RDNS_MAIL_MESSY && !__VIA_ML && !__PHPMAILER_MUA && !__AC_TINY_FONT && !__HAS_PHP_SCRIPT && !__DOS_HAS_LIST_UNSUB && !__HAS_IMG_SRC_ONECASE && !__NAKED_TO && !__HAS_THREAD_INDEX && !__HAS_TNEF && !__HAS_SENDER && !__UNPARSEABLE_RELAY_COUNT && !__PDS_RDNS_MTA && !__RCD_RDNS_SMTP_MESSY && !__RCD_RDNS_MX_MESSY && !__TO___LOWER && !__FROM_WORDY && !__RP_MATCHES_RCVD && !__DKIM_EXISTS && !__FROM_WEB_DAEMON && !__RDNS_SHORT && !__L_BODY_8BITS && !__HAS_X_SENDER + +meta __XPRIO_SHORT_SUBJ __XPRIO_MINFP && __SUBJ_SHORT + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __X_MSO_MT Content-Type =~ m,\bapplication/x-mso\b,i +endif + +body __YOUR_BANK /\byour?\s(?:full\s)?bank(?:ing)?\sinformations?\b/i + +body __YOUR_CONSIGNMENT /\b(?:received?|pa(?:y|id)|sen[dt]|h[oe]ld|delay(?:ed)?|impound(?:ed)?|released?|ship(?:ped)?)\syour(?:\s\w+)?\sconsignment\b/i + +body __YOUR_FUND /\b(?:your|ihr)\s(?:unpaid\s|win+ing\s|ap+roved\s|foreign\s|overdue\s|outstanding\s|contract\s|inheritance\s|nicht\sausbezahlten\s){0,3}(?:fund|f\su\sn\sd|payment|geld)\b/i + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __YOUR_ONAN /\b(?:your?|ihrer)\s(?:ma+s+t+[ur]+b+a+t+(?:ion|ing|e)(?:svideo)?|onanism|solitary\ssex|hand\sfucking|Selbstbefriedigung|(?:pleasur(?:e|ing)|satisfy(?:ing)?)\syourself)\b/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __YOUR_ONAN /(?:^|\s)(?:?|)\s(?:++++(?:|)++++(?:||)(?:)?||\s|\s||(?:

(?:|)|(?:)?)\s)/i +endif + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __YOUR_PASSWORD /\b(?:your|(?:change|modify|update|reset|alter|fix)\sthe)\s(?:account\s|e-?mail\s)?(?:pass[-\s_]?word|pswd)\b/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __YOUR_PASSWORD /(?:^|\s)(?:|(?:||

|||)\s)\s(?:\s|-?\s)?(?:

[-\s_]?|

\s)/i +endif + +body __YOUR_PERM /\byour\spermission\b/i + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __YOUR_PERSONAL /\b(?:your\s(?:personal|private|social\scontact|address|friends)\s(?:info(?:rmation)?|data|details|book|secrets)|all\s(?:of\s)?your\s(?:files|contacts|secrets|correspondence))\b/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __YOUR_PERSONAL /(?:^|\s)(?:\s(?:

|

|\s||)\s(?:(?:)?||||)|\s(?:\s)?\s(?:|||

))[\s\.,]/i +endif + +body __YOUR_PROFIT /\byour?\sprofit/i + +if !plugin(Mail::SpamAssassin::Plugin::ReplaceTags) + body __YOUR_WEBCAM /\b(?:from|your|with|and|on)\s(?:(?:screen|desktop|microphone)\sand\s|own\s)?(?:web[-\s]?|front[-\s]?|network\s|your\s)camer+a/i +endif + +ifplugin Mail::SpamAssassin::Plugin::ReplaceTags + body __YOUR_WEBCAM /(?:^|\s)(?:||||)\s(?:(?:|

|

)\s\s|\s)?(?:[-\s]?|[-\s]?|\s|\s)+/i +endif + +body __YOU_ASSIST /\b(?:your\sas+istan(?:ce|t)|votre\s(?:as+istance|aide))\b/i + +body __YOU_INHERIT /\byour\s[a-z\s]{0,30}inherit+ance\b/i + +meta __YOU_WON __YOU_WON_01 || __YOU_WON_02 || __YOU_WON_03 || __YOU_WON_04 || __HAS_WON_01 || (__YOU_WON_05 && (__MOVE_MONEY || __GIVE_MONEY)) + +body __YOU_WON_01 /\byou(?:r|'re|'ve|'ll|\shave|\sdid)?\s(?:e-?mail\s)?(?:\w+\s){0,2}(?:a\s)?w[io]n+(?:er|ing)?(?!\xe2\x80\x99t)(?![`'\x92]t)\b/i + +body __YOU_WON_02 /\bw[io]n\s(?:(?:for|by)\s)?your?\b/i + +body __YOU_WON_03 /\b(?:your?|win+ing|win+ers?|beneficiaries|participants?|individuals?|address(?:es)?|accounts?|emails?)(?:\s[-a-z\s]{4,40})?\s(?:w(?:ere|as)|ha(?:ve|s) be(?:en)?)\s(?:automatically\s)?(?:(?:randomly|raffly)\s(?:selected|cho+sen|cho+sing|picked)|(?:selected|cho+sen|cho+sing|picked)\s(?:[a-z\s]{2,40}?\srandom(?:ly)?|online|lottery|computer\s(?:ballot|wahlgang))|(?:selected|cho+sen|cho+sing|picked)(?:\sas?|\sthe){0,3}\swin+er)/i + +body __YOU_WON_04 /\bqu[ei]\s?(?:vous (?:[\xc3][\xaa]|=C3=AA|[\xea]|e)tes\s?gagnant|en\scons(?:e|=E9|[\xe9]|[\xc3][\xa9])quence\sgagne)\b/i + +body __YOU_WON_05 /\bI won(?!\xe2\x80\x99t)(?![`'\x92]t)\b/i + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __ZIP_ATTACH_MT 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __ZIP_ATTACH_MT Content-Type =~ m,\bapplication/(?:zip|x-(?:zip-)?compress(?:ed)?)\b,i +endif + +if !plugin(Mail::SpamAssassin::Plugin::MIMEHeader) + meta __ZIP_ATTACH_NOFN 0 +endif + +ifplugin Mail::SpamAssassin::Plugin::MIMEHeader + mimeheader __ZIP_ATTACH_NOFN Content-Type =~ m,\bapplication/(?:zip|x-(?:zip-)?compress(?:ed)?)[;\s]*$,i +endif + +ifplugin Mail::SpamAssassin::Plugin::FreeMail + header __freemail_mailreplyto eval:check_freemail_header('Mail-Reply-To') +endif + +body __hk_bigmoney /(?:EURO?|USD?|GBP|CFA|\&\#163;|[\xa3\xa4]|\$|sum of).{0,4}(?:[0-9]{3}[^0-9a-z]?[0-9]{3}|[0-9.,]{1,4}(?: ?M\b| ?(?:de )?Mil))/i + +ifplugin Mail::SpamAssassin::Plugin::FreeMail +header __smf_freemail_hdr_replyto eval:check_freemail_header('Reply-To:addr') +endif diff --git a/resources/spamassassin/72_scores.cf b/resources/spamassassin/72_scores.cf new file mode 100644 index 00000000..600b25a7 --- /dev/null +++ b/resources/spamassassin/72_scores.cf @@ -0,0 +1,407 @@ +score AC_BR_BONANZA 0.001 0.001 0.001 0.001 +score AC_DIV_BONANZA 0.001 0.001 0.001 0.001 +score AC_FROM_MANY_DOTS 2.999 2.999 2.999 2.999 +score AC_HTML_NONSENSE_TAGS 1.999 1.999 1.999 1.999 +score AC_POST_EXTRAS 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS1 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS10 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS11 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS12 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS2 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS3 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS4 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS8 1.000 1.000 1.000 1.000 +score AC_SPAMMY_URI_PATTERNS9 1.000 1.000 1.000 1.000 +score ADMITS_SPAM 3.299 0.001 3.299 0.001 +score ADULT_DATING_COMPANY 10.000 10.000 10.000 10.000 +score ADVANCE_FEE_2_NEW_FORM 1.000 1.000 1.000 1.000 +score ADVANCE_FEE_2_NEW_FRM_MNY 1.000 1.000 1.000 1.000 +score ADVANCE_FEE_2_NEW_MONEY 1.999 1.999 1.999 1.999 +score ADVANCE_FEE_3_NEW 2.350 2.776 2.350 2.776 +score ADVANCE_FEE_3_NEW_MONEY 0.488 2.599 0.488 2.599 +score ADVANCE_FEE_4_NEW 2.499 2.399 2.499 2.399 +score ADVANCE_FEE_4_NEW_MONEY 2.126 0.001 2.126 0.001 +score ADVANCE_FEE_5_NEW_FRM_MNY 0.841 2.499 0.841 2.499 +score ADVANCE_FEE_5_NEW_MONEY 0.001 0.001 0.001 0.001 +score AD_PREFS 0.499 0.001 0.499 0.001 +score ALIBABA_IMG_NOT_RCVD_ALI 1.000 1.000 1.000 1.000 +score AMAZON_IMG_NOT_RCVD_AMZN 0.001 0.001 0.001 0.001 +score APP_DEVELOPMENT_FREEM 1.000 1.000 1.000 1.000 +score APP_DEVELOPMENT_NORDNS 1.000 1.000 1.000 1.000 +score ARC_SIGNED 0.001 0.001 0.001 0.001 +score ARC_VALID 0.001 0.001 0.001 0.001 +score AXB_XMAILER_MIMEOLE_OL_024C2 0.001 0.001 0.001 0.001 +score AXB_X_FF_SEZ_S 2.499 2.699 2.499 2.699 +score BAT_BDRY_TO_MALF 2.499 2.499 2.499 2.499 +score BEBEE_IMG_NOT_RCVD_BB 1.000 1.000 1.000 1.000 +score BIGNUM_EMAILS_FREEM 0.001 0.001 0.001 0.001 +score BIGNUM_EMAILS_MANY 2.999 2.999 2.999 2.999 +score BITCOIN_BOMB 1.000 1.000 1.000 1.000 +score BITCOIN_DEADLINE 2.999 2.278 2.999 2.278 +score BITCOIN_EXTORT_01 2.102 1.793 2.102 1.793 +score BITCOIN_EXTORT_02 1.000 1.000 1.000 1.000 +score BITCOIN_IMGUR 1.000 1.000 1.000 1.000 +score BITCOIN_MALF_HTML 2.834 0.776 2.834 0.776 +score BITCOIN_MALWARE 1.670 0.001 1.670 0.001 +score BITCOIN_OBFU_SUBJ 1.000 1.000 1.000 1.000 +score BITCOIN_ONAN 1.146 2.042 1.146 2.042 +score BITCOIN_PAY_ME 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_01 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_02 1.436 0.696 1.436 0.696 +score BITCOIN_SPAM_03 2.499 2.500 2.499 2.500 +score BITCOIN_SPAM_04 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_05 0.001 1.565 0.001 1.565 +score BITCOIN_SPAM_06 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_07 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_08 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_09 1.499 1.499 1.499 1.499 +score BITCOIN_SPAM_10 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_11 1.000 1.000 1.000 1.000 +score BITCOIN_SPAM_12 1.000 1.000 1.000 1.000 +score BITCOIN_SPF_ONLYALL 0.001 1.000 0.001 1.000 +score BITCOIN_XPRIO 0.510 0.001 0.510 0.001 +score BITCOIN_YOUR_INFO 1.395 1.916 1.395 1.916 +score BODY_URI_ONLY 1.153 0.484 1.153 0.484 +score BOGUS_MIME_VERSION 1.000 1.000 1.000 1.000 +score BOGUS_MSM_HDRS 1.000 1.000 1.000 1.000 +score BOMB_FREEM 1.000 1.000 1.000 1.000 +score BOMB_MONEY 1.000 1.000 1.000 1.000 +score BTC_ORG 1.000 1.000 1.000 1.000 +score BULK_RE_SUSP_NTLD 0.920 1.000 0.920 1.000 +score CANT_SEE_AD 1.000 1.000 1.000 1.000 +score CK_HELO_GENERIC 0.250 0.249 0.250 0.249 +score COMMENT_GIBBERISH 1.000 1.000 1.000 1.000 +score COMPENSATION 1.000 0.001 1.000 0.001 +score CONTENT_AFTER_HTML 1.000 1.000 1.000 1.000 +score CONTENT_AFTER_HTML_WEAK 1.000 1.000 1.000 1.000 +score CTE_8BIT_MISMATCH 0.999 0.001 0.999 0.001 +score DATE_IN_FUTURE_Q_PLUS 2.699 2.699 2.699 2.699 +score DAY_I_EARNED 1.000 1.000 1.000 1.000 +score DEAR_BENEFICIARY 1.865 1.387 1.865 1.387 +score DKIMWL_BL 0.001 1.000 0.001 1.000 +score DKIMWL_BLOCKED 0.001 0.001 0.001 0.001 +score DKIMWL_WL_HIGH 0.001 -0.001 0.001 -0.001 +score DKIMWL_WL_MED 0.001 -0.001 0.001 -0.001 +score DKIMWL_WL_MEDHI 0.001 -0.214 0.001 -0.214 +score DOTGOV_IMAGE 1.000 1.000 1.000 1.000 +score DX_TEXT_03 1.699 1.799 1.699 1.799 +score DYNAMIC_IMGUR 1.000 1.000 1.000 1.000 +score EBAY_IMG_NOT_RCVD_EBAY 1.000 1.000 1.000 1.000 +score ENCRYPTED_MESSAGE -1.000 -0.999 -1.000 -0.999 +score END_FUTURE_EMAILS 2.500 2.499 2.500 2.499 +score ENVFROM_GOOG_TRIX 1.000 1.000 1.000 1.000 +score FACEBOOK_IMG_NOT_RCVD_FB 1.000 1.000 1.000 1.000 +score FBI_MONEY 1.000 0.001 1.000 0.001 +score FBI_SPOOF 1.000 1.109 1.000 1.109 +score FILL_THIS_FORM 0.799 0.699 0.799 0.699 +score FONT_INVIS_DIRECT 0.001 0.001 0.001 0.001 +score FONT_INVIS_DOTGOV 1.000 1.000 1.000 1.000 +score FONT_INVIS_HTML_NOHTML 1.000 1.000 1.000 1.000 +score FONT_INVIS_LONG_LINE 2.999 3.000 2.999 3.000 +score FONT_INVIS_MSGID 1.762 1.942 1.762 1.942 +score FONT_INVIS_NORDNS 0.001 1.614 0.001 1.614 +score FONT_INVIS_POSTEXTRAS 0.155 1.389 0.155 1.389 +score FORM_FRAUD 0.001 1.000 0.001 1.000 +score FORM_FRAUD_3 2.399 0.001 2.399 0.001 +score FORM_FRAUD_5 0.889 0.001 0.889 0.001 +score FOUND_YOU 1.000 1.000 1.000 1.000 +score FREEMAIL_FORGED_FROMDOMAIN 0.249 0.001 0.249 0.001 +score FREEM_FRNUM_UNICD_EMPTY 1.000 1.000 1.000 1.000 +score FRNAME_IN_MSG_XPRIO_NO_SUB 1.000 1.000 1.000 1.000 +score FROM_2_EMAILS_SHORT 0.001 1.306 0.001 1.306 +score FROM_ADDR_WS 1.000 2.999 1.000 2.999 +score FROM_BANK_NOAUTH 0.001 1.000 0.001 1.000 +score FROM_FMBLA_NDBLOCKED 0.001 0.001 0.001 0.001 +score FROM_FMBLA_NEWDOM 0.001 1.500 0.001 1.500 +score FROM_FMBLA_NEWDOM14 0.001 1.000 0.001 1.000 +score FROM_FMBLA_NEWDOM28 0.001 0.799 0.001 0.799 +score FROM_GOV_DKIM_AU 0.001 -0.001 0.001 -0.001 +score FROM_GOV_REPLYTO_FREEMAIL 0.001 1.000 0.001 1.000 +score FROM_GOV_SPOOF 0.001 1.000 0.001 1.000 +score FROM_MISSPACED 2.000 1.999 2.000 1.999 +score FROM_MISSP_EH_MATCH 1.999 1.595 1.999 1.595 +score FROM_MISSP_FREEMAIL 0.001 1.017 0.001 1.017 +score FROM_MISSP_MSFT 0.001 0.001 0.001 0.001 +score FROM_MISSP_REPLYTO 2.198 0.001 2.198 0.001 +score FROM_MISSP_SPF_FAIL 0.001 0.185 0.001 0.185 +score FROM_MISSP_USER 0.001 0.001 0.001 0.001 +score FROM_MULTI_NORDNS 1.786 1.002 1.786 1.002 +score FROM_NEWDOM_BTC 0.001 1.000 0.001 1.000 +score FROM_NTLD_LINKBAIT 1.000 1.000 1.000 1.000 +score FROM_NTLD_REPLY_FREEMAIL 1.000 1.000 1.000 1.000 +score FROM_NUMBERO_NEWDOMAIN 0.001 1.000 0.001 1.000 +score FROM_PAYPAL_SPOOF 0.001 1.599 0.001 1.599 +score FROM_SUSPICIOUS_NTLD 0.499 0.499 0.499 0.499 +score FROM_SUSPICIOUS_NTLD_FP 1.999 1.999 1.999 1.999 +score FSL_BULK_SIG 0.001 0.001 0.001 0.001 +score FSL_CTYPE_WIN1251 0.001 0.001 0.001 0.001 +score FSL_NEW_HELO_USER 0.001 0.001 0.001 0.001 +score FUZZY_AMAZON 0.001 0.001 0.001 0.001 +score FUZZY_BITCOIN 0.001 0.001 0.001 0.001 +score FUZZY_PORN 0.269 0.001 0.269 0.001 +score FUZZY_WALLET 1.799 0.001 1.799 0.001 +score GAPPY_SALES_LEADS_FREEM 1.000 1.000 1.000 1.000 +score GB_BITCOIN_CP 1.004 2.910 1.004 2.910 +score GB_BITCOIN_NH 0.965 0.737 0.965 0.737 +score GB_CUSTOM_HTM_URI 1.499 0.490 1.499 0.490 +score GB_FAKE_RF_SHORT 1.061 1.460 1.061 1.460 +score GB_FORGED_MUA_POSTFIX 1.000 1.000 1.000 1.000 +score GB_FREEMAIL_DISPTO 0.499 0.500 0.499 0.500 +score GB_FREEMAIL_DISPTO_NOTFREEM 0.500 0.500 0.500 0.500 +score GB_GOOGLE_OBFUR 0.750 0.750 0.750 0.750 +score GB_HASHBL_BTC 0.001 0.001 0.001 0.001 +score GB_STORAGE_GOOGLE_EMAIL 1.000 1.000 1.000 1.000 +score GB_URI_FLEEK_STO_HTM 0.999 0.999 0.999 0.999 +score GOOGLE_DOCS_PHISH 1.000 1.000 1.000 1.000 +score GOOGLE_DOCS_PHISH_MANY 1.000 1.000 1.000 1.000 +score GOOGLE_DOC_SUSP 1.000 1.000 1.000 1.000 +score GOOGLE_DRIVE_REPLY_BAD_NTLD 1.000 1.000 1.000 1.000 +score GOOG_MALWARE_DNLD 1.000 1.000 1.000 1.000 +score GOOG_REDIR_HTML_ONLY 2.000 1.999 2.000 1.999 +score GOOG_REDIR_NORDNS 2.499 2.549 2.499 2.549 +score GOOG_STO_EMAIL_PHISH 1.000 1.000 1.000 1.000 +score GOOG_STO_HTML_PHISH 1.000 1.000 1.000 1.000 +score GOOG_STO_HTML_PHISH_MANY 1.000 1.000 1.000 1.000 +score GOOG_STO_IMG_HTML 1.000 1.000 1.000 1.000 +score GOOG_STO_IMG_NOHTML 2.499 2.499 2.499 2.499 +score GOOG_STO_NOIMG_HTML 2.999 2.891 2.999 2.891 +score HAS_X_NO_RELAY 1.000 1.000 1.000 1.000 +score HAS_X_OUTGOING_SPAM_STAT 0.503 0.728 0.503 0.728 +score HDRS_LCASE_IMGONLY 0.099 0.100 0.099 0.100 +score HDRS_MISSP 2.500 2.499 2.500 2.499 +score HDR_ORDER_FTSDMCXX_DIRECT 0.001 0.001 0.001 0.001 +score HDR_ORDER_FTSDMCXX_NORDNS 0.001 0.001 0.001 0.001 +score HEADER_FROM_DIFFERENT_DOMAINS 0.250 0.249 0.250 0.249 +score HELO_NO_DOMAIN 0.001 0.001 0.001 0.001 +score HEXHASH_WORD 1.000 1.000 1.000 1.000 +score HK_CTE_RAW 1.000 1.000 1.000 1.000 +score HK_LOTTO 0.626 0.001 0.626 0.001 +score HK_NAME_MR_MRS 1.000 0.999 1.000 0.999 +score HK_RANDOM_ENVFROM 0.999 0.999 0.999 0.999 +score HK_RANDOM_FROM 0.999 0.999 0.999 0.999 +score HK_RANDOM_REPLYTO 0.999 0.999 0.999 0.999 +score HK_RCVD_IP_MULTICAST 1.000 1.000 1.000 1.000 +score HK_SCAM 1.999 1.999 1.999 1.999 +score HOSTED_IMG_DIRECT_MX 0.001 0.289 0.001 0.289 +score HOSTED_IMG_DQ_UNSUB 1.000 1.000 1.000 1.000 +score HOSTED_IMG_FREEM 3.499 3.464 3.499 3.464 +score HOSTED_IMG_MULTI 1.000 1.000 1.000 1.000 +score HOSTED_IMG_MULTI_PUB_01 2.999 2.999 2.999 2.999 +score HTML_ENTITY_ASCII 2.999 2.999 2.999 2.999 +score HTML_ENTITY_ASCII_TINY 1.000 1.000 1.000 1.000 +score HTML_FONT_TINY_NORDNS 1.886 1.085 1.886 1.085 +score HTML_OFF_PAGE 2.601 0.977 2.601 0.977 +score HTML_SHRT_CMNT_OBFU_MANY 1.000 1.000 1.000 1.000 +score HTML_SINGLET_MANY 2.499 1.000 2.499 1.000 +score HTML_TAG_BALANCE_CENTER 2.599 2.816 2.599 2.816 +score HTML_TEXT_INVISIBLE_FONT 1.924 0.609 1.924 0.609 +score HTML_TEXT_INVISIBLE_STYLE 0.472 1.312 0.472 1.312 +score IMG_ONLY_FM_DOM_INFO 1.000 1.000 1.000 1.000 +score JH_SPAMMY_HEADERS 3.499 3.499 3.499 3.499 +score JH_SPAMMY_PATTERN01 1.000 1.000 1.000 1.000 +score JH_SPAMMY_PATTERN02 1.000 1.000 1.000 1.000 +score KHOP_HELO_FCRDNS 0.399 0.001 0.399 0.001 +score KHOP_JS_OBFUSCATION 3.099 0.001 3.099 0.001 +score LINKEDIN_IMG_NOT_RCVD_LNKN 1.000 1.000 1.000 1.000 +score LIST_PRTL_PUMPDUMP 1.000 1.000 1.000 1.000 +score LIST_PRTL_SAME_USER 1.000 1.000 1.000 1.000 +score LONGLN_LOW_CONTRAST 0.123 1.329 0.123 1.329 +score LONG_HEX_URI 2.679 1.617 2.679 1.617 +score LONG_IMG_URI 2.599 0.001 2.599 0.001 +score LONG_INVISIBLE_TEXT 2.999 2.364 2.999 2.364 +score LOTS_OF_MONEY 0.010 0.009 0.010 0.009 +score LOTTO_AGENT 1.000 1.499 1.000 1.499 +score LOTTO_DEPT 0.754 1.096 0.754 1.096 +score LUCRATIVE 1.000 1.000 1.000 1.000 +score MALF_HTML_B64 1.000 1.000 1.000 1.000 +score MALWARE_NORDNS 0.001 0.616 0.001 0.616 +score MALWARE_PASSWORD 1.000 1.000 1.000 1.000 +score MAY_BE_FORGED 1.599 0.001 1.599 0.001 +score MILLION_HUNDRED 0.440 0.391 0.440 0.391 +score MILLION_USD 1.307 0.194 1.307 0.194 +score MIMEOLE_DIRECT_TO_MX 0.001 0.001 0.001 0.001 +score MIME_NO_TEXT 1.000 1.000 1.000 1.000 +score MIXED_AREA_CASE 1.000 1.000 1.000 1.000 +score MIXED_CENTER_CASE 1.000 1.000 1.000 1.000 +score MIXED_ES 2.199 2.399 2.199 2.399 +score MIXED_FONT_CASE 1.000 1.000 1.000 1.000 +score MIXED_HREF_CASE 1.000 1.000 1.000 1.000 +score MIXED_IMG_CASE 1.957 2.999 1.957 2.999 +score MONERO_DEADLINE 1.000 1.000 1.000 1.000 +score MONERO_EXTORT_01 1.000 1.000 1.000 1.000 +score MONERO_MALWARE 1.000 1.000 1.000 1.000 +score MONERO_PAY_ME 1.000 1.000 1.000 1.000 +score MONEY_ATM_CARD 0.560 1.599 0.560 1.599 +score MONEY_FORM 0.001 0.001 0.001 0.001 +score MONEY_FORM_SHORT 2.499 0.001 2.499 0.001 +score MONEY_FRAUD_3 2.499 2.499 2.499 2.499 +score MONEY_FRAUD_5 0.001 0.001 0.001 0.001 +score MONEY_FRAUD_8 0.001 0.001 0.001 0.001 +score MONEY_FREEMAIL_REPTO 2.999 1.155 2.999 1.155 +score MONEY_FROM_41 1.000 1.000 1.000 1.000 +score MONEY_FROM_MISSP 0.001 0.001 0.001 0.001 +score MSGID_DOLLARS_URI_IMG 1.000 1.000 1.000 1.000 +score MSGID_HDR_MALF 1.000 1.000 1.000 1.000 +score MSMAIL_PRI_ABNORMAL 1.499 1.499 1.499 1.499 +score MSM_PRIO_REPTO 1.000 1.000 1.000 1.000 +score NAME_EMAIL_DIFF 1.727 0.001 1.727 0.001 +score NA_DOLLARS 1.499 1.499 1.499 1.499 +score NEWEGG_IMG_NOT_RCVD_NEGG 1.000 1.000 1.000 1.000 +score NEW_PRODUCTS 1.000 1.000 1.000 1.000 +score NICE_REPLY_A -0.438 -0.001 -0.438 -0.001 +score NORDNS_LOW_CONTRAST 0.001 0.770 0.001 0.770 +score NO_FM_NAME_IP_HOSTN 0.001 0.001 0.001 0.001 +score NSL_RCVD_FROM_USER 0.001 0.001 0.001 0.001 +score NSL_RCVD_HELO_USER 0.001 0.001 0.001 0.001 +score NUMBERONLY_BITCOIN_EXP 1.735 1.787 1.735 1.787 +score OBFU_BITCOIN 0.001 0.001 0.001 0.001 +score OBFU_TEXT_ATTACH 1.499 1.444 1.499 1.444 +score ODD_FREEM_REPTO 2.999 1.845 2.999 1.845 +score PDS_BAD_THREAD_QP_64 0.999 0.999 0.999 0.999 +score PDS_BTC_ID 0.499 0.499 0.499 0.499 +score PDS_BTC_MSGID 0.302 0.001 0.302 0.001 +score PDS_BTC_NTLD 1.000 1.000 1.000 1.000 +score PDS_DBL_URL_TNB_RUNON 1.999 1.000 1.999 1.000 +score PDS_FROM_2_EMAILS 0.714 2.460 0.714 2.460 +score PDS_HELO_SPF_FAIL 0.001 1.000 0.001 1.000 +score PDS_NAKED_TO_NUMERO 1.999 2.000 1.999 2.000 +score PDS_NO_FULL_NAME_SPOOFED_URL 0.750 0.750 0.750 0.750 +score PDS_RDNS_DYNAMIC_FP 0.001 0.001 0.001 0.001 +score PDS_SHORT_SPOOFED_URL 1.999 1.999 1.999 1.999 +score PDS_TINYSUBJ_URISHRT 1.000 1.000 1.000 1.000 +score PDS_TONAME_EQ_TOLOCAL_FREEM_FORGE 1.000 1.000 1.000 1.000 +score PHISH_AZURE_CLOUDAPP 3.500 3.500 3.500 3.500 +score PHISH_FBASEAPP 1.000 1.000 1.000 1.000 +score PHP_NOVER_MUA 1.000 1.000 1.000 1.000 +score PHP_ORIG_SCRIPT 2.001 2.036 2.001 2.036 +score PHP_SCRIPT 2.499 2.499 2.499 2.499 +score PHP_SCRIPT_MUA 1.000 1.000 1.000 1.000 +score PP_MIME_FAKE_ASCII_TEXT 0.999 0.001 0.999 0.001 +score PP_TOO_MUCH_UNICODE02 0.500 0.500 0.500 0.500 +score PP_TOO_MUCH_UNICODE05 1.000 1.000 1.000 1.000 +score PUMPDUMP 1.000 1.000 1.000 1.000 +score PUMPDUMP_MULTI 1.000 1.000 1.000 1.000 +score RAND_HEADER_LIST_SPOOF 1.000 1.000 1.000 1.000 +score RAND_HEADER_MANY 1.000 1.000 1.000 1.000 +score RAND_MKTG_HEADER 1.999 1.999 1.999 1.999 +score RATWARE_NO_RDNS 1.864 0.001 1.864 0.001 +score RCVD_DOTEDU_SHORT 1.000 1.000 1.000 1.000 +score RCVD_DOTEDU_SUSP_URI 1.000 1.000 1.000 1.000 +score RCVD_IN_MSPIKE_BL 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_H2 0.001 -0.001 0.001 -0.001 +score RCVD_IN_MSPIKE_H3 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_H4 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_H5 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_L2 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_L3 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_L4 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_L5 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_WL 0.001 0.001 0.001 0.001 +score RCVD_IN_MSPIKE_ZBI 0.001 0.001 0.001 0.001 +score RDNS_NUM_TLD_ATCHNX 1.000 1.000 1.000 1.000 +score RDNS_NUM_TLD_XM 2.681 2.999 2.681 2.999 +score READY_TO_SHIP 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_AOL 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_AOL_LOOSE 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_CNS 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_GM 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_GM_LOOSE 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_HM 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_OL 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_PM 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_QQ 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_YH 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_YH_LOOSE 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_YJ 1.000 1.000 1.000 1.000 +score REPTO_419_FRAUD_YN 1.000 1.000 1.000 1.000 +score REPTO_INFONUMSCOM 1.000 1.000 1.000 1.000 +score SCC_CANSPAM_1 2.300 0.001 2.300 0.001 +score SCC_CANSPAM_2 2.299 2.599 2.299 2.599 +score SCC_ISEMM_LID_1 1.000 1.000 1.000 1.000 +score SCC_ISEMM_LID_1A 1.000 1.000 1.000 1.000 +score SCC_ISEMM_LID_1B 1.499 1.499 1.499 1.499 +score SENDGRID_REDIR 1.499 1.068 1.499 1.068 +score SENDGRID_REDIR_PHISH 1.000 1.000 1.000 1.000 +score SEO_SUSP_NTLD 1.000 1.000 1.000 1.000 +score SERGIO_SUBJECT_VIAGRA01 2.699 2.656 2.699 2.656 +score SHOPIFY_IMG_NOT_RCVD_SFY 2.499 2.499 2.499 2.499 +score SHORTENER_SHORT_IMG 0.001 1.002 0.001 1.002 +score SHORT_IMG_SUSP_NTLD 1.000 1.000 1.000 1.000 +score SHORT_SHORTNER 1.999 1.999 1.999 1.999 +score SPOOFED_FREEMAIL 0.001 0.001 0.001 0.001 +score SPOOFED_FREEMAIL_NO_RDNS 0.001 0.001 0.001 0.001 +score SPOOFED_FREEM_REPTO 0.001 0.001 0.001 0.001 +score SPOOFED_FREEM_REPTO_CHN 0.001 1.000 0.001 1.000 +score SPOOFED_FREEM_REPTO_RUS 0.001 1.000 0.001 1.000 +score SPOOF_GMAIL_MID 1.499 0.001 1.499 0.001 +score STATIC_XPRIO_OLE 0.001 0.001 0.001 0.001 +score STOCK_TIP 1.000 1.000 1.000 1.000 +score STOX_BOUND_090909_B 0.001 0.001 0.001 0.001 +score SUBJ_ATTENTION 0.128 0.500 0.128 0.500 +score SUBJ_BRKN_WORDNUMS 1.000 1.000 1.000 1.000 +score SURBL_BLOCKED 0.001 0.001 0.001 0.001 +score SUSP_UTF8_WORD_SUBJ 1.999 1.970 1.999 1.970 +score SYSADMIN 1.000 1.000 1.000 1.000 +score TAGSTAT_IMG_NOT_RCVD_TGST 1.000 1.000 1.000 1.000 +score TARINGANET_IMG_NOT_RCVD_TN 1.000 1.000 1.000 1.000 +score THIS_AD 2.099 1.815 2.099 1.815 +score THIS_IS_ADV_SUSP_NTLD 1.000 1.000 1.000 1.000 +score TONLINE_FAKE_DKIM 1.000 1.000 1.000 1.000 +score TO_EQ_FM_DIRECT_MX 1.000 1.000 1.000 1.000 +score TO_EQ_FM_DOM_SPF_FAIL 0.001 0.001 0.001 0.001 +score TO_EQ_FM_SPF_FAIL 0.001 0.001 0.001 0.001 +score TO_IN_SUBJ 0.100 0.100 0.100 0.100 +score TO_NAME_SUBJ_NO_RDNS 0.338 1.000 0.338 1.000 +score TO_NO_BRKTS_FROM_MSSP 2.499 2.499 2.499 2.499 +score TO_NO_BRKTS_HTML_IMG 1.999 1.999 1.999 1.999 +score TO_NO_BRKTS_HTML_ONLY 1.999 1.999 1.999 1.999 +score TO_NO_BRKTS_MSFT 0.001 0.001 0.001 0.001 +score TO_NO_BRKTS_NORDNS_HTML 1.999 1.597 1.999 1.597 +score TO_NO_BRKTS_PCNT 2.500 2.499 2.500 2.499 +score TVD_PH_BODY_META 2.099 2.299 2.099 2.299 +score TVD_RCVD_SPACE_BRACKET 2.554 1.427 2.554 1.427 +score TVD_SPACE_ENCODED 1.821 0.001 1.821 0.001 +score TVD_SPACE_RATIO_MINFP 0.238 0.001 0.238 0.001 +score TW_GIBBERISH_MANY 1.000 1.000 1.000 1.000 +score UC_GIBBERISH_OBFU 1.000 1.000 1.000 1.000 +score UNDISC_FREEM 2.699 2.700 2.699 2.700 +score UNDISC_MONEY 2.899 3.099 2.899 3.099 +score UNICODE_OBFU_ASC 2.499 2.499 2.499 2.499 +score UNICODE_OBFU_ZW 1.000 1.000 1.000 1.000 +score UNSUB_GOOG_FORM 1.000 1.000 1.000 1.000 +score URI_ADOBESPARK 1.000 1.000 1.000 1.000 +score URI_AZURE_CLOUDAPP 1.000 1.000 1.000 1.000 +score URI_DASHGOVEDU 1.000 1.000 1.000 1.000 +score URI_DATA 1.000 1.000 1.000 1.000 +score URI_DOTEDU 1.999 1.278 1.999 1.278 +score URI_DOTEDU_ENTITY 1.000 1.000 1.000 1.000 +score URI_FIREBASEAPP 1.000 1.000 1.000 1.000 +score URI_GOOGLE_PROXY 1.999 1.999 1.999 1.999 +score URI_GOOG_STO_SPAMMY 3.000 3.000 3.000 3.000 +score URI_HEX_IP 1.000 1.000 1.000 1.000 +score URI_IMG_WP_REDIR 1.000 1.000 1.000 1.000 +score URI_LONG_REPEAT 1.000 1.000 1.000 1.000 +score URI_ONLY_MSGID_MALF 0.001 1.000 0.001 1.000 +score URI_OPTOUT_3LD 1.000 1.000 1.000 1.000 +score URI_PHISH 3.999 3.695 3.999 3.695 +score URI_PHP_REDIR 1.000 1.000 1.000 1.000 +score URI_TRY_3LD 1.950 0.956 1.950 0.956 +score URI_TRY_USME 1.000 1.000 1.000 1.000 +score URI_WPADMIN 1.685 2.099 1.685 2.099 +score URI_WP_DIRINDEX 1.000 1.000 1.000 1.000 +score URI_WP_HACKED 1.685 3.499 1.685 3.499 +score URI_WP_HACKED_2 2.499 2.499 2.499 2.499 +score USB_DRIVES 1.000 1.000 1.000 1.000 +score VFY_ACCT_NORDNS 2.633 2.551 2.633 2.551 +score VPS_NO_NTLD 1.000 1.000 1.000 1.000 +score WALMART_IMG_NOT_RCVD_WAL 1.000 1.000 1.000 1.000 +score WORD_INVIS 0.972 0.001 0.972 0.001 +score WORD_INVIS_MANY 2.999 2.999 2.999 2.999 +score XFER_LOTSA_MONEY 0.999 0.999 0.999 0.999 +score XM_DIGITS_ONLY 1.000 1.000 1.000 1.000 +score XM_RANDOM 1.665 0.256 1.665 0.256 +score XPRIO 0.617 0.001 0.617 0.001 +score XPRIO_SHORT_SUBJ 1.133 2.172 1.133 2.172 +score XPRIO_URL_SHORTNER 0.429 0.613 0.429 0.613 +score YOUR_DELIVERY_ADDRESS 1.000 1.000 1.000 1.000 diff --git a/resources/spamassassin/73_sandbox_manual_scores.cf b/resources/spamassassin/73_sandbox_manual_scores.cf new file mode 100644 index 00000000..f424c605 --- /dev/null +++ b/resources/spamassassin/73_sandbox_manual_scores.cf @@ -0,0 +1,121 @@ +# SpamAssassin rules file +# +# Manual override of the automatically-generated scores +# for automatically-published sandbox rules +# +# <@LICENSE> +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +########################################################################### + +require_version @@VERSION@@ + +# jhardin +# things depend on these +# score as informative just for the hits header +score LOTS_OF_MONEY 0.001 +score FILL_THIS_FORM 0.001 + +# jhardin +# reevolved Advance Fee rules +# scores are cumulative (i.e. 3 hits 2, 4 hits 3 and 2) +# Commented out if GA is scoring reasonably +#score ADVANCE_FEE_2_NEW_MONEY 0.50 +#score ADVANCE_FEE_2_NEW_FORM 0.75 +#score ADVANCE_FEE_3_NEW 0.50 +#score ADVANCE_FEE_3_NEW_MONEY 1.00 +#score ADVANCE_FEE_3_NEW_FORM 1.00 +#score ADVANCE_FEE_4_NEW 1.00 +#score ADVANCE_FEE_5_NEW 1.50 +score ADVANCE_FEE_5_NEW_MONEY 3.00 + +# jhardin +# metas using Advance Fee component rules +# Commented out if GA is scoring reasonably +#score FORM_FRAUD_3 0.50 +#score FORM_FRAUD_5 0.50 +#score MONEY_FRAUD_3 1.00 +#score MONEY_FRAUD_5 0.50 +#score MONEY_FRAUD_8 0.50 + +# jhardin +# GA scores this unreasonably high, and +# the fact that this is defined in an #ifplugin +# appears to be preventing score limiting from working +score FILL_THIS_FORM_LONG 2.00 + +# jhardin +# misc rules +# Commented out if GA is scoring reasonably +#score FROM_MISSP_MSFT 0.50 +#score TO_NO_BRKTS_DYNIP 0.50 +#score LOTTO_AGENT 0.50 + +# jhardin +# 1.000 S/O, hits only <= 6 points, but GA is not publishing it! +# perhaps because very few examples in spam corpus +# 12/24/12 GA likes it now +#score GOOGLE_DOCS_PHISH 3.00 +# similar: .990 S/O, hits primarily spam <= 5 points +# 01/07/13 GA likes it now +#score EMAIL_URI_PHISH 2.50 +# Reliable but not widespread (low corpus count, ahead of the curve?), boost the score +score PHISH_AZURE_CLOUDAPP 3.50 +score URI_GOOG_STO_SPAMMY 3.50 + +# jhardin +# double-extension file attachments, low corpus count +score PHISH_ATTACH 3.50 +score MALW_ATTACH 3.50 + +# hege +# FPs reported [bug 6417], GA assigning 3+ points +# reduce score until that's resolved +# score HK_FAKENAME_MICROSOFT 2.50 +# RULE DISABLED IN 20_hk.cf + +# jhardin for mmartinec +# Lots of hate; score as informative hammy, may override locally +score RP_MATCHES_RCVD -0.001 + +# until rule or rescoring issues sorted, hits 20%+ ham +# too problematic, disabled entirely +#score STYLE_GIBBERISH 0.1 + +# jhardin +# Limit some network scores until rule changes can be evaluated by weekly net masscheck +# Dangit, relative scores are broken - see bug#7721 +#score FROM_IN_TO_AND_SUBJ (0) 0.001 (0) 0.001 +#score OBFU_TEXT_ATTACH (0) 0.001 (0) 0.001 +#score MIME_NO_TEXT (0) 0.001 (0) 0.001 +#score AD_PREFS (0) 0.001 (0) 0.001 +score AD_PREFS 0.250 +#score URI_WP_HACKED_2 (0) 0.001 (0) 0.001 +#score STYLE_GIBBERISH (0) 0.001 (0) 0.001 +#score UC_GIBBERISH_OBFU (0) 0.001 (0) 0.001 +#score LUCRATIVE (0) 0.001 (0) 0.001 +#score HEXHASH_WORD (0) 0.001 (0) 0.001 +#score FROM_WORDY (0) 0.001 (0) 0.001 +#score AC_HTML_NONSENSE_TAGS (0) 0.001 (0) 0.001 +#score LONG_HEX_URI (0) 0.001 (0) 0.001 +#score FROM_PAYPAL_SPOOF (0) 0.001 (0) 0.001 + + +# jhardin +# Don't joe-job a SA dev's wife +score ADULT_DATING_COMPANY 20.000 + diff --git a/resources/spamassassin/Mail-SpamAssassin-rules-4.0.0.r1905950.tgz b/resources/spamassassin/Mail-SpamAssassin-rules-4.0.0.r1905950.tgz new file mode 100644 index 00000000..69e2e642 Binary files /dev/null and b/resources/spamassassin/Mail-SpamAssassin-rules-4.0.0.r1905950.tgz differ diff --git a/resources/spamassassin/STATISTICS-set0-72_scores.cf.txt b/resources/spamassassin/STATISTICS-set0-72_scores.cf.txt new file mode 100644 index 00000000..4ee2b542 --- /dev/null +++ b/resources/spamassassin/STATISTICS-set0-72_scores.cf.txt @@ -0,0 +1,40 @@ +##### WITH NEW RULES AND SCORES ##### + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 295376 69.870% (99.568% of non-spam corpus) +# Correctly spam: 90325 21.366% (71.634% of spam corpus) +# False positives: 1282 0.303% (0.432% of nonspam, 19065 weighted) +# False negatives: 35767 8.461% (28.366% of spam, 50278 weighted) +# Average score for spam: 8.9 nonspam: 0.7 +# Average for false-pos: 7.0 false-neg: 1.4 +# TOTAL: 422750 100.00% + +Reading scores from "tmprules"... +Reading per-message hit stat logs and scores... + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 36853 99.58% +# Correctly spam: 11338 71.64% +# False positives: 155 0.42% +# False negatives: 4489 28.36% +# TCR(l=50): 1.293161 SpamRecall: 71.637% SpamPrec: 98.651% + +##### WITHOUT NEW RULES AND SCORES ##### +Reading scores from "../rules-base"... +Reading per-message hit stat logs and scores... + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 289677 97.65% +# Correctly spam: 73447 58.25% +# False positives: 6981 2.35% +# False negatives: 52645 41.75% +# TCR(l=50): 0.313900 SpamRecall: 58.249% SpamPrec: 91.320% +Reading scores from "../rules-base"... +Reading per-message hit stat logs and scores... + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 36132 97.63% +# Correctly spam: 9229 58.31% +# False positives: 876 2.37% +# False negatives: 6598 41.69% +# TCR(l=50): 0.314040 SpamRecall: 58.312% SpamPrec: 91.331% diff --git a/resources/spamassassin/STATISTICS-set1-72_scores.cf.txt b/resources/spamassassin/STATISTICS-set1-72_scores.cf.txt new file mode 100644 index 00000000..3ae102a6 --- /dev/null +++ b/resources/spamassassin/STATISTICS-set1-72_scores.cf.txt @@ -0,0 +1,40 @@ +##### WITH NEW RULES AND SCORES ##### + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 297244 68.072% (99.304% of non-spam corpus) +# Correctly spam: 102975 23.582% (74.980% of spam corpus) +# False positives: 2082 0.477% (0.696% of nonspam, 82501 weighted) +# False negatives: 34362 7.869% (25.020% of spam, 59356 weighted) +# Average score for spam: 13.0 nonspam: -0.0 +# Average for false-pos: 8.6 false-neg: 1.7 +# TOTAL: 436663 100.00% + +Reading scores from "tmprules"... +Reading per-message hit stat logs and scores... + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 37058 99.18% +# Correctly spam: 13021 75.69% +# False positives: 307 0.82% +# False negatives: 4182 24.31% +# TCR(l=50): 0.880760 SpamRecall: 75.690% SpamPrec: 97.697% + +##### WITHOUT NEW RULES AND SCORES ##### +Reading scores from "../rules-base"... +Reading per-message hit stat logs and scores... + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 297291 99.32% +# Correctly spam: 88670 64.56% +# False positives: 2035 0.68% +# False negatives: 48667 35.44% +# TCR(l=50): 0.913042 SpamRecall: 64.564% SpamPrec: 97.756% +Reading scores from "../rules-base"... +Reading per-message hit stat logs and scores... + +# SUMMARY for threshold 5.0: +# Correctly non-spam: 37082 99.24% +# Correctly spam: 11166 64.91% +# False positives: 283 0.76% +# False negatives: 6037 35.09% +# TCR(l=50): 0.852182 SpamRecall: 64.907% SpamPrec: 97.528% diff --git a/resources/spamassassin/STATISTICS-set2-72_scores.cf.txt b/resources/spamassassin/STATISTICS-set2-72_scores.cf.txt new file mode 100644 index 00000000..e69de29b diff --git a/resources/spamassassin/STATISTICS-set3-72_scores.cf.txt b/resources/spamassassin/STATISTICS-set3-72_scores.cf.txt new file mode 100644 index 00000000..e69de29b diff --git a/resources/spamassassin/languages b/resources/spamassassin/languages new file mode 100644 index 00000000..b3c4a952 Binary files /dev/null and b/resources/spamassassin/languages differ diff --git a/resources/spamassassin/local.cf b/resources/spamassassin/local.cf new file mode 100644 index 00000000..fb1d1111 --- /dev/null +++ b/resources/spamassassin/local.cf @@ -0,0 +1,112 @@ +# This is the right place to customize your installation of SpamAssassin. +# +# See 'perldoc Mail::SpamAssassin::Conf' for details of what can be +# tweaked. +# +# Only a small subset of options are listed below +# +########################################################################### + +# A 'contact address' users should contact for more info. (replaces +# _CONTACTADDRESS_ in the report template) +# report_contact youremailaddress@domain.tld + + +# Add *****SPAM***** to the Subject header of spam e-mails +# +# rewrite_header Subject *****SPAM***** + + +# Save spam messages as a message/rfc822 MIME attachment instead of +# modifying the original message (0: off, 2: use text/plain instead) +# +# report_safe 1 + + +# Set which networks or hosts are considered 'trusted' by your mail +# server (i.e. not spammers) +# +# trusted_networks 212.17.35. + + +# Set file-locking method (flock is not safe over NFS, but is faster) +# +# lock_method flock + + +# Set the threshold at which a message is considered spam (default: 5.0) +# +# required_score 5.0 + + +# Use Bayesian classifier (default: 1) +# +# use_bayes 1 + + +# Bayesian classifier auto-learning (default: 1) +# +# bayes_auto_learn 1 + + +# Set headers which may provide inappropriate cues to the Bayesian +# classifier +# +# bayes_ignore_header X-Bogosity +# bayes_ignore_header X-Spam-Flag +# bayes_ignore_header X-Spam-Status + + +# Whether to decode non- UTF-8 and non-ASCII textual parts and recode +# them to UTF-8 before the text is given over to rules processing. +# +# normalize_charset 1 + +# Textual body scan limit (default: 50000) +# +# Amount of data per email text/* mimepart, that will be run through body +# rules. This enables safer and faster scanning of large messages, +# perhaps having very large textual attachments. There should be no need +# to change this well tested default. +# +# body_part_scan_size 50000 + +# Textual rawbody data scan limit (default: 500000) +# +# Amount of data per email text/* mimepart, that will be run through +# rawbody rules. +# +# rawbody_part_scan_size 500000 + +# Some shortcircuiting, if the plugin is enabled +# +ifplugin Mail::SpamAssassin::Plugin::Shortcircuit +# +# default: strongly-welcomelisted mails are *really* welcomelisted now, if +# the shortcircuiting plugin is active, causing early exit to save CPU +# load. Uncomment to turn this on +# +# SpamAssassin tries hard not to launch DNS queries before priority -100. +# If you want to shortcircuit without launching unneeded queries, make +# sure such rule priority is below -100. These examples are already: +# +# shortcircuit USER_IN_WELCOMELIST on +# shortcircuit USER_IN_DEF_WELCOMELIST on +# shortcircuit USER_IN_ALL_SPAM_TO on + +# the opposite; blocklisted mails can also save CPU +# +# shortcircuit USER_IN_BLOCKLIST on +# shortcircuit USER_IN_BLOCKLIST_TO on + +# if you have taken the time to correctly specify your "trusted_networks", +# this is another good way to save CPU +# +# shortcircuit ALL_TRUSTED on + +# and a well-trained bayes DB can save running rules, too +# +# shortcircuit BAYES_99 spam +# shortcircuit BAYES_00 ham + +endif # Mail::SpamAssassin::Plugin::Shortcircuit diff --git a/resources/spamassassin/regression_tests.cf b/resources/spamassassin/regression_tests.cf new file mode 100644 index 00000000..872aaafe --- /dev/null +++ b/resources/spamassassin/regression_tests.cf @@ -0,0 +1,62 @@ +# SpamAssassin rules file: regression tests +# +# This file contains tests performed on `make test`. It should not be +# distributed. +# +# <@LICENSE> +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +########################################################################### + +test DEAR_SOMETHING ok Dear IT professional, +test DEAR_SOMETHING ok Dear Internet Investor: +test DEAR_FRIEND ok Dear friend, +test DEAR_FRIEND fail Dear Mr. Ithacus, + +test FROM_STARTS_WITH_NUMS ok 12345678matt@sergeant.org +test FROM_STARTS_WITH_NUMS fail matt@sergeant.org +test FORGED_YAHOO_RCVD fail by mf1.lng.yahoo.com (8.11.1/8.11.1) id g3SDfPH19426 +test NUMERIC_HTTP_ADDR ok http://123456789/foo/bar + +test US_DOLLARS_3 fail $-$NFbMF$K!"A49q$+$iLd$$9g$o$;$,;&E~$7$F$$$^$9!# +test US_DOLLARS_3 ok OF US$75,000,000.00 ( SEVENTYFIVE +test US_DOLLARS_3 ok DOLLAR(USD$30,000,000,00.) +test US_DOLLARS_3 ok ($21,500,000.) +test US_DOLLARS_3 ok ($ 152,000.000.00) + +# note: have to use "." instead of "#", as it's the comment char + +test TRACKER_ID ok 2174Hzdm0-105YUqT8863DiDg0-616mqbE4931HEBc0-732qBHd6314l52 +test TRACKER_ID ok ofsknxxdqgtgqvsoiytkivajvtj +test TRACKER_ID fail +test TRACKER_ID fail Donau-Dampfschifffahrts-Kapitaen + +test __OBFUSCATING_COMMENT_A ok This is a test +test __OBFUSCATING_COMMENT_A fail Not a here +test __OBFUSCATING_COMMENT_A fail or here +test __OBFUSCATING_COMMENT_A fail This I hope + +test HIDE_WIN_STATUS ok with any questions. + + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.2 (SunOS) + +mQILBEOnbDQBEADBfda+hU8cGXD/2WYrIHsZ5CmvC2eCYKgQ87W706tzwmxoZWQS +JfnRpkZnBqS5WDhXhNBOhk9CgF5/e9yHnDQCusNYfRstKd+t0XTFvq30/tacrJNe +67zgq+DtWqIK9C7akfElc+2M5NkX6mF4cjaMXZoW17ltPy0XSSeirf584nvK3pXf +oEFLYQ/0AUV9EBpo9+i2DkMUd8d5tz7A6O5foB3ijYPzIcVtVJ1eyCg6gO1I4cIA +YbIZCH0WIVx5MQjydfKyCR4D7VFPpZgwcZ1PmyZSsy3lrigGVvYEoUS2fWTt2jUO +pB3wg5pgzuu9hN5CpChZGvq65t4PGtAeShnBkddIH4l+iDC6sAc6W06KidSaUCW1 +BKvNMa39lyEkO4bfLblZRjoZbj7Tjq3wQV/PLpPyKDa8ZZ88GfWaeRDUNRgZG6Qq +e6UKlFGfrw2RXOImUje7Sjy/eG4Ud/BOeGkV913yWBm9CHsPNtaVDK+iQI6vkAWS +3QkiPjBkXGTZFHsUx9/i3k5Iga6d4Gq2cBIVBur3sDxjKuuSazLwA9OAybpzQe2s +PvTzbGc/f1P7plT++HBFlBHwFtl/v68Q8pkbMWlEc5M9nYJ6yXHATHZzFfThxBwt +OYfF25XGaclUMkOMX++RiRkmjaEaT7Whv5aPbeb3+H3v6Omjvnebge24lQAGKbQ/ +dXBkYXRlcy5zcGFtYXNzYXNzaW4ub3JnIFNpZ25pbmcgS2V5IDxyZWxlYXNlQHNw +YW1hc3Nhc3Npbi5vcmc+iQI2BBMBAgAgBQJDp2w0AhsDBgsJCAcDAgQVAggDBBYC +AwECHgECF4AACgkQQFamGlJE7EVkfg//ZjBQ6UXDizX9UPsEmogWXIqbBsyP5DJH +uToaFa6OzCbOJqcYnXNfOjovYdDOTje+x3ZEkwbx+y6MSfhmDuHPDPqBU7hXenxx +oRktC68mJasKo0wXym2YfyWFnhSZMlXXFQ9We48zNGcVRckzaxLzM67BFJuRUfOM +EV6Lf3HxMvoUK3/Xzq9YPEq2sqFO1Eu+qPC3nq726Tj/aYBBFHgHmbjDrZTaQNyV +fHvEjDzPcDRjlJI+vZw1UEuXG+BKATPpiT7U7I1OGLDa2ExDIxh0+eJnsmA3YyHG +VweE7nDN2GmkXMVfa5vXHH49Ae9Ee8jIIRipfgMgZWnkZ0XYDvLj2ueH0Ixu4o9R +D2zJIwqzRh1sytG+1YOfHrOMUCplImJaY/ARgOM324ZdBvhkgIi1XvT7Sy/ZmGWd +DKFo+GjX0r2cujR8Pd4i7VlKsF9wRypk+n/aupXiaz5GY44EIVbnweyS5IlCNrwn +4UtqcB9/9uk1tmUNIcC5xjbq5ud/Y+iMIqCKCH0C9WUwSNSdsg+K+9xoZuvlaXY0 +JeXWNcDdq+tMir+x+/o0U4ENVYBkSFesnotmHwN6jZj4lSMRmvcFHPBljXqLqzM+ +y5wZxnCo1N7T+erZaI7BUrpJYm8JxcJ2VCWV0JFoO1Ec//B6XYB0pckbRuSTX/Zw +pKEkNqOdmjm5AgsEQ6dsigEQAKvdggbwqJgfDbRE2Lcy2gsn4j7haqu3IVBbyUDn +kGuuDuEtSeoRjCZXEb5DaKibIpEy5vzvRGvCFFkrBs4KXk/uamkgCpGnQZFnoz/S +rNZ8U7+e1pecEePpIkhQyafUKox9+p43UVoq4UybdPRDvE9SmQ1qaNUhyQY2FP9S +WT1a63u5GA73aH4puGO0BuZ9R3MNaDYZe/MOlRRjmlAsbY4oqWOudlNVaZ71EV3O +FFmOH4pnpxdO0X0l6sF6nvqvO5/gdZ3dI5iqrJjUneVgVOmPkREq7tQ5qHS/2pny +rDrH8NZCDNT5TXciBxBrt53bxxL/V/HWaolmtJi8gK82uXt8YlmT6zuEsofufDmu +P/HMDZ+BhGI+ggNzY2AVwERTRD6ecHDOI3iIuCP4Ck26YNHRCLyocL3CSlIpjQPu +tb3qfdAcqKLJ/fVyLtGkXr24crel6IeJY7/AGjYBrfh47DWnK7Xds8bAqJ8VCjOc +/q1usFTHgGkYocvtv0gmcjbu8YypzuG8HxOg9Yk9qRLQgg1fNhzXE2lqEPyMlBfj +eLmMNRvKP70fH8CK8adinPIegaRrS6gZ/iIdv8+YV+1rlEt28qzzGJxnmzUEmW6X +Xj44u91umg9WOsLxTOCQWdjGHonytHqj/xIsf45N2JIGLhU0lF04hYfEo5p65AyM +PpYhAAYpiQIfBBgBAgAJBQJDp2yKAhsCAAoJEEBWphpSROxFungP/iWKe7o8szOz +VmXkj89xDVFZ69nthVKkbgSYIZYQC+QLF8P1MWRnNWO/8TY+XsaCT3SrqxDFQ/R/ +9mlAPGUM1ySVihOPmP/DPiOlWLCsc0mb6OzYF2olcOR33s05MqvJlqXSmIrdB+hI +KkC7G5byZ+XZwPXVj4XlxIEOzs18+0YJqy0IPZPXTiMet4k2KyWyWkJpJYUCb19G +R6QC8hZQD97EYTbkbr5Ss26jjY/9AqLofW5F1/98pLDo+ron7pI2k8Ymn5DngEsa +XoGsQuyvPfTAjS4p9q/XwExJcX3gvQesdw18mpoSaGAOgDISolBPRqpHpy7v7vuw +3UMnsefKOX3F0Rossevw+c2/JCulnGmJDlgz6nHSR6FhHsbrDKF8oBeYPfGW/Kjw +NvzB1i9yubAMrsTQVu1Q8e5LsnL/MNYKb6oEJbBywdeHxBkehGWFXVdSoFvVSih/ +VNqX9f7jlybpLZW/n8cQ2r1ax19v7FleO/xSGvkYm7B1+4BW0mjy6A5dta5+e5WG +D5R06Uya3/xRAPGdmV6t4Mw8fFsuyCvs+vC73PR3+eS1UvCYsDpcQD8KpVBnsHaA +duWRKKhjuFL0vdOWAr25tFOTKAj5Ywas47PBukO0isov2WBCA1rVqOr6FUvdP76y +mqHv/0E6/vnTLxFoNsu4Ce42nAQ/A/jRiQQ+BBgBAgAJAhsCBQJHhbheAinBXSAE +GQECAAYFAkOnbIoACgkQbFU5eCT0NM68MQ/8DvYqxRm3vP0Gwnr+63kzET8S+6vf +gxOghnU+eMlqUeUu/ajqnVDMzoAIRDw9QgQc9ZZoklOSJQwOuloAbdpL4TwQ2XfJ +MLU60JkZWnEOXJwClb0qG1GqtcBPbMEUPfZcQfphdRL3jpWZlaexFiJRSD+A0riw +7q3NZKPDt4FrF7F3GY9krFy+P0nRt5f462DeDhCYZgguBQH+oGtjc5Hx+kOVWDsS +txo5xkt4/0DG50ZklPkTlCohmJwRLACy+NswdQ9q83eWAhzKOPgkal7xF6a+LyE+ +ytVYy2EgEU74r2gVw5iizy92FDj//Z2QAUyf/c4BMuAhvfwVIHd8n2DPHvpMP15L +6fwoymh0OjzmhwK94Z2u1YqNC1CK27/hfB6okQ/Tct7/Ik61dBjtiYdUC9tTA5Ze +W8X5ouSmttS1QFixx+Z4hiXV7Qj12lgVKuJohjrVshfcbVzTHljjAo3YkOZIHIoA +IJTUMRNzTIx9k4hrPVbxbVQhKjKTwFNtBuxvmptGTcLEIv9THpqlq8jkcStJ2Zrd +hhofPCWRT/Kzo+WE+Kgefv88T5Li7Ku12U/UpiK85+6nRspXj3rnkfDOUbLZjGM+ +1NET0xQTPuyxN6CXF7MMxfGCpszCudYxMANDQqNXu9brcPN/+EIxGRjqin4E7q+h +kYUaY7Ki8mXtJ8cJEEBWphpSROxFktcQALWQv996bFq1iFcGuQ0ITxNDlOWCsses +bgEM5zR10DH+6s2bXEO8xyDHQJtrvdCPetRDosnuOToBMnGMXTYVytnWzwwAzwq1 +YM+bGAeTHaIX+2UmxwFyX4GMOdqsNB+xDZ8pmRKjamJSgUQt6e18YpZlg1Y4QkxS +Vptq7OZBjiKeLUhLhGJ6GWgEIedLcoCtFzKCfz3zwn0Oxl+1EnVu8yqN+quWTf8P +7EZn+0ztqZY059BrcK2jmOyXvtOZBcAHXCUknh/uPHwAJV2WFWSNid2kNiLOrV+J +3eLTs5sF9wNhxWRhl6/10cwTzjy0Onv5cJh2tjdwksigMRMwz4c839zXORni/tnY ++IY22kNTKu84gB8rBuqUq8MQXNdS3bbROwwNUzpC0D1C1z1fBvyXDL1EwJdz70Wc +2m/Sw6tIid5g98+XMW+Ibt43Jk2XbK71JLhbVbePbAcHVh/UXEtnjhRfX7oyWlwS +a+lkKMiJd/6CQ6bvYsgklE7uEzTpRskpkkOcCk1O+8jfl+DsDwKrvVaNu8tpx45k +TtV4JDA6iEHKakD/zZdVTR79W2CFqBvRfRikc5INOl1OfMQ4ODmjkMl3yI9wrHwS +SQQxdq2XsS7xbU9HDFBEguQDu0rfzILZ9DuKIVHyr/CsRoJ5joj+JvKaUQC81ywQ +aB8EKy5bg4U6 +=IbYW +-----END PGP PUBLIC KEY BLOCK----- diff --git a/resources/spamassassin/user_prefs.template b/resources/spamassassin/user_prefs.template new file mode 100644 index 00000000..74ed3b4f --- /dev/null +++ b/resources/spamassassin/user_prefs.template @@ -0,0 +1,43 @@ +# SpamAssassin user preferences file. See 'perldoc Mail::SpamAssassin::Conf' +# for details of what can be tweaked. +#* +#* Note: this file is not read by SpamAssassin until copied into the user +#* directory. At runtime, if a user has no preferences in their home directory +#* already, it will be copied for them, allowing them to perform personalised +#* customisation. If you want to make changes to the site-wide defaults, +#* create a file in /etc/spamassassin or /etc/mail/spamassassin instead. +########################################################################### + +# How many points before a mail is considered spam. +# required_score 5 + +# Welcomelist and blocklist addresses are now file-glob-style patterns, so +# "friend@somewhere.com", "*@isp.com", or "*.domain.net" will all work. +# welcomelist_from someone@somewhere.com +# welcomelist_to someone@mydomain.com + +# Add your own customised scores for some tests below. The default scores are +# read from the installed spamassassin rules files, but you can override them +# here. To see the list of tests and their default scores, go to +# https://spamassassin.apache.org/tests.html . +# +# score SYMBOLIC_TEST_NAME n.nn + +# Speakers of Asian languages, like Chinese, Japanese and Korean, will almost +# definitely want to uncomment the following lines. They will switch off some +# rules that detect 8-bit characters, which commonly trigger on mails using CJK +# character sets, or that assume a western-style charset is in use. +# +# score HTML_COMMENT_8BITS 0 +# score UPPERCASE_25_50 0 +# score UPPERCASE_50_75 0 +# score UPPERCASE_75_100 0 +# score OBSCURED_EMAIL 0 + +# Speakers of any language that uses non-English, accented characters may wish +# to uncomment the following lines. They turn off rules that fire on +# misformatted messages generated by common mail apps in contravention of the +# email RFCs. + +# score SUBJ_ILLEGAL_CHARS 0 +