Settings hot reloading - All tests passing

This commit is contained in:
mdecimus 2024-03-27 11:35:02 +01:00
parent 170ff38d1f
commit 37eb6483ca
51 changed files with 8541 additions and 8317 deletions

1
Cargo.lock generated
View file

@ -4686,6 +4686,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"h2 0.4.2",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",

View file

@ -13,7 +13,7 @@ resolver = "2"
[dependencies]
jmap-client = { version = "0.3", features = ["async"] }
mail-parser = { version = "0.9", features = ["full_encoding", "serde_support", "ludicrous_mode"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots"]}
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
tokio = { version = "1.23", features = ["full"] }
num_cpus = "1.13.1"
clap = { version = "4.1.6", features = ["derive"] }

View file

@ -29,7 +29,7 @@ tokio = { version = "1.23", features = ["net", "macros"] }
tokio-rustls = { version = "0.25.0"}
futures = "0.3"
rcgen = "0.12"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots"]}
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
serde = { version = "1.0", features = ["derive"]}
serde_json = "1.0"
base64 = "0.22"

View file

@ -11,7 +11,7 @@ readme = "README.md"
resolver = "2"
[dependencies]
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "blocking"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "blocking", "http2"] }
rpassword = "7.0"
indicatif = "0.17.0"
dialoguer = "0.11"

View file

@ -37,7 +37,7 @@ p256 = { version = "0.13", features = ["ecdh"] }
hkdf = "0.12.3"
sha1 = "0.10"
sha2 = "0.10"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots"]}
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
tokio-tungstenite = "0.21"
tungstenite = "0.21"
chrono = "0.4"

View file

@ -46,7 +46,7 @@ blake3 = "1.3"
lru-cache = "0.1.2"
rand = "0.8.5"
x509-parser = "0.16.0"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "blocking"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "blocking", "http2"] }
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
num_cpus = "1.15.0"

View file

@ -262,7 +262,7 @@ impl Message {
.unwrap_or_else(|| String::from("MAILER-DAEMON@localhost"));
let reporting_mta = core
.core
.eval_if(&config.hostname, self)
.eval_if(&core.core.smtp.report.submitter, self)
.await
.unwrap_or_else(|| String::from("localhost"));

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2023 Stalwart Labs Ltd.
*
* This file is part of the Stalwart Mail Server.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* in the LICENSE file at the top-level directory of this distribution.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can be released from the requirements of the AGPLv3 license by
* purchasing a commercial license. Please contact licensing@stalw.art
* for more details.
*/
use ahash::AHashMap;
use utils::{config::Config, glob::GlobPattern};
use crate::{LookupStore, Stores, Value};
#[derive(Debug, Default)]
pub struct MemoryStore {
entries: AHashMap<String, Value<'static>>,
globs: Vec<(GlobPattern, Value<'static>)>,
}
impl MemoryStore {
pub fn get(&self, id: &str) -> Option<&Value<'static>> {
self.entries.get(id).or_else(|| {
self.globs
.iter()
.find_map(|(pattern, value)| pattern.matches(id).then_some(value))
})
}
}
pub fn parse_memory_stores(config: &mut Config, stores: &mut Stores) {
let mut lookups = AHashMap::new();
let mut errors = Vec::new();
for (key, value) in &config.keys {
if let Some(key) = key.strip_prefix("lookup.") {
if let Some((id, key)) = key
.split_once('.')
.filter(|(id, key)| !id.is_empty() && !key.is_empty())
{
// Detect if the key is a glob pattern
let mut last_ch = '\0';
let mut has_escape = false;
let mut is_glob = false;
for ch in key.chars() {
match ch {
'\\' => {
has_escape = true;
}
'*' | '?' if last_ch != '\\' => {
is_glob = true;
}
_ => {}
}
last_ch = ch;
}
// Detect value type
let value = if !value.is_empty() {
let mut has_integers = false;
let mut has_floats = false;
let mut has_others = false;
for (pos, ch) in value.as_bytes().iter().enumerate() {
match ch {
b'.' if !has_floats && has_integers => {
has_floats = true;
}
b'0'..=b'9' => {
has_integers = true;
}
b'-' if pos == 0 && value.len() > 1 => {}
_ => {
has_others = true;
}
}
}
if has_others {
Value::Text(value.to_string().into())
} else if has_floats {
value
.parse()
.map(Value::Float)
.unwrap_or_else(|_| Value::Text(value.to_string().into()))
} else {
value
.parse()
.map(Value::Integer)
.unwrap_or_else(|_| Value::Text(value.to_string().into()))
}
} else {
Value::Text("".into())
};
// Add entry
let store = lookups
.entry(id.to_string())
.or_insert_with(MemoryStore::default);
if is_glob {
store.globs.push((GlobPattern::compile(key, false), value));
} else {
store.entries.insert(
if has_escape {
key.replace('\\', "")
} else {
key.to_string()
},
value,
);
}
} else {
errors.push(key.to_string());
}
} else if !lookups.is_empty() {
break;
}
}
for error in errors {
config.new_parse_error(error, "Invalid lookup key format");
}
for (id, store) in lookups {
stores
.lookup_stores
.insert(id, LookupStore::Memory(store.into()));
}
}

View file

@ -26,6 +26,7 @@ pub mod elastic;
#[cfg(feature = "foundation")]
pub mod foundationdb;
pub mod fs;
pub mod memory;
#[cfg(feature = "mysql")]
pub mod mysql;
#[cfg(feature = "postgres")]

View file

@ -26,7 +26,7 @@ use std::sync::Arc;
use utils::config::{cron::SimpleCron, Config};
use crate::{
backend::fs::FsStore,
backend::{fs::FsStore, memory::parse_memory_stores},
write::purge::{PurgeSchedule, PurgeStore},
BlobStore, CompressionAlgo, FtsStore, LookupStore, QueryStore, Store, Stores,
};
@ -285,6 +285,9 @@ impl Stores {
}
}
// Parse memory stores
parse_memory_stores(config, &mut stores);
stores
}
}

View file

@ -88,6 +88,9 @@ impl LookupStore {
)
.await
.map(|_| ()),
LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support key_set".into(),
)),
}
}
@ -126,7 +129,7 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.key_incr(key, value, expires).await,
LookupStore::Query(_) => Err(crate::Error::InternalError(
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support counter_incr".into(),
)),
}
@ -144,7 +147,7 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.key_delete(key).await,
LookupStore::Query(_) => Err(crate::Error::InternalError(
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support key_set".into(),
)),
}
@ -162,7 +165,7 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.key_delete(key).await,
LookupStore::Query(_) => Err(crate::Error::InternalError(
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support key_set".into(),
)),
}
@ -192,6 +195,9 @@ impl LookupStore {
row.and_then(|row| row.values.into_iter().next())
.map(|value| T::from(value))
}),
LookupStore::Memory(store) => Ok(store
.get(std::str::from_utf8(&key).unwrap_or_default())
.map(|value| T::from(value.clone()))),
}
}
@ -206,7 +212,7 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(store) => store.counter_get(key).await,
LookupStore::Query(_) => Err(crate::Error::InternalError(
LookupStore::Query(_) | LookupStore::Memory(_) => Err(crate::Error::InternalError(
"This store does not support counter_get".into(),
)),
}
@ -230,6 +236,9 @@ impl LookupStore {
)
.await
.map(|row| row.is_some()),
LookupStore::Memory(store) => Ok(store
.get(std::str::from_utf8(&key).unwrap_or_default())
.is_some()),
}
}
@ -338,7 +347,7 @@ impl LookupStore {
}
#[cfg(feature = "redis")]
LookupStore::Redis(_) => {}
LookupStore::Query(_) => {}
LookupStore::Query(_) | LookupStore::Memory(_) => {}
}
Ok(())

View file

@ -32,7 +32,7 @@ pub mod write;
pub use ahash;
use ahash::AHashMap;
use backend::fs::FsStore;
use backend::{fs::FsStore, memory::MemoryStore};
pub use blake3;
pub use parking_lot;
pub use rand;
@ -242,6 +242,7 @@ pub enum LookupStore {
Query(Arc<QueryStore>),
#[cfg(feature = "redis")]
Redis(Arc<RedisStore>),
Memory(Arc<MemoryStore>),
}
pub struct QueryStore {

View file

@ -24,7 +24,7 @@ ring = { version = "0.17" }
base64 = "0.21"
serde_json = "1.0"
rcgen = "0.12"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots"]}
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
x509-parser = "0.16.0"
pem = "3.0"
parking_lot = "0.12"

127
crates/utils/src/glob.rs Normal file
View file

@ -0,0 +1,127 @@
/*
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
*
* This file is part of the Stalwart Sieve Interpreter.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* in the LICENSE file at the top-level directory of this distribution.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can be released from the requirements of the AGPLv3 license by
* purchasing a commercial license. Please contact licensing@stalw.art
* for more details.
*/
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GlobPattern {
pattern: Vec<PatternChar>,
to_lower: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PatternChar {
WildcardMany { num: usize, match_pos: usize },
WildcardSingle { match_pos: usize },
Char { char: char, match_pos: usize },
}
impl GlobPattern {
pub fn compile(pattern: &str, to_lower: bool) -> Self {
let mut chars = Vec::new();
let mut is_escaped = false;
let mut str = pattern.chars().peekable();
while let Some(char) = str.next() {
match char {
'*' if !is_escaped => {
let mut num = 1;
while let Some('*') = str.peek() {
num += 1;
str.next();
}
chars.push(PatternChar::WildcardMany { num, match_pos: 0 });
}
'?' if !is_escaped => {
chars.push(PatternChar::WildcardSingle { match_pos: 0 });
}
'\\' if !is_escaped => {
is_escaped = true;
continue;
}
_ => {
if is_escaped {
is_escaped = false;
}
if to_lower && char.is_uppercase() {
for char in char.to_lowercase() {
chars.push(PatternChar::Char { char, match_pos: 0 });
}
} else {
chars.push(PatternChar::Char { char, match_pos: 0 });
}
}
}
}
GlobPattern {
pattern: chars,
to_lower,
}
}
// Credits: Algorithm ported from https://research.swtch.com/glob
pub fn matches(&self, value: &str) -> bool {
let value = if self.to_lower {
value.to_lowercase().chars().collect::<Vec<_>>()
} else {
value.chars().collect::<Vec<_>>()
};
let mut px = 0;
let mut nx = 0;
let mut next_px = 0;
let mut next_nx = 0;
while px < self.pattern.len() || nx < value.len() {
match self.pattern.get(px) {
Some(PatternChar::Char { char, .. }) => {
if matches!(value.get(nx), Some(nc) if nc == char ) {
px += 1;
nx += 1;
continue;
}
}
Some(PatternChar::WildcardSingle { .. }) => {
if nx < value.len() {
px += 1;
nx += 1;
continue;
}
}
Some(PatternChar::WildcardMany { .. }) => {
next_px = px;
next_nx = nx + 1;
px += 1;
continue;
}
_ => (),
}
if 0 < next_nx && next_nx <= value.len() {
px = next_px;
nx = next_nx;
continue;
}
return false;
}
true
}
}

View file

@ -25,6 +25,7 @@ use std::sync::Arc;
pub mod codec;
pub mod config;
pub mod glob;
pub mod lru_cache;
pub mod map;
pub mod snowflake;

View file

@ -3,7 +3,7 @@
#############################################
[report]
#submitter = "%{HOST}%"
#submitter = "'%{HOST}%'"
[report.analysis]
addresses = ["dmarc@*", "abuse@*", "postmaster@*"]

View file

@ -27,66 +27,6 @@ reject = 0
directory = ""
lookup = ""
[store."spam/free-domains"]
type = "memory"
format = "glob"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/domains_free.list",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/domains_free.list"]
[store."spam/disposable-domains"]
type = "memory"
format = "glob"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/domains_disposable.list",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/domains_disposable.list"]
[store."spam/redirectors"]
type = "memory"
format = "glob"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/url_redirectors.list",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/url_redirectors.list"]
[store."spam/domains-allow"]
type = "memory"
format = "glob"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/allow_domains.list",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/allow_domains.list"]
[store."spam/dmarc-allow"]
type = "memory"
format = "glob"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/allow_dmarc.list",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/allow_dmarc.list"]
[store."spam/spf-dkim-allow"]
type = "memory"
format = "glob"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/allow_spf_dkim.list",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/allow_spf_dkim.list"]
[store."spam/mime-types"]
type = "memory"
format = "map"
comment = '#'
values = ["https://get.stalw.art/resources/config/spamfilter/maps/mime_types.map",
"file+fallback://%{BASE_PATH}%/etc/spamfilter/maps/mime_types.map"]
[store."spam/trap-address"]
type = "memory"
format = "glob"
comment = '#'
values = "file://%{BASE_PATH}%/etc/spamfilter/maps/spam_trap.list"
[store."spam/scores"]
type = "memory"
format = "map"
values = "file://%{BASE_PATH}%/etc/spamfilter/maps/scores.map"
[sieve.trusted.scripts]
spam-filter = ["file://%{BASE_PATH}%/etc/spamfilter/scripts/config.sieve",
"file://%{BASE_PATH}%/etc/spamfilter/scripts/prelude.sieve",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,238 +1,238 @@
1cfresh.com
4chan.org
6pm.com
about.com
addthis.com
adf.ly
adobe.com
adp.com
adschemist.com
airbnb.com
airtel.in
alibaba.com
aliexpress.com
alipay.com
allrecipes.com
amazon.ca
amazon.cn
amazon.co.jp
amazon.com
amazon.co.uk
amazon.de
amazon.es
amazon.fr
amazon.in
amazon.it
amazon.ru
americanexpress.com
ancestry.com
android.com
apple.com
asana.com
att.com
autohome.com.cn
avg.com
aweber.com
badoo.com
bankofamerica.com
basecamp.com
battle.net
bet365.com
biglobe.ne.jp
bitly.com
bleacherreport.com
blogger.com
bloomberg.com
booking.com
box.com
bt.com
capitalone.com
cdiscount.com
change.org
chase.com
cisco.com
citi.com
costco.com
craigslist.org
custhelp.com
dell.com
delta.com
diply.com
discovercard.com
disqus.com
dropbox.com
drweb.com
e-boks.dk
ebay.ca
ebay.com
ebay.com.au
ebay.co.uk
ebay.de
ebay.fr
ebay.in
ebay.it
ebay.ru
etsy.com
evernote.com
expedia.com
facebook.com
fedex.com
fidelity.com
fishki.net
flickr.com
flirchi.com
force.com
freepik.com
gap.com
gawker.com
github.com
gizmodo.com
godaddy.com
googleadservices.com
googleusercontent.com
groupon.com
hdfcbank.com
hgtv.com
hh.ru
hm.com
houzz.com
hubspot.com
icicibank.com
icloud.com
ign.com
imgur.com
immobilienscout24.de
indeed.com
indiatimes.com
infusionsoft.com
instagram.com
intel.com
irctc.co.in
kayak.com
kickstarter.com
kijiji.ca
kotaku.com
letsencrypt.org
libero.it
lifehacker.com
likes.com
linkedin.com
linux.com
list-manage.com
mackeeper.com
mailchimp.com
mashable.com
match.com
mercadolibre.com.ar
mercadolivre.com.br
messenger.com
microsoft.com
microsoftonline.com
minmyndighetspost.se
moikrug.ru
mts.ru
neobux.com
netflix.com
newegg.com
nhk.or.jp
nifty.com
nikkeibp.co.jp
nyaa.se
nytimes.com
odnoklassniki.ru
ofd.yandex.ru
ok.ru
olx.ua
overstock.com
ozon.ru
ozon.travel
pandora.com
paypal.ca
paypal.cn
paypal.com
paypal.com
paypal.co.uk
paypal.de
paypal.es
paypal.fr
paypal.it
paypal.ru
paytm.com
pch.com
pinterest.com
porn.com
priceline.com
quora.com
rakuten.co.jp
reddit.com
researchgate.net
salesforce.com
sciencedirect.com
shopify.com
skanetrafiken.se
skat.dk
skatteverket.se
slack.com
slideshare.net
so-net.ne.jp
southwest.com
spotify.com
springer.com
squarespace.com
stalker.com
steampowered.com
stumbleupon.com
surveymonkey.com
swagbucks.com
taboola.com
taleo.net
taobao.com
target.com
taringa.net
taxi.yandex.ru
tele2.ru
thekitchn.com
tochka.com
tokopedia.com
trello.com
tribunnews.com
trulia.com
tumblr.com
twitter.com
ultimate-guitar.com
ups.com
usaa.com
usbank.com
usps.com
verizon.com
verizonwireless.com
vimeo.com
vine.co
vk.com
vmware.com
vtb24.ru
wahoofitness.com
walmart.com
wav.tv
wellsfargo.com
whatsapp.com
wikia.com
wikimedia.org
wikipedia.org
wildberries.ru
wix.com
wordpress.com
wordpress.org
wp.com
xuite.net
xvideos.com
yelp.com
youtube.com
yts.to
zappos.com
zendesk.com
zippyshare.com
zomato.com
zoom.us
zulily.com
zwift.com
spam-spdk = {"1cfresh.com",
"4chan.org",
"6pm.com",
"about.com",
"addthis.com",
"adf.ly",
"adobe.com",
"adp.com",
"adschemist.com",
"airbnb.com",
"airtel.in",
"alibaba.com",
"aliexpress.com",
"alipay.com",
"allrecipes.com",
"amazon.ca",
"amazon.cn",
"amazon.co.jp",
"amazon.com",
"amazon.co.uk",
"amazon.de",
"amazon.es",
"amazon.fr",
"amazon.in",
"amazon.it",
"amazon.ru",
"americanexpress.com",
"ancestry.com",
"android.com",
"apple.com",
"asana.com",
"att.com",
"autohome.com.cn",
"avg.com",
"aweber.com",
"badoo.com",
"bankofamerica.com",
"basecamp.com",
"battle.net",
"bet365.com",
"biglobe.ne.jp",
"bitly.com",
"bleacherreport.com",
"blogger.com",
"bloomberg.com",
"booking.com",
"box.com",
"bt.com",
"capitalone.com",
"cdiscount.com",
"change.org",
"chase.com",
"cisco.com",
"citi.com",
"costco.com",
"craigslist.org",
"custhelp.com",
"dell.com",
"delta.com",
"diply.com",
"discovercard.com",
"disqus.com",
"dropbox.com",
"drweb.com",
"e-boks.dk",
"ebay.ca",
"ebay.com",
"ebay.com.au",
"ebay.co.uk",
"ebay.de",
"ebay.fr",
"ebay.in",
"ebay.it",
"ebay.ru",
"etsy.com",
"evernote.com",
"expedia.com",
"facebook.com",
"fedex.com",
"fidelity.com",
"fishki.net",
"flickr.com",
"flirchi.com",
"force.com",
"freepik.com",
"gap.com",
"gawker.com",
"github.com",
"gizmodo.com",
"godaddy.com",
"googleadservices.com",
"googleusercontent.com",
"groupon.com",
"hdfcbank.com",
"hgtv.com",
"hh.ru",
"hm.com",
"houzz.com",
"hubspot.com",
"icicibank.com",
"icloud.com",
"ign.com",
"imgur.com",
"immobilienscout24.de",
"indeed.com",
"indiatimes.com",
"infusionsoft.com",
"instagram.com",
"intel.com",
"irctc.co.in",
"kayak.com",
"kickstarter.com",
"kijiji.ca",
"kotaku.com",
"letsencrypt.org",
"libero.it",
"lifehacker.com",
"likes.com",
"linkedin.com",
"linux.com",
"list-manage.com",
"mackeeper.com",
"mailchimp.com",
"mashable.com",
"match.com",
"mercadolibre.com.ar",
"mercadolivre.com.br",
"messenger.com",
"microsoft.com",
"microsoftonline.com",
"minmyndighetspost.se",
"moikrug.ru",
"mts.ru",
"neobux.com",
"netflix.com",
"newegg.com",
"nhk.or.jp",
"nifty.com",
"nikkeibp.co.jp",
"nyaa.se",
"nytimes.com",
"odnoklassniki.ru",
"ofd.yandex.ru",
"ok.ru",
"olx.ua",
"overstock.com",
"ozon.ru",
"ozon.travel",
"pandora.com",
"paypal.ca",
"paypal.cn",
"paypal.com",
"paypal.com",
"paypal.co.uk",
"paypal.de",
"paypal.es",
"paypal.fr",
"paypal.it",
"paypal.ru",
"paytm.com",
"pch.com",
"pinterest.com",
"porn.com",
"priceline.com",
"quora.com",
"rakuten.co.jp",
"reddit.com",
"researchgate.net",
"salesforce.com",
"sciencedirect.com",
"shopify.com",
"skanetrafiken.se",
"skat.dk",
"skatteverket.se",
"slack.com",
"slideshare.net",
"so-net.ne.jp",
"southwest.com",
"spotify.com",
"springer.com",
"squarespace.com",
"stalker.com",
"steampowered.com",
"stumbleupon.com",
"surveymonkey.com",
"swagbucks.com",
"taboola.com",
"taleo.net",
"taobao.com",
"target.com",
"taringa.net",
"taxi.yandex.ru",
"tele2.ru",
"thekitchn.com",
"tochka.com",
"tokopedia.com",
"trello.com",
"tribunnews.com",
"trulia.com",
"tumblr.com",
"twitter.com",
"ultimate-guitar.com",
"ups.com",
"usaa.com",
"usbank.com",
"usps.com",
"verizon.com",
"verizonwireless.com",
"vimeo.com",
"vine.co",
"vk.com",
"vmware.com",
"vtb24.ru",
"wahoofitness.com",
"walmart.com",
"wav.tv",
"wellsfargo.com",
"whatsapp.com",
"wikia.com",
"wikimedia.org",
"wikipedia.org",
"wildberries.ru",
"wix.com",
"wordpress.com",
"wordpress.org",
"wp.com",
"xuite.net",
"xvideos.com",
"yelp.com",
"youtube.com",
"yts.to",
"zappos.com",
"zendesk.com",
"zippyshare.com",
"zomato.com",
"zoom.us",
"zulily.com",
"zwift.com"}

View file

@ -1,427 +1,427 @@
0815.ru
0clickemail.com
0wnd.net
0wnd.org
1054733.mail-temp.com
10m.email
10minutemail.com
10minutesmail.com
1secmail.com
1secmail.net
1secmail.org
20minutemail.com
2emailock.com
2prong.com
33mail.com
3d-magical-magnet.ru
4warding.com
90bit.ru
9ox.net
a-bc.net
afrobacon.com
alaki.ga
alivance.com
amilegit.com
amiri.net
anonymbox.com
antichef.com
antichef.net
antispam.de
audio.now.im
awex.icu
barenshop.ru
barryogorman.com
baxomale.ht.cx
beefmilk.com
binkmail.com
bio-muesli.net
bobmail.info
bofthew.com
brefmail.com
bsnow.net
bspamfree.org
bugmenot.com
casualdx.com
centermail.com
cetpass.com
chammy.info
choicemail1.com
choocho-telegram.ru
cool.fr.nf
courriel.fr.nf
courrieltemporaire.com
cuvox.de
dandikmail.com
dayrep.com
dcemail.com
deadspam.com
desoz.com
devnullmail.com
dfg6.kozow.com
dfgh.net
digitalsanctuary.com
dingbone.com
discardmail.com
discardmail.de
dispomail.win
dispomail.xyz
disposableaddress.com
disposeamail.com
dispostable.com
divismail.ru
dlesha.ru
dmaster39.ru
dodgit.com
domremonta-nv.ru
donemail.ru
dontreg.com
dontsendmespam.de
dumpandjunk.com
e-mail.com
e-mail.org
e4ward.com
edu.aiot.ze.cx
ekholotdeeper.ru
email-24x7.com
email60.com
emailate.com
emailay.com
emailias.com
emailmiser.com
emailsensei.com
emailtemporanea.net
emailtemporario.com.br
emailtex.com
emailwarden.com
emailx.at.hm
emailxfer.com
emz.net
exbts.com
explodemail.com
extremail.ru
eyeemail.com
fakeinbox.com
fakeinformation.com
fantasymail.de
filzmail.com
fls4.gleeze.com
fotosta.ru
frapmail.com
fudgerub.com
funny-mom.ru
furycraft.ru
garliclife.com
get2mail.fr
getonemail.com
gishpuppy.com
gnomi.ru
goplaygame.ru
greensloth.com
grr.la
gsrv.co.uk
guerillamail.com
guerrillamail.biz
guerrillamail.com
guerrillamail.de
guerrillamail.info
guerrillamail.net
guerrillamail.org
guerrillamailblock.com
h2ocoffe.ru
haltospam.com
hatespam.org
hidemail.de
hmamail.com
hochsitze.com
hulapla.de
hydraulics360.ru
i.xcode.ro
imails.info
inboxclean.com
inboxclean.org
irish2me.com
isdaq.com
iwi.net
jetable.com
jetable.fr.nf
jetable.net
jetable.org
justyland.ru
kasmail.com
kaspop.com
kemampuan.me
kikoxltd.com
killmail.com
killmail.net
kismail.ru
kkm35.ru
klassmaster.com
klzlk.com
koszmail.pl
kurzepost.de
kusrc.com
lackmail.ru
laoho.com
ldaho.biz
leeching.net
letthemeatspam.com
lhsdv.com
lifebyfood.com
lifeguru.online
light-marketing.ru
lol.ovpn.to
lookugly.com
lortemail.dk
lr78.com
madecassol78.ru
mail-temporaire.fr
mail.mezimages.net
mail333.com
mailbidon.com
mailblocks.com
mailbucket.org
mailcatch.com
maildrop.cc
maildx.com
mailed.ro
mailfreeonline.com
mailfs.com
mailin8r.com
mailinater.com
mailinator.com
mailinator.net
mailinator2.com
mailincubator.com
mailme.ir
mailme.lv
mailmetal.com
mailmetrash.com
mailmoat.com
mailnesia.com
mailnull.com
mailscrap.com
mailshell.com
mailsiphon.com
mailsoul.com
mailtrash.net
mailzilla.com
makemetheking.com
mbx.cc
mega.zik.dj
meinspamschutz.de
meltmail.com
messagebeamer.de
mineblue.ru
mintemail.com
misha-rosestoy.ru
moboinfo.xyz
moncourrier.fr.nf
monemail.fr.nf
monmail.fr.nf
mor19.uu.gl
mt2009.com
mvrht.com
mycleaninbox.net
mymail-in.net
mypartyclip.de
myphantomemail.com
mytempemail.com
mytrashmail.com
neomailbox.com
nepwk.com
nervmich.net
nervtmich.net
netmails.com
netmails.net
neverbox.com
newfilm24.ru
niepodam.pl
no-spam.ws
nomail.xl.cx
nomorespamemails.com
nospam.ze.tc
nospam4.us
nospammail.net
notmailinator.com
notsharingmy.info
nowmymail.com
nurfuerspam.de
objectmail.com
obobbo.com
officialrolex.ru
oneoffemail.com
onewaymail.com
onlinenet.info
oopi.org
ordinaryamerican.net
otherinbox.com
ovpn.to
owlpic.com
p33.org
pancakemail.com
partner1bizmoney.ru
pchelovodstvo-tut.ru
piratesdelivery.ru
pmlep.de
politikerclub.de
pookmail.com
powerbank-russia.ru
privacy.net
proxymail.eu
prtnx.com
putthisinyourspamdatabase.com
quickinbox.com
razinrocks.me
rcpt.at
reallymymail.com
recode.me
reconmail.com
recursor.net
reloadpoint.ru
rtrtr.com
s-sakamas.ru
s0ny.net
safe-mail.net
safersignup.de
safetymail.info
safetypost.de
samogonda.ru
sendspamhere.com
senseless-entertainment.com
sgbteamreborn.imouto.pro
shar-kov.ru
sharklasers.com
shiftmail.com
shitmail.me
shortmail.net
sibmail.com
slaskpost.se
smellfear.com
sneakemail.com
sofimail.com
sogetthis.com
soodonims.com
spam4.me
spambob.net
spambog.com
spambog.de
spambog.ru
spambooger.com
spambox.us
spambox.win
spambox.xyz
spamcannon.com
spamcannon.net
spamcon.org
spamcorptastic.com
spamcowboy.com
spamcowboy.net
spamcowboy.org
spamday.com
spamex.com
spamfree.eu
spamfree24.com
spamfree24.de
spamfree24.org
spamgourmet.com
spamgourmet.net
spamgourmet.org
spamhereplease.com
spamhole.com
spamify.com
spaml.de
spammotel.com
spamobox.com
spamslicer.com
spamthis.co.uk
speed.1s.fr
squizzy.net
sskstroy.ru
streetwisemail.com
super-auswahl.de
supermailer.jp
suremail.info
tecninja.xyz
teewars.org
teleosaurs.xyz
teleworm.com
temp-mail.org
tempe-mail.com
tempemail.com
tempemail.net
tempinbox.co.uk
tempinbox.com
tempmail.it
tempmail.top
tempmail.win
tempomail.fr
thankyou2010.com
thisisnotmyrealemail.com
thrott.com
throwawayemailaddress.com
tilien.com
titaspaharpur1.gq
tmailinator.com
tradermail.info
trash-mail.at
trash-mail.com
trash-mail.de
trash2009.com
trashdevil.com
trashemail.de
trashinbox.net
trashmail.at
trashmail.com
trashmail.de
trashmail.me
trashmail.net
trashmail.org
trashmail.ws
trashmailer.com
trashymail.com
trbvm.com
trbvn.com
trillianpro.com
tvchd.com
twinmail.de
tyldd.com
uggsrock.com
upliftnow.com
urhen.com
ussv.club
vapecentral.ru
venompen.com
veryrealemail.com
vkusup.ru
voemail.com
vssms.com
weammo.xyz
webcool.club
wegwerfadresse.de
wegwerfemail.com
wegwerfemail.de
wegwerfmail.de
wegwerfmail.net
wegwerfmail.org
wh4f.org
whyspam.me
willhackforfood.biz
willselfdestruct.com
wronghead.com
wwwnew.eu
xemaps.com
xitroo.com
xmaily.com
xoxy.net
xww.ro
yep.it
yevme.com
yopmail.com
yopmail.fr
yopmail.net
yuurok.com
zagorodnyi-domik.ru
zdorovpagh.ru
zehnminutenmail.de
zippymail.info
zoemail.net
spam-disposable = {"0815.ru",
"0clickemail.com",
"0wnd.net",
"0wnd.org",
"1054733.mail-temp.com",
"10m.email",
"10minutemail.com",
"10minutesmail.com",
"1secmail.com",
"1secmail.net",
"1secmail.org",
"20minutemail.com",
"2emailock.com",
"2prong.com",
"33mail.com",
"3d-magical-magnet.ru",
"4warding.com",
"90bit.ru",
"9ox.net",
"a-bc.net",
"afrobacon.com",
"alaki.ga",
"alivance.com",
"amilegit.com",
"amiri.net",
"anonymbox.com",
"antichef.com",
"antichef.net",
"antispam.de",
"audio.now.im",
"awex.icu",
"barenshop.ru",
"barryogorman.com",
"baxomale.ht.cx",
"beefmilk.com",
"binkmail.com",
"bio-muesli.net",
"bobmail.info",
"bofthew.com",
"brefmail.com",
"bsnow.net",
"bspamfree.org",
"bugmenot.com",
"casualdx.com",
"centermail.com",
"cetpass.com",
"chammy.info",
"choicemail1.com",
"choocho-telegram.ru",
"cool.fr.nf",
"courriel.fr.nf",
"courrieltemporaire.com",
"cuvox.de",
"dandikmail.com",
"dayrep.com",
"dcemail.com",
"deadspam.com",
"desoz.com",
"devnullmail.com",
"dfg6.kozow.com",
"dfgh.net",
"digitalsanctuary.com",
"dingbone.com",
"discardmail.com",
"discardmail.de",
"dispomail.win",
"dispomail.xyz",
"disposableaddress.com",
"disposeamail.com",
"dispostable.com",
"divismail.ru",
"dlesha.ru",
"dmaster39.ru",
"dodgit.com",
"domremonta-nv.ru",
"donemail.ru",
"dontreg.com",
"dontsendmespam.de",
"dumpandjunk.com",
"e-mail.com",
"e-mail.org",
"e4ward.com",
"edu.aiot.ze.cx",
"ekholotdeeper.ru",
"email-24x7.com",
"email60.com",
"emailate.com",
"emailay.com",
"emailias.com",
"emailmiser.com",
"emailsensei.com",
"emailtemporanea.net",
"emailtemporario.com.br",
"emailtex.com",
"emailwarden.com",
"emailx.at.hm",
"emailxfer.com",
"emz.net",
"exbts.com",
"explodemail.com",
"extremail.ru",
"eyeemail.com",
"fakeinbox.com",
"fakeinformation.com",
"fantasymail.de",
"filzmail.com",
"fls4.gleeze.com",
"fotosta.ru",
"frapmail.com",
"fudgerub.com",
"funny-mom.ru",
"furycraft.ru",
"garliclife.com",
"get2mail.fr",
"getonemail.com",
"gishpuppy.com",
"gnomi.ru",
"goplaygame.ru",
"greensloth.com",
"grr.la",
"gsrv.co.uk",
"guerillamail.com",
"guerrillamail.biz",
"guerrillamail.com",
"guerrillamail.de",
"guerrillamail.info",
"guerrillamail.net",
"guerrillamail.org",
"guerrillamailblock.com",
"h2ocoffe.ru",
"haltospam.com",
"hatespam.org",
"hidemail.de",
"hmamail.com",
"hochsitze.com",
"hulapla.de",
"hydraulics360.ru",
"i.xcode.ro",
"imails.info",
"inboxclean.com",
"inboxclean.org",
"irish2me.com",
"isdaq.com",
"iwi.net",
"jetable.com",
"jetable.fr.nf",
"jetable.net",
"jetable.org",
"justyland.ru",
"kasmail.com",
"kaspop.com",
"kemampuan.me",
"kikoxltd.com",
"killmail.com",
"killmail.net",
"kismail.ru",
"kkm35.ru",
"klassmaster.com",
"klzlk.com",
"koszmail.pl",
"kurzepost.de",
"kusrc.com",
"lackmail.ru",
"laoho.com",
"ldaho.biz",
"leeching.net",
"letthemeatspam.com",
"lhsdv.com",
"lifebyfood.com",
"lifeguru.online",
"light-marketing.ru",
"lol.ovpn.to",
"lookugly.com",
"lortemail.dk",
"lr78.com",
"madecassol78.ru",
"mail-temporaire.fr",
"mail.mezimages.net",
"mail333.com",
"mailbidon.com",
"mailblocks.com",
"mailbucket.org",
"mailcatch.com",
"maildrop.cc",
"maildx.com",
"mailed.ro",
"mailfreeonline.com",
"mailfs.com",
"mailin8r.com",
"mailinater.com",
"mailinator.com",
"mailinator.net",
"mailinator2.com",
"mailincubator.com",
"mailme.ir",
"mailme.lv",
"mailmetal.com",
"mailmetrash.com",
"mailmoat.com",
"mailnesia.com",
"mailnull.com",
"mailscrap.com",
"mailshell.com",
"mailsiphon.com",
"mailsoul.com",
"mailtrash.net",
"mailzilla.com",
"makemetheking.com",
"mbx.cc",
"mega.zik.dj",
"meinspamschutz.de",
"meltmail.com",
"messagebeamer.de",
"mineblue.ru",
"mintemail.com",
"misha-rosestoy.ru",
"moboinfo.xyz",
"moncourrier.fr.nf",
"monemail.fr.nf",
"monmail.fr.nf",
"mor19.uu.gl",
"mt2009.com",
"mvrht.com",
"mycleaninbox.net",
"mymail-in.net",
"mypartyclip.de",
"myphantomemail.com",
"mytempemail.com",
"mytrashmail.com",
"neomailbox.com",
"nepwk.com",
"nervmich.net",
"nervtmich.net",
"netmails.com",
"netmails.net",
"neverbox.com",
"newfilm24.ru",
"niepodam.pl",
"no-spam.ws",
"nomail.xl.cx",
"nomorespamemails.com",
"nospam.ze.tc",
"nospam4.us",
"nospammail.net",
"notmailinator.com",
"notsharingmy.info",
"nowmymail.com",
"nurfuerspam.de",
"objectmail.com",
"obobbo.com",
"officialrolex.ru",
"oneoffemail.com",
"onewaymail.com",
"onlinenet.info",
"oopi.org",
"ordinaryamerican.net",
"otherinbox.com",
"ovpn.to",
"owlpic.com",
"p33.org",
"pancakemail.com",
"partner1bizmoney.ru",
"pchelovodstvo-tut.ru",
"piratesdelivery.ru",
"pmlep.de",
"politikerclub.de",
"pookmail.com",
"powerbank-russia.ru",
"privacy.net",
"proxymail.eu",
"prtnx.com",
"putthisinyourspamdatabase.com",
"quickinbox.com",
"razinrocks.me",
"rcpt.at",
"reallymymail.com",
"recode.me",
"reconmail.com",
"recursor.net",
"reloadpoint.ru",
"rtrtr.com",
"s-sakamas.ru",
"s0ny.net",
"safe-mail.net",
"safersignup.de",
"safetymail.info",
"safetypost.de",
"samogonda.ru",
"sendspamhere.com",
"senseless-entertainment.com",
"sgbteamreborn.imouto.pro",
"shar-kov.ru",
"sharklasers.com",
"shiftmail.com",
"shitmail.me",
"shortmail.net",
"sibmail.com",
"slaskpost.se",
"smellfear.com",
"sneakemail.com",
"sofimail.com",
"sogetthis.com",
"soodonims.com",
"spam4.me",
"spambob.net",
"spambog.com",
"spambog.de",
"spambog.ru",
"spambooger.com",
"spambox.us",
"spambox.win",
"spambox.xyz",
"spamcannon.com",
"spamcannon.net",
"spamcon.org",
"spamcorptastic.com",
"spamcowboy.com",
"spamcowboy.net",
"spamcowboy.org",
"spamday.com",
"spamex.com",
"spamfree.eu",
"spamfree24.com",
"spamfree24.de",
"spamfree24.org",
"spamgourmet.com",
"spamgourmet.net",
"spamgourmet.org",
"spamhereplease.com",
"spamhole.com",
"spamify.com",
"spaml.de",
"spammotel.com",
"spamobox.com",
"spamslicer.com",
"spamthis.co.uk",
"speed.1s.fr",
"squizzy.net",
"sskstroy.ru",
"streetwisemail.com",
"super-auswahl.de",
"supermailer.jp",
"suremail.info",
"tecninja.xyz",
"teewars.org",
"teleosaurs.xyz",
"teleworm.com",
"temp-mail.org",
"tempe-mail.com",
"tempemail.com",
"tempemail.net",
"tempinbox.co.uk",
"tempinbox.com",
"tempmail.it",
"tempmail.top",
"tempmail.win",
"tempomail.fr",
"thankyou2010.com",
"thisisnotmyrealemail.com",
"thrott.com",
"throwawayemailaddress.com",
"tilien.com",
"titaspaharpur1.gq",
"tmailinator.com",
"tradermail.info",
"trash-mail.at",
"trash-mail.com",
"trash-mail.de",
"trash2009.com",
"trashdevil.com",
"trashemail.de",
"trashinbox.net",
"trashmail.at",
"trashmail.com",
"trashmail.de",
"trashmail.me",
"trashmail.net",
"trashmail.org",
"trashmail.ws",
"trashmailer.com",
"trashymail.com",
"trbvm.com",
"trbvn.com",
"trillianpro.com",
"tvchd.com",
"twinmail.de",
"tyldd.com",
"uggsrock.com",
"upliftnow.com",
"urhen.com",
"ussv.club",
"vapecentral.ru",
"venompen.com",
"veryrealemail.com",
"vkusup.ru",
"voemail.com",
"vssms.com",
"weammo.xyz",
"webcool.club",
"wegwerfadresse.de",
"wegwerfemail.com",
"wegwerfemail.de",
"wegwerfmail.de",
"wegwerfmail.net",
"wegwerfmail.org",
"wh4f.org",
"whyspam.me",
"willhackforfood.biz",
"willselfdestruct.com",
"wronghead.com",
"wwwnew.eu",
"xemaps.com",
"xitroo.com",
"xmaily.com",
"xoxy.net",
"xww.ro",
"yep.it",
"yevme.com",
"yopmail.com",
"yopmail.fr",
"yopmail.net",
"yuurok.com",
"zagorodnyi-domik.ru",
"zdorovpagh.ru",
"zehnminutenmail.de",
"zippymail.info",
"zoemail.net"}

File diff suppressed because it is too large Load diff

View file

@ -1,129 +1,131 @@
bat BAD
chm BAD
com BAD
exe BAD
hta BAD|NZ
iso BAD
jar BAD|NZ
lnk BAD
scr BAD
htm text/html|BAD
html text/html|BAD
shtm text/html|BAD
shtml text/html|BAD
ace BAD|AR
arj BAD|AR
asx BAD
cab BAD|AR
sfx BAD
vst BAD
vss BAD
ade BAD
adp BAD
cmd BAD
cpl BAD
ins BAD
isp BAD
js BAD|NZ
jse BAD
lib BAD
mde BAD
msc BAD
msi BAD
msp BAD
mst BAD
nsh BAD
pif BAD
sct BAD
shb BAD
sys BAD
vb BAD
vbe BAD
vbs BAD|NZ
vxd BAD
wsc BAD
wsh BAD
app BAD
asp BAD
bas BAD
cnt BAD
csh BAD
diagcab BAD
fxp BAD
gadget BAD
grp BAD
hlp BAD
hpj BAD
inf BAD
its BAD
jnlp BAD
ksh BAD
mad BAD
maf BAD
mag BAD
mam BAD
maq BAD
mar BAD
mas BAD
mat BAD
mau BAD
mav BAD
maw BAD
mcf BAD
mda BAD
mdb BAD
mdt BAD
mdw BAD
mdz BAD
msh BAD
msh1 BAD
msh2 BAD
mshxml BAD
msh1xml BAD
msh2xml BAD
msu BAD
ops BAD
osd BAD
pcd BAD
pl BAD
plg BAD
prf BAD
prg BAD
printerexport BAD
ps1 BAD
ps1xml BAD
ps2 BAD
ps2xml BAD
psc1 BAD
psc2 BAD
psd1 BAD
psdm1 BAD
pst BAD
reg BAD
scf BAD
shs BAD
theme BAD
url BAD
vbp BAD
vsmacros BAD
vsw BAD
webpnp BAD
website BAD
ws BAD
xbap BAD
xll BAD
xnk BAD
docx NZ
pdf application/pdf|application/x-pdf|NZ
pptx NZ
wsf NZ
xlsx NZ
7x AR
alz AR
bz2 AR
egg AR
lz AR
rar AR
xz AR
zip AR
txt text/plain|message/disposition-notification|text/rfc822-headers
spam-mime = {
"bat" = "BAD",
"chm" = "BAD",
"com" = "BAD",
"exe" = "BAD",
"hta" = "BAD|NZ",
"iso" = "BAD",
"jar" = "BAD|NZ",
"lnk" = "BAD",
"scr" = "BAD",
"htm" = "text/html|BAD",
"html" = "text/html|BAD",
"shtm" = "text/html|BAD",
"shtml" = "text/html|BAD",
"ace" = "BAD|AR",
"arj" = "BAD|AR",
"asx" = "BAD",
"cab" = "BAD|AR",
"sfx" = "BAD",
"vst" = "BAD",
"vss" = "BAD",
"ade" = "BAD",
"adp" = "BAD",
"cmd" = "BAD",
"cpl" = "BAD",
"ins" = "BAD",
"isp" = "BAD",
"js" = "BAD|NZ",
"jse" = "BAD",
"lib" = "BAD",
"mde" = "BAD",
"msc" = "BAD",
"msi" = "BAD",
"msp" = "BAD",
"mst" = "BAD",
"nsh" = "BAD",
"pif" = "BAD",
"sct" = "BAD",
"shb" = "BAD",
"sys" = "BAD",
"vb" = "BAD",
"vbe" = "BAD",
"vbs" = "BAD|NZ",
"vxd" = "BAD",
"wsc" = "BAD",
"wsh" = "BAD",
"app" = "BAD",
"asp" = "BAD",
"bas" = "BAD",
"cnt" = "BAD",
"csh" = "BAD",
"diagcab" = "BAD",
"fxp" = "BAD",
"gadget" = "BAD",
"grp" = "BAD",
"hlp" = "BAD",
"hpj" = "BAD",
"inf" = "BAD",
"its" = "BAD",
"jnlp" = "BAD",
"ksh" = "BAD",
"mad" = "BAD",
"maf" = "BAD",
"mag" = "BAD",
"mam" = "BAD",
"maq" = "BAD",
"mar" = "BAD",
"mas" = "BAD",
"mat" = "BAD",
"mau" = "BAD",
"mav" = "BAD",
"maw" = "BAD",
"mcf" = "BAD",
"mda" = "BAD",
"mdb" = "BAD",
"mdt" = "BAD",
"mdw" = "BAD",
"mdz" = "BAD",
"msh" = "BAD",
"msh1" = "BAD",
"msh2" = "BAD",
"mshxml" = "BAD",
"msh1xml" = "BAD",
"msh2xml" = "BAD",
"msu" = "BAD",
"ops" = "BAD",
"osd" = "BAD",
"pcd" = "BAD",
"pl" = "BAD",
"plg" = "BAD",
"prf" = "BAD",
"prg" = "BAD",
"printerexport" = "BAD",
"ps1" = "BAD",
"ps1xml" = "BAD",
"ps2" = "BAD",
"ps2xml" = "BAD",
"psc1" = "BAD",
"psc2" = "BAD",
"psd1" = "BAD",
"psdm1" = "BAD",
"pst" = "BAD",
"reg" = "BAD",
"scf" = "BAD",
"shs" = "BAD",
"theme" = "BAD",
"url" = "BAD",
"vbp" = "BAD",
"vsmacros" = "BAD",
"vsw" = "BAD",
"webpnp" = "BAD",
"website" = "BAD",
"ws" = "BAD",
"xbap" = "BAD",
"xll" = "BAD",
"xnk" = "BAD",
"docx" = "NZ",
"pdf" = "application/pdf|application/x-pdf|NZ",
"pptx" = "NZ",
"wsf" = "NZ",
"xlsx" = "NZ",
"7x" = "AR",
"alz" = "AR",
"bz2" = "AR",
"egg" = "AR",
"lz" = "AR",
"rar" = "AR",
"xz" = "AR",
"zip" = "AR",
"txt" = "text/plain|message/disposition-notification|text/rfc822-headers"}

View file

@ -1,364 +1,364 @@
ABUSE_SURBL 5.0
ALLOWLIST_DKIM -1.0
ALLOWLIST_DMARC -7.0
ALLOWLIST_SPF -1.0
ALLOWLIST_SPF_DKIM -3.0
ARC_ALLOW -1.0
ARC_DNSFAIL 0.0
ARC_INVALID 0.5
ARC_NA 0.0
ARC_REJECT 1.0
ARC_SIGNED 0.0
AUTH_NA 1.0
AUTH_NA_OR_FAIL 1.0
AUTOGEN_PHP_SPAMMY 1.0
BAYES_HAM -3.0
BAYES_SPAM 5.1
BLOCKLIST_DKIM 2.0
BLOCKLIST_DMARC 6.0
BLOCKLIST_SPF 1.0
BLOCKLIST_SPF_DKIM 3.0
BODY_URI_ONLY 2.0
BOGUS_ENCRYPTED_AND_TEXT 10.0
BOUNCE -0.1
BOUNCE_NO_AUTH 1.0
BROKEN_CONTENT_TYPE 1.5
COMPROMISED_ACCT_BULK 3.0
CRACKED_SURBL 5.0
CTE_CASE 0.5
CTYPE_MISSING_DISPOSITION 4.0
CTYPE_MIXED_BOGUS 1.0
CT_EXTRA_SEMI 1.0
DATA_URI_OBFU 2.0
DATE_IN_FUTURE 4.0
DATE_IN_PAST 1.0
DBL_ABUSE 5.0
DBL_ABUSE_BOTNET 6.5
DBL_ABUSE_MALWARE 6.5
DBL_ABUSE_PHISH 6.5
DBL_ABUSE_REDIR 5.0
DBL_BLOCKED 0.0
DBL_BLOCKED_OPENRESOLVER 0.0
DBL_BOTNET 7.5
DBL_MALWARE 7.5
DBL_PHISH 7.5
DBL_SPAM 6.5
DCC_BULK 3.0
DIRECT_TO_MX 0.0
DISPOSABLE_CC 0.0
DISPOSABLE_ENVFROM 0.0
DISPOSABLE_FROM 0.0
DISPOSABLE_REPLYTO 0.0
DISPOSABLE_TO 0.0
DKIM_SIGNED 0.0
DMARC_BAD_POLICY 0.5
DMARC_DNSFAIL 0.0
DMARC_NA 0.0
DMARC_POLICY_ALLOW -0.5
DMARC_POLICY_ALLOW_WITH_FAILURES 0.0
DMARC_POLICY_QUARANTINE 1.5
DMARC_POLICY_REJECT 2.0
DMARC_POLICY_SOFTFAIL 0.1
DNSWL_BLOCKED 0.0
DWL_DNSWL_BLOCKED 0.0
DWL_DNSWL_HI -3.5
DWL_DNSWL_LOW -1.0
DWL_DNSWL_MED -2.0
DWL_DNSWL_NONE 0.0
EMPTY_SUBJECT 1.0
ENCRYPTED_PGP -0.5
ENCRYPTED_SMIME -0.5
ENVFROM_INVALID 2.0
ENVFROM_SERVICE_ACCT 1.0
EXT_CSS 1.0
FAKE_REPLY 1.0
FORGED_RCVD_TRAIL 1.0
FORGED_RECIPIENTS 2.0
FORGED_RECIPIENTS_MAILLIST 0.0
FORGED_SENDER 0.3
FORGED_SENDER_MAILLIST 0.0
FREEMAIL_AFF 4.0
FREEMAIL_CC 0.0
FREEMAIL_ENVFROM 0.0
FREEMAIL_FROM 0.0
FREEMAIL_REPLYTO 0.0
FREEMAIL_REPLYTO_NEQ_FROM_DOM 3.0
FREEMAIL_TO 0.0
FROM_DN_EQ_ADDR 1.0
FROM_EQ_ENVFROM 0.0
FROM_EXCESS_BASE64 1.5
FROM_EXCESS_QP 1.2
FROM_HAS_DN 0.0
FROM_INVALID 2.0
FROM_NAME_EXCESS_SPACE 1.0
FROM_NAME_HAS_TITLE 1.0
FROM_NEEDS_ENCODING 1.0
FROM_NEQ_DISPLAY_NAME 4.0
FROM_NEQ_ENVFROM 0.0
FROM_NO_DN 0.0
FROM_SERVICE_ACCT 1.0
HACKED_WP_PHISHING 4.5
HAS_ANON_DOMAIN 0.1
HAS_ATTACHMENT 0.0
HAS_DATA_URI 0.0
HAS_GOOGLE_FIREBASE_URL 2.0
HAS_GOOGLE_REDIR 1.0
HAS_GUC_PROXY_URI 1.0
HAS_IPFS_GATEWAY_URL 6.0
HAS_LIST_UNSUB -0.01
HAS_ONION_URI 0.0
HAS_ORG_HEADER 0.0
HAS_PHPMAILER_SIG 0.0
HAS_REPLYTO 0.0
HAS_WP_URI 0.0
HAS_XAW 0.0
HAS_XOIP 0.0
HAS_X_ANTIABUSE 0.0
HAS_X_AS 0.0
HAS_X_GMSV 0.0
HAS_X_PHP_SCRIPT 0.0
HAS_X_POS 0.0
HAS_X_PRIO_FIVE 0.0
HAS_X_PRIO_ONE 0.0
HAS_X_PRIO_THREE 0.0
HAS_X_PRIO_TWO 0.0
HAS_X_PRIO_ZERO 0.0
HAS_X_SOURCE 0.0
HEADER_EMPTY_DELIMITER 1.0
HEADER_FORGED_MDN 2.0
HEADER_RCONFIRM_MISMATCH 2.0
FROMHOST_NORES_A_OR_MX 1.5
FROM_BOUNCE 0.0
HELO_BAREIP 3.0
HELO_IP_A 1.0
HELO_NORES_A_OR_MX 0.3
HELO_NOT_FQDN 2.0
HELO_IPREV_MISMATCH 1.0
RCPT_BOUNCEMOREONE 1.5
URL_ONLY 2.2
HIDDEN_SOURCE_OBJ 2.0
HTML_META_REFRESH_URL 5.0
HTML_SHORT_LINK_IMG_1 2.0
HTML_SHORT_LINK_IMG_2 1.0
HTML_SHORT_LINK_IMG_3 0.5
HTML_TEXT_IMG_RATIO 1.0
HTML_UNBALANCED_TAG 0.5
HTTP_TO_HTTPS 0.5
HTTP_TO_IP 1.0
INFO_TO_INFO_LU 2.0
INVALID_DATE 1.5
INVALID_FROM_8BIT 6.0
INVALID_MSGID 1.7
KLMS_SPAM 5.0
LONG_SUBJ 3.0
MAILLIST -0.2
MANY_INVISIBLE_PARTS 1.0
MID_BARE_IP 2.0
MID_CONTAINS_FROM 1.0
MID_CONTAINS_TO 1.0
MID_MISSING_BRACKETS 1.0
MID_RHS_IP_LITERAL 1.0
MID_RHS_MATCH_FROM 1.0
MID_RHS_MATCH_FROMTLD 1.0
MID_RHS_MATCH_TO 1.0
MID_RHS_NOT_FQDN 0.5
MID_RHS_WWW 0.5
MIME_ARCHIVE_IN_ARCHIVE 5.0
MIME_BAD 1.0
MIME_BAD_ATTACHMENT 4.0
MIME_BAD_EXTENSION 2.0
MIME_BAD_UNICODE 8.0
MIME_BASE64_TEXT 0.1
MIME_BASE64_TEXT_BOGUS 1.0
MIME_DOUBLE_BAD_EXTENSION 2.0
MIME_GOOD -0.1
MIME_HEADER_CTYPE_ONLY 2.0
MIME_HTML_ONLY 0.2
MIME_MA_MISSING_HTML 1.0
MIME_MA_MISSING_TEXT 2.0
MISSING_DATE 1.0
MISSING_FROM 2.0
MISSING_MID 2.5
MISSING_MIME_VERSION 2.0
MISSING_SUBJECT 2.0
MISSING_TO 2.0
MSBL_EBL 7.5
MSBL_EBL_GREY 0.5
MULTIPLE_FROM 8.0
MULTIPLE_UNIQUE_HEADERS 7.0
MV_CASE 0.5
MW_SURBL_MULTI 7.5
HOMOGRAPH_URL 5.0
ONCE_RECEIVED 0.1
PHISHED_OPENPHISH 7.0
PHISHED_PHISHTANK 7.0
PHISHING 4.0
PHISH_EMOTION 1.0
PHP_XPS_PATTERN 0.0
PH_SURBL_MULTI 7.5
PRECEDENCE_BULK 0.0
PREVIOUSLY_DELIVERED 0.0
PYZOR 3.5
RBL_BARRACUDA 4.0
RBL_BLOCKLISTDE 4.0
RBL_MAILSPIKE_BAD 1.0
RBL_MAILSPIKE_VERYBAD 1.5
RBL_MAILSPIKE_WORST 2.0
RBL_NIXSPAM 4.0
RBL_SEM 1.0
RBL_SEM_IPV6 1.0
RBL_SENDERSCORE 2.0
RBL_SPAMCOP 4.0
RBL_SPAMHAUS 0.0
RBL_SPAMHAUS_BLOCKED 0.0
RBL_SPAMHAUS_BLOCKED_OPENRESOLVER 0.0
RBL_SPAMHAUS_CSS 2.0
RBL_SPAMHAUS_DROP 7.0
RBL_SPAMHAUS_PBL 2.0
RBL_SPAMHAUS_SBL 4.0
RBL_SPAMHAUS_XBL 4.0
RBL_VIRUSFREE_BOTNET 2.0
RCPT_ADDR_IN_SUBJECT 3.0
RCPT_COUNT_FIVE 0.0
RCPT_COUNT_GT_50 0.0
RCPT_COUNT_ONE 0.0
RCPT_COUNT_SEVEN 0.0
RCPT_COUNT_THREE 0.0
RCPT_COUNT_TWELVE 0.0
RCPT_COUNT_TWO 0.0
RCPT_COUNT_ZERO 0.0
RCPT_LOCAL_IN_SUBJECT 2.0
RCVD_COUNT_FIVE 0.0
RCVD_COUNT_ONE 0.0
RCVD_COUNT_SEVEN 0.0
RCVD_COUNT_THREE 0.0
RCVD_COUNT_TWELVE 0.0
RCVD_COUNT_TWO 0.0
RCVD_COUNT_ZERO 0.0
RCVD_DKIM_ARC_DNSWL_HI -1.0
RCVD_DKIM_ARC_DNSWL_MED -0.5
RCVD_DOUBLE_IP_SPAM 2.0
RCVD_FROM_SMTP_AUTH 0.0
RCVD_HELO_USER 3.0
RCVD_ILLEGAL_CHARS 4.0
RCVD_IN_DNSWL_HI -0.5
RCVD_IN_DNSWL_LOW -0.1
RCVD_IN_DNSWL_MED -0.2
RCVD_IN_DNSWL_NONE 0.0
RCVD_NO_TLS_LAST 0.1
RCVD_TLS_ALL 0.0
RCVD_TLS_LAST 0.0
RCVD_UNAUTH_PBL 2.0
RCVD_VIA_SMTP_AUTH 0.0
RDNS_DNSFAIL 0.0
RDNS_NONE 1.0
RECEIVED_BLOCKLISTDE 3.0
RECEIVED_SPAMHAUS_BLOCKED 0.0
RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER 0.0
RECEIVED_SPAMHAUS_CSS 1.0
RECEIVED_SPAMHAUS_PBL 0.0
RECEIVED_SPAMHAUS_SBL 3.0
RECEIVED_SPAMHAUS_XBL 1.0
REDIRECTOR_URL 0.0
REDIRECTOR_URL_ONLY 1.0
REPLYTO_ADDR_EQ_FROM 0.0
REPLYTO_DN_EQ_FROM_DN 0.0
REPLYTO_DOM_EQ_FROM_DOM 0.0
REPLYTO_DOM_NEQ_FROM_DOM 0.0
REPLYTO_EMAIL_HAS_TITLE 2.0
REPLYTO_EQ_FROM 0.0
REPLYTO_EQ_TO_ADDR 5.0
REPLYTO_EXCESS_BASE64 1.5
REPLYTO_EXCESS_QP 1.2
REPLYTO_UNPARSEABLE 1.0
RWL_MAILSPIKE_EXCELLENT -0.4
RWL_MAILSPIKE_GOOD -0.1
RWL_MAILSPIKE_NEUTRAL 0.0
RWL_MAILSPIKE_POSSIBLE 0.0
RWL_MAILSPIKE_VERYGOOD -0.2
R_BAD_CTE_7BIT 3.5
DKIM_ALLOW -0.2
DKIM_NA 0.0
DKIM_PERMFAIL 0.0
DKIM_REJECT 1.0
DKIM_TEMPFAIL 0.0
R_MISSING_CHARSET 0.5
R_MIXED_CHARSET 5.0
MIXED_CHARSET_URL 7.0
R_NO_SPACE_IN_FROM 1.0
R_PARTS_DIFFER 1.0
SPF_ALLOW -0.2
SPF_DNSFAIL 0.0
SPF_FAIL 1.0
SPF_NA 0.0
SPF_NEUTRAL 0.0
SPF_PERMFAIL 0.0
SPF_SOFTFAIL 0.0
R_SUSPICIOUS_URL 5.0
R_UNDISC_RCPT 3.0
SEM_URIBL 3.5
SEM_URIBL_FRESH15 3.0
SIGNED_PGP -2.0
SIGNED_SMIME -2.0
SORTED_RECIPS 3.5
SPAM_FLAG 5.0
SPAM_TRAP discard
SPOOF_DISPLAY_NAME 8.0
SPOOF_REPLYTO 6.0
SUBJECT_ENDS_EXCLAIM 0.0
SUBJECT_ENDS_QUESTION 1.0
SUBJECT_ENDS_SPACES 0.5
SUBJECT_HAS_CURRENCY 1.0
SUBJECT_HAS_EXCLAIM 0.0
SUBJECT_HAS_QUESTION 0.0
SUBJECT_NEEDS_ENCODING 1.0
SUBJ_ALL_CAPS 3.0
SUBJ_BOUNCE_WORDS 0.0
SUBJ_EXCESS_BASE64 1.5
SUBJ_EXCESS_QP 1.2
SURBL_BLOCKED 0.0
SURBL_HASHBL_ABUSE 5.0
SURBL_HASHBL_CRACKED 5.0
SURBL_HASHBL_EMAIL 5.0
SURBL_HASHBL_MALWARE 6.5
SURBL_HASHBL_PHISH 6.5
SUSPICIOUS_RECIPS 1.5
TAGGED_FROM 0.0
TAGGED_RCPT 0.0
THREAD_HIJACKING_FROM_INJECTOR 2.0
TO_DN_ALL 0.0
TO_DN_EQ_ADDR_ALL 0.0
TO_DN_EQ_ADDR_SOME 0.0
TO_DN_NONE 0.0
TO_DN_RECIPIENTS 2.0
TO_DN_SOME 0.0
TO_DOM_EQ_FROM_DOM 0.0
TO_EQ_FROM 0.0
TO_EXCESS_BASE64 1.5
TO_EXCESS_QP 1.2
TO_MATCH_ENVRCPT_ALL 0.0
TO_MATCH_ENVRCPT_SOME 0.0
TO_NEEDS_ENCODING 1.0
TO_WRAPPED_IN_SPACES 2.0
TRUSTED_REPLY -7.0
UNDISC_RCPTS_BULK 3.0
UNITEDINTERNET_SPAM 5.0
URIBL_BLACK 7.5
URIBL_BLOCKED 0.0
URIBL_GREY 1.5
URIBL_RED 3.5
URI_COUNT_ODD 1.0
URI_HIDDEN_PATH 1.0
URL_IN_SUBJECT 4.0
URL_REDIRECTOR_NESTED 1.0
VIOLATED_DIRECT_SPF 3.5
WP_COMPROMISED 0.0
WWW_DOT_DOMAIN 0.5
XM_CASE 0.5
XM_UA_NO_VERSION 0.01
X_PHP_EVAL 4.0
ZERO_WIDTH_SPACE_URL 7.0
SHORT_PART_BAD_HEADERS 7.0
MISSING_ESSENTIAL_HEADERS 7.0
SINGLE_SHORT_PART 0.0
COMPLETELY_EMPTY 7.0
spam-scores = {"ABUSE_SURBL" = "5.0",
"ALLOWLIST_DKIM" = "-1.0",
"ALLOWLIST_DMARC" = "-7.0",
"ALLOWLIST_SPF" = "-1.0",
"ALLOWLIST_SPF_DKIM" = "-3.0",
"ARC_ALLOW" = "-1.0",
"ARC_DNSFAIL" = "0.0",
"ARC_INVALID" = "0.5",
"ARC_NA" = "0.0",
"ARC_REJECT" = "1.0",
"ARC_SIGNED" = "0.0",
"AUTH_NA" = "1.0",
"AUTH_NA_OR_FAIL" = "1.0",
"AUTOGEN_PHP_SPAMMY" = "1.0",
"BAYES_HAM" = "-3.0",
"BAYES_SPAM" = "5.1",
"BLOCKLIST_DKIM" = "2.0",
"BLOCKLIST_DMARC" = "6.0",
"BLOCKLIST_SPF" = "1.0",
"BLOCKLIST_SPF_DKIM" = "3.0",
"BODY_URI_ONLY" = "2.0",
"BOGUS_ENCRYPTED_AND_TEXT" = "10.0",
"BOUNCE" = "-0.1",
"BOUNCE_NO_AUTH" = "1.0",
"BROKEN_CONTENT_TYPE" = "1.5",
"COMPROMISED_ACCT_BULK" = "3.0",
"CRACKED_SURBL" = "5.0",
"CTE_CASE" = "0.5",
"CTYPE_MISSING_DISPOSITION" = "4.0",
"CTYPE_MIXED_BOGUS" = "1.0",
"CT_EXTRA_SEMI" = "1.0",
"DATA_URI_OBFU" = "2.0",
"DATE_IN_FUTURE" = "4.0",
"DATE_IN_PAST" = "1.0",
"DBL_ABUSE" = "5.0",
"DBL_ABUSE_BOTNET" = "6.5",
"DBL_ABUSE_MALWARE" = "6.5",
"DBL_ABUSE_PHISH" = "6.5",
"DBL_ABUSE_REDIR" = "5.0",
"DBL_BLOCKED" = "0.0",
"DBL_BLOCKED_OPENRESOLVER" = "0.0",
"DBL_BOTNET" = "7.5",
"DBL_MALWARE" = "7.5",
"DBL_PHISH" = "7.5",
"DBL_SPAM" = "6.5",
"DCC_BULK" = "3.0",
"DIRECT_TO_MX" = "0.0",
"DISPOSABLE_CC" = "0.0",
"DISPOSABLE_ENVFROM" = "0.0",
"DISPOSABLE_FROM" = "0.0",
"DISPOSABLE_REPLYTO" = "0.0",
"DISPOSABLE_TO" = "0.0",
"DKIM_SIGNED" = "0.0",
"DMARC_BAD_POLICY" = "0.5",
"DMARC_DNSFAIL" = "0.0",
"DMARC_NA" = "0.0",
"DMARC_POLICY_ALLOW" = "-0.5",
"DMARC_POLICY_ALLOW_WITH_FAILURES" = "0.0",
"DMARC_POLICY_QUARANTINE" = "1.5",
"DMARC_POLICY_REJECT" = "2.0",
"DMARC_POLICY_SOFTFAIL" = "0.1",
"DNSWL_BLOCKED" = "0.0",
"DWL_DNSWL_BLOCKED" = "0.0",
"DWL_DNSWL_HI" = "-3.5",
"DWL_DNSWL_LOW" = "-1.0",
"DWL_DNSWL_MED" = "-2.0",
"DWL_DNSWL_NONE" = "0.0",
"EMPTY_SUBJECT" = "1.0",
"ENCRYPTED_PGP" = "-0.5",
"ENCRYPTED_SMIME" = "-0.5",
"ENVFROM_INVALID" = "2.0",
"ENVFROM_SERVICE_ACCT" = "1.0",
"EXT_CSS" = "1.0",
"FAKE_REPLY" = "1.0",
"FORGED_RCVD_TRAIL" = "1.0",
"FORGED_RECIPIENTS" = "2.0",
"FORGED_RECIPIENTS_MAILLIST" = "0.0",
"FORGED_SENDER" = "0.3",
"FORGED_SENDER_MAILLIST" = "0.0",
"FREEMAIL_AFF" = "4.0",
"FREEMAIL_CC" = "0.0",
"FREEMAIL_ENVFROM" = "0.0",
"FREEMAIL_FROM" = "0.0",
"FREEMAIL_REPLYTO" = "0.0",
"FREEMAIL_REPLYTO_NEQ_FROM_DOM" = "3.0",
"FREEMAIL_TO" = "0.0",
"FROM_DN_EQ_ADDR" = "1.0",
"FROM_EQ_ENVFROM" = "0.0",
"FROM_EXCESS_BASE64" = "1.5",
"FROM_EXCESS_QP" = "1.2",
"FROM_HAS_DN" = "0.0",
"FROM_INVALID" = "2.0",
"FROM_NAME_EXCESS_SPACE" = "1.0",
"FROM_NAME_HAS_TITLE" = "1.0",
"FROM_NEEDS_ENCODING" = "1.0",
"FROM_NEQ_DISPLAY_NAME" = "4.0",
"FROM_NEQ_ENVFROM" = "0.0",
"FROM_NO_DN" = "0.0",
"FROM_SERVICE_ACCT" = "1.0",
"HACKED_WP_PHISHING" = "4.5",
"HAS_ANON_DOMAIN" = "0.1",
"HAS_ATTACHMENT" = "0.0",
"HAS_DATA_URI" = "0.0",
"HAS_GOOGLE_FIREBASE_URL" = "2.0",
"HAS_GOOGLE_REDIR" = "1.0",
"HAS_GUC_PROXY_URI" = "1.0",
"HAS_IPFS_GATEWAY_URL" = "6.0",
"HAS_LIST_UNSUB" = "-0.01",
"HAS_ONION_URI" = "0.0",
"HAS_ORG_HEADER" = "0.0",
"HAS_PHPMAILER_SIG" = "0.0",
"HAS_REPLYTO" = "0.0",
"HAS_WP_URI" = "0.0",
"HAS_XAW" = "0.0",
"HAS_XOIP" = "0.0",
"HAS_X_ANTIABUSE" = "0.0",
"HAS_X_AS" = "0.0",
"HAS_X_GMSV" = "0.0",
"HAS_X_PHP_SCRIPT" = "0.0",
"HAS_X_POS" = "0.0",
"HAS_X_PRIO_FIVE" = "0.0",
"HAS_X_PRIO_ONE" = "0.0",
"HAS_X_PRIO_THREE" = "0.0",
"HAS_X_PRIO_TWO" = "0.0",
"HAS_X_PRIO_ZERO" = "0.0",
"HAS_X_SOURCE" = "0.0",
"HEADER_EMPTY_DELIMITER" = "1.0",
"HEADER_FORGED_MDN" = "2.0",
"HEADER_RCONFIRM_MISMATCH" = "2.0",
"FROMHOST_NORES_A_OR_MX" = "1.5",
"FROM_BOUNCE" = "0.0",
"HELO_BAREIP" = "3.0",
"HELO_IP_A" = "1.0",
"HELO_NORES_A_OR_MX" = "0.3",
"HELO_NOT_FQDN" = "2.0",
"HELO_IPREV_MISMATCH" = "1.0",
"RCPT_BOUNCEMOREONE" = "1.5",
"URL_ONLY" = "2.2",
"HIDDEN_SOURCE_OBJ" = "2.0",
"HTML_META_REFRESH_URL" = "5.0",
"HTML_SHORT_LINK_IMG_1" = "2.0",
"HTML_SHORT_LINK_IMG_2" = "1.0",
"HTML_SHORT_LINK_IMG_3" = "0.5",
"HTML_TEXT_IMG_RATIO" = "1.0",
"HTML_UNBALANCED_TAG" = "0.5",
"HTTP_TO_HTTPS" = "0.5",
"HTTP_TO_IP" = "1.0",
"INFO_TO_INFO_LU" = "2.0",
"INVALID_DATE" = "1.5",
"INVALID_FROM_8BIT" = "6.0",
"INVALID_MSGID" = "1.7",
"KLMS_SPAM" = "5.0",
"LONG_SUBJ" = "3.0",
"MAILLIST" = "-0.2",
"MANY_INVISIBLE_PARTS" = "1.0",
"MID_BARE_IP" = "2.0",
"MID_CONTAINS_FROM" = "1.0",
"MID_CONTAINS_TO" = "1.0",
"MID_MISSING_BRACKETS" = "1.0",
"MID_RHS_IP_LITERAL" = "1.0",
"MID_RHS_MATCH_FROM" = "1.0",
"MID_RHS_MATCH_FROMTLD" = "1.0",
"MID_RHS_MATCH_TO" = "1.0",
"MID_RHS_NOT_FQDN" = "0.5",
"MID_RHS_WWW" = "0.5",
"MIME_ARCHIVE_IN_ARCHIVE" = "5.0",
"MIME_BAD" = "1.0",
"MIME_BAD_ATTACHMENT" = "4.0",
"MIME_BAD_EXTENSION" = "2.0",
"MIME_BAD_UNICODE" = "8.0",
"MIME_BASE64_TEXT" = "0.1",
"MIME_BASE64_TEXT_BOGUS" = "1.0",
"MIME_DOUBLE_BAD_EXTENSION" = "2.0",
"MIME_GOOD" = "-0.1",
"MIME_HEADER_CTYPE_ONLY" = "2.0",
"MIME_HTML_ONLY" = "0.2",
"MIME_MA_MISSING_HTML" = "1.0",
"MIME_MA_MISSING_TEXT" = "2.0",
"MISSING_DATE" = "1.0",
"MISSING_FROM" = "2.0",
"MISSING_MID" = "2.5",
"MISSING_MIME_VERSION" = "2.0",
"MISSING_SUBJECT" = "2.0",
"MISSING_TO" = "2.0",
"MSBL_EBL" = "7.5",
"MSBL_EBL_GREY" = "0.5",
"MULTIPLE_FROM" = "8.0",
"MULTIPLE_UNIQUE_HEADERS" = "7.0",
"MV_CASE" = "0.5",
"MW_SURBL_MULTI" = "7.5",
"HOMOGRAPH_URL" = "5.0",
"ONCE_RECEIVED" = "0.1",
"PHISHED_OPENPHISH" = "7.0",
"PHISHED_PHISHTANK" = "7.0",
"PHISHING" = "4.0",
"PHISH_EMOTION" = "1.0",
"PHP_XPS_PATTERN" = "0.0",
"PH_SURBL_MULTI" = "7.5",
"PRECEDENCE_BULK" = "0.0",
"PREVIOUSLY_DELIVERED" = "0.0",
"PYZOR" = "3.5",
"RBL_BARRACUDA" = "4.0",
"RBL_BLOCKLISTDE" = "4.0",
"RBL_MAILSPIKE_BAD" = "1.0",
"RBL_MAILSPIKE_VERYBAD" = "1.5",
"RBL_MAILSPIKE_WORST" = "2.0",
"RBL_NIXSPAM" = "4.0",
"RBL_SEM" = "1.0",
"RBL_SEM_IPV6" = "1.0",
"RBL_SENDERSCORE" = "2.0",
"RBL_SPAMCOP" = "4.0",
"RBL_SPAMHAUS" = "0.0",
"RBL_SPAMHAUS_BLOCKED" = "0.0",
"RBL_SPAMHAUS_BLOCKED_OPENRESOLVER" = "0.0",
"RBL_SPAMHAUS_CSS" = "2.0",
"RBL_SPAMHAUS_DROP" = "7.0",
"RBL_SPAMHAUS_PBL" = "2.0",
"RBL_SPAMHAUS_SBL" = "4.0",
"RBL_SPAMHAUS_XBL" = "4.0",
"RBL_VIRUSFREE_BOTNET" = "2.0",
"RCPT_ADDR_IN_SUBJECT" = "3.0",
"RCPT_COUNT_FIVE" = "0.0",
"RCPT_COUNT_GT_50" = "0.0",
"RCPT_COUNT_ONE" = "0.0",
"RCPT_COUNT_SEVEN" = "0.0",
"RCPT_COUNT_THREE" = "0.0",
"RCPT_COUNT_TWELVE" = "0.0",
"RCPT_COUNT_TWO" = "0.0",
"RCPT_COUNT_ZERO" = "0.0",
"RCPT_LOCAL_IN_SUBJECT" = "2.0",
"RCVD_COUNT_FIVE" = "0.0",
"RCVD_COUNT_ONE" = "0.0",
"RCVD_COUNT_SEVEN" = "0.0",
"RCVD_COUNT_THREE" = "0.0",
"RCVD_COUNT_TWELVE" = "0.0",
"RCVD_COUNT_TWO" = "0.0",
"RCVD_COUNT_ZERO" = "0.0",
"RCVD_DKIM_ARC_DNSWL_HI" = "-1.0",
"RCVD_DKIM_ARC_DNSWL_MED" = "-0.5",
"RCVD_DOUBLE_IP_SPAM" = "2.0",
"RCVD_FROM_SMTP_AUTH" = "0.0",
"RCVD_HELO_USER" = "3.0",
"RCVD_ILLEGAL_CHARS" = "4.0",
"RCVD_IN_DNSWL_HI" = "-0.5",
"RCVD_IN_DNSWL_LOW" = "-0.1",
"RCVD_IN_DNSWL_MED" = "-0.2",
"RCVD_IN_DNSWL_NONE" = "0.0",
"RCVD_NO_TLS_LAST" = "0.1",
"RCVD_TLS_ALL" = "0.0",
"RCVD_TLS_LAST" = "0.0",
"RCVD_UNAUTH_PBL" = "2.0",
"RCVD_VIA_SMTP_AUTH" = "0.0",
"RDNS_DNSFAIL" = "0.0",
"RDNS_NONE" = "1.0",
"RECEIVED_BLOCKLISTDE" = "3.0",
"RECEIVED_SPAMHAUS_BLOCKED" = "0.0",
"RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER" = "0.0",
"RECEIVED_SPAMHAUS_CSS" = "1.0",
"RECEIVED_SPAMHAUS_PBL" = "0.0",
"RECEIVED_SPAMHAUS_SBL" = "3.0",
"RECEIVED_SPAMHAUS_XBL" = "1.0",
"REDIRECTOR_URL" = "0.0",
"REDIRECTOR_URL_ONLY" = "1.0",
"REPLYTO_ADDR_EQ_FROM" = "0.0",
"REPLYTO_DN_EQ_FROM_DN" = "0.0",
"REPLYTO_DOM_EQ_FROM_DOM" = "0.0",
"REPLYTO_DOM_NEQ_FROM_DOM" = "0.0",
"REPLYTO_EMAIL_HAS_TITLE" = "2.0",
"REPLYTO_EQ_FROM" = "0.0",
"REPLYTO_EQ_TO_ADDR" = "5.0",
"REPLYTO_EXCESS_BASE64" = "1.5",
"REPLYTO_EXCESS_QP" = "1.2",
"REPLYTO_UNPARSEABLE" = "1.0",
"RWL_MAILSPIKE_EXCELLENT" = "-0.4",
"RWL_MAILSPIKE_GOOD" = "-0.1",
"RWL_MAILSPIKE_NEUTRAL" = "0.0",
"RWL_MAILSPIKE_POSSIBLE" = "0.0",
"RWL_MAILSPIKE_VERYGOOD" = "-0.2",
"R_BAD_CTE_7BIT" = "3.5",
"DKIM_ALLOW" = "-0.2",
"DKIM_NA" = "0.0",
"DKIM_PERMFAIL" = "0.0",
"DKIM_REJECT" = "1.0",
"DKIM_TEMPFAIL" = "0.0",
"R_MISSING_CHARSET" = "0.5",
"R_MIXED_CHARSET" = "5.0",
"MIXED_CHARSET_URL" = "7.0",
"R_NO_SPACE_IN_FROM" = "1.0",
"R_PARTS_DIFFER" = "1.0",
"SPF_ALLOW" = "-0.2",
"SPF_DNSFAIL" = "0.0",
"SPF_FAIL" = "1.0",
"SPF_NA" = "0.0",
"SPF_NEUTRAL" = "0.0",
"SPF_PERMFAIL" = "0.0",
"SPF_SOFTFAIL" = "0.0",
"R_SUSPICIOUS_URL" = "5.0",
"R_UNDISC_RCPT" = "3.0",
"SEM_URIBL" = "3.5",
"SEM_URIBL_FRESH15" = "3.0",
"SIGNED_PGP" = "-2.0",
"SIGNED_SMIME" = "-2.0",
"SORTED_RECIPS" = "3.5",
"SPAM_FLAG" = "5.0",
"SPAM_TRAP" = "discard",
"SPOOF_DISPLAY_NAME" = "8.0",
"SPOOF_REPLYTO" = "6.0",
"SUBJECT_ENDS_EXCLAIM" = "0.0",
"SUBJECT_ENDS_QUESTION" = "1.0",
"SUBJECT_ENDS_SPACES" = "0.5",
"SUBJECT_HAS_CURRENCY" = "1.0",
"SUBJECT_HAS_EXCLAIM" = "0.0",
"SUBJECT_HAS_QUESTION" = "0.0",
"SUBJECT_NEEDS_ENCODING" = "1.0",
"SUBJ_ALL_CAPS" = "3.0",
"SUBJ_BOUNCE_WORDS" = "0.0",
"SUBJ_EXCESS_BASE64" = "1.5",
"SUBJ_EXCESS_QP" = "1.2",
"SURBL_BLOCKED" = "0.0",
"SURBL_HASHBL_ABUSE" = "5.0",
"SURBL_HASHBL_CRACKED" = "5.0",
"SURBL_HASHBL_EMAIL" = "5.0",
"SURBL_HASHBL_MALWARE" = "6.5",
"SURBL_HASHBL_PHISH" = "6.5",
"SUSPICIOUS_RECIPS" = "1.5",
"TAGGED_FROM" = "0.0",
"TAGGED_RCPT" = "0.0",
"THREAD_HIJACKING_FROM_INJECTOR" = "2.0",
"TO_DN_ALL" = "0.0",
"TO_DN_EQ_ADDR_ALL" = "0.0",
"TO_DN_EQ_ADDR_SOME" = "0.0",
"TO_DN_NONE" = "0.0",
"TO_DN_RECIPIENTS" = "2.0",
"TO_DN_SOME" = "0.0",
"TO_DOM_EQ_FROM_DOM" = "0.0",
"TO_EQ_FROM" = "0.0",
"TO_EXCESS_BASE64" = "1.5",
"TO_EXCESS_QP" = "1.2",
"TO_MATCH_ENVRCPT_ALL" = "0.0",
"TO_MATCH_ENVRCPT_SOME" = "0.0",
"TO_NEEDS_ENCODING" = "1.0",
"TO_WRAPPED_IN_SPACES" = "2.0",
"TRUSTED_REPLY" = "-7.0",
"UNDISC_RCPTS_BULK" = "3.0",
"UNITEDINTERNET_SPAM" = "5.0",
"URIBL_BLACK" = "7.5",
"URIBL_BLOCKED" = "0.0",
"URIBL_GREY" = "1.5",
"URIBL_RED" = "3.5",
"URI_COUNT_ODD" = "1.0",
"URI_HIDDEN_PATH" = "1.0",
"URL_IN_SUBJECT" = "4.0",
"URL_REDIRECTOR_NESTED" = "1.0",
"VIOLATED_DIRECT_SPF" = "3.5",
"WP_COMPROMISED" = "0.0",
"WWW_DOT_DOMAIN" = "0.5",
"XM_CASE" = "0.5",
"XM_UA_NO_VERSION" = "0.01",
"X_PHP_EVAL" = "4.0",
"ZERO_WIDTH_SPACE_URL" = "7.0",
"SHORT_PART_BAD_HEADERS" = "7.0",
"MISSING_ESSENTIAL_HEADERS" = "7.0",
"SINGLE_SHORT_PART" = "0.0",
"COMPLETELY_EMPTY" = "7.0"}

View file

@ -1,2 +1 @@
# Spam Trap list
# Messages to addresses listed here are classified as SPAM and rejected by the server.
spam-trap = {}

File diff suppressed because it is too large Load diff

View file

@ -64,13 +64,13 @@ if eval "header.DKIM-Signature.exists" {
}
# Check allowlists
if eval "key_exists('spam/dmarc-allow', from_domain)" {
if eval "key_exists('spam-dmarc', from_domain)" {
if eval "t.DMARC_POLICY_ALLOW" {
let "t.ALLOWLIST_DMARC" "1";
} else {
let "t.BLOCKLIST_DMARC" "1";
}
} elsif eval "key_exists('spam/spf-dkim-allow', from_domain)" {
} elsif eval "key_exists('spam-spdk', from_domain)" {
let "is_dkim_pass" "contains(env.dkim.domains, from_domain) || t.ARC_ALLOW";
if eval "is_dkim_pass && t.SPF_ALLOW" {

View file

@ -16,9 +16,9 @@ if eval "from_count > 0" {
let "t.WWW_DOT_DOMAIN" "1";
}
if eval "key_exists('spam/free-domains', from_domain_sld)" {
if eval "key_exists('spam-free', from_domain_sld)" {
let "t.FREEMAIL_FROM" "1";
} elsif eval "key_exists('spam/disposable-domains', from_domain_sld)" {
} elsif eval "key_exists('spam-disposable', from_domain_sld)" {
let "t.DISPOSABLE_FROM" "1";
}
} else {
@ -125,9 +125,9 @@ if eval "!is_empty(envelope.from)" {
}
if eval "!is_empty(envfrom_domain_sld)" {
if eval "key_exists('spam/free-domains', envfrom_domain_sld)" {
if eval "key_exists('spam-free', envfrom_domain_sld)" {
let "t.FREEMAIL_ENVFROM" "1";
} elsif eval "key_exists('spam/disposable-domains', envfrom_domain_sld)" {
} elsif eval "key_exists('spam-disposable', envfrom_domain_sld)" {
let "t.DISPOSABLE_ENVFROM" "1";
}

View file

@ -186,9 +186,9 @@ foreverypart {
}
let "name_parts" "rsplit(to_lowercase(attach_name), '.')";
if eval "count(name_parts) > 1" {
let "ext_type" "key_get('spam/mime-types', name_parts[0])";
let "ext_type" "key_get('spam-mime', name_parts[0])";
if eval "!is_empty(ext_type)" {
let "ext_type_double" "key_get('spam/mime-types', name_parts[1])";
let "ext_type_double" "key_get('spam-mime', name_parts[1])";
if eval "contains(ext_type, 'BAD')" {
# Bad extension
if eval "contains(ext_type_double, 'BAD')" {

View file

@ -175,7 +175,7 @@ while "i < domains_len" {
if eval "!contains(domain, '.') ||
is_ip_addr(domain) ||
is_local_domain(DOMAIN_DIRECTORY, domain_part(domain, 'sld')) ||
key_exists('spam/domains-allow', domain)" {
key_exists('spam-allow', domain)" {
continue;
}
@ -327,7 +327,7 @@ while "i < urls_len" {
# Skip URLs pointing to local or trusted domains
let "domain" "domain_part(uri_part(url, 'host'), 'sld')";
if eval "is_local_domain(DOMAIN_DIRECTORY, domain) ||
key_exists('spam/domains-allow', domain)" {
key_exists('spam-allow', domain)" {
continue;
}

View file

@ -89,13 +89,13 @@ if eval "rcpt_count > 0" {
# Check for freemail or disposable domains
let "domain" "domain_part(email_part(addr, 'domain'), 'sld')";
if eval "!is_empty(domain)" {
if eval "key_exists('spam/free-domains', domain)" {
if eval "key_exists('spam-free', domain)" {
if eval "!t.FREEMAIL_TO && contains_ignore_case(recipients_to, addr)" {
let "t.FREEMAIL_TO" "1";
} elsif eval "!t.FREEMAIL_CC && contains_ignore_case(recipients_cc, addr)" {
let "t.FREEMAIL_CC" "1";
}
} elsif eval "key_exists('spam/disposable-domains', domain)" {
} elsif eval "key_exists('spam-disposable', domain)" {
if eval "!t.DISPOSABLE_TO && contains_ignore_case(recipients_to, addr)" {
let "t.DISPOSABLE_TO" "1";
} elsif eval "!t.DISPOSABLE_CC && contains_ignore_case(recipients_cc, addr)" {

View file

@ -49,12 +49,12 @@ if eval "!is_empty(rto_raw)" {
let "t.REPLYTO_ADDR_EQ_FROM" "1";
}
if eval "key_exists('spam/free-domains', rto_domain_sld)" {
if eval "key_exists('spam-free', rto_domain_sld)" {
let "t.FREEMAIL_REPLYTO" "1";
if eval "rto_domain_sld != from_domain_sld && key_exists('spam/free-domains', from_domain_sld)" {
if eval "rto_domain_sld != from_domain_sld && key_exists('spam-free', from_domain_sld)" {
let "t.FREEMAIL_REPLYTO_NEQ_FROM_DOM" "1";
}
} elsif eval "key_exists('spam/disposable-domains', rto_domain_sld)" {
} elsif eval "key_exists('spam-disposable', rto_domain_sld)" {
let "t.DISPOSABLE_REPLYTO" "1";
}

View file

@ -5,7 +5,7 @@ let "spam_result" "";
while "i > 0" {
let "i" "i - 1";
let "tag" "tags[i]";
let "tag_score" "key_get('spam/scores', tag)";
let "tag_score" "key_get('spam-scores', tag)";
if eval "is_number(tag_score)" {
let "score" "score + tag_score";

View file

@ -1,6 +1,6 @@
# Check if the message was sent to a spam trap address
if eval "AUTOLEARN_ENABLE && key_exists('spam/trap-address', envelope.to)" {
if eval "AUTOLEARN_ENABLE && key_exists('spam-trap', envelope.to)" {
eval "bayes_is_balanced(SPAM_DB, false, AUTOLEARN_SPAM_HAM_BALANCE) && bayes_train(SPAM_DB, body_and_subject, true)";
let "t.SPAM_TRAP" "1";

View file

@ -27,13 +27,13 @@ while "i > 0" {
let "host_sld" "domain_part(host_lc, 'sld')";
# Skip local and trusted domains
if eval "is_local_domain(DOMAIN_DIRECTORY, host_sld) || key_exists('spam/domains-allow', host_sld)" {
if eval "is_local_domain(DOMAIN_DIRECTORY, host_sld) || key_exists('spam-allow', host_sld)" {
continue;
}
if eval "!is_ip &&
(!t.REDIRECTOR_URL || !t.URL_REDIRECTOR_NESTED) &&
key_exists('spam/redirectors', host_sld)" {
key_exists('spam-redirect', host_sld)" {
let "t.REDIRECTOR_URL" "1";
let "redir_count" "1";
@ -48,7 +48,7 @@ while "i > 0" {
let "host_lc" "to_lowercase(host)";
let "host_sld" "domain_part(host_lc, 'sld')";
if eval "!is_ip && key_exists('spam/redirectors', host_sld)" {
if eval "!is_ip && key_exists('spam-redirect', host_sld)" {
let "redir_count" "redir_count + 1";
} else {
break;

View file

@ -47,7 +47,7 @@ serde = { version = "1.0", features = ["derive"]}
serde_json = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "multipart"]}
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "multipart", "http2"]}
bytes = "1.4.0"
futures = "0.3"
ece = "2.2"

View file

@ -117,7 +117,7 @@ pub async fn test(params: &mut JMAPTest) {
});
// Start mock push server
let mut settings = Config::new(&add_test_certs(SERVER)).unwrap();
let mut settings = Config::new(add_test_certs(SERVER)).unwrap();
settings.resolve_macros().await;
let servers = Servers::parse(&mut settings);

View file

@ -9,7 +9,6 @@ use std::{
use ahash::AHashMap;
use common::{
expr::if_block::IfBlock,
scripts::{
functions::html::{get_attribute, html_attr_tokens, html_img_area, html_to_tokens},
ScriptModification,
@ -19,7 +18,7 @@ use common::{
use mail_auth::{dmarc::Policy, DkimResult, DmarcResult, IprevResult, SpfResult, MX};
use sieve::runtime::Variable;
use smtp::{
core::{Inner, Session, SessionAddress, SMTP},
core::{Inner, Session, SessionAddress},
inbound::AuthResult,
scripts::ScriptResult,
};
@ -27,9 +26,38 @@ use store::Stores;
use tokio::runtime::Handle;
use utils::config::Config;
use crate::smtp::{build_smtp, session::TestSession, TestSMTP};
use crate::smtp::{build_smtp, session::TestSession, TempDir};
const CONFIG: &str = r#"
[spam.header]
add-spam = true
add-spam-result = true
is-spam = "X-Spam-Status: Yes"
[spam.autolearn]
enable = true
#balance = 0.9
balance = 0.0
[spam.autolearn.ham]
replies = true
threshold = -0.5
[spam.autolearn.spam]
threshold = 6.0
[spam.threshold]
spam = 5.0
discard = 0
reject = 0
[spam.data]
directory = ""
lookup = ""
[session.rcpt]
relay = true
[sieve.trusted]
from-name = "Sieve Daemon"
from-addr = "sieve@foobar.org"
@ -45,95 +73,50 @@ cpu = 500000
nested-includes = 5
duplicate-expiry = "7d"
[sieve.trusted.default]
#directory = "%{DEFAULT_DIRECTORY}%"
store = "spamdb"
[storage]
data = "spamdb"
lookup = "spamdb"
blob = "spamdb"
fts = "spamdb"
[store."spamdb"]
type = "sqlite"
path = "%PATH%/test_antispam.db"
path = "{PATH}/test_antispam.db"
#[store."redis"]
#type = "redis"
#url = "redis://127.0.0.1"
[store."default/domains"]
type = "memory"
format = "list"
values = ["local-domain.org"]
[store."spam/free-domains"]
type = "memory"
format = "glob"
comment = '#'
values = ["gmail.com", "googlemail.com", "yahoomail.com", "*.freemail.org"]
[store."spam/disposable-domains"]
type = "memory"
format = "glob"
comment = '#'
values = ["guerrillamail.com", "*.disposable.org"]
[store."spam/redirectors"]
type = "memory"
format = "glob"
comment = '#'
values = ["bit.ly", "redirect.io", "redirect.me", "redirect.org",
"redirect.com", "redirect.net", "t.ly", "tinyurl.com"]
[store."spam/dmarc-allow"]
type = "memory"
format = "glob"
comment = '#'
values = ["dmarc-allow.org"]
[store."spam/spf-dkim-allow"]
type = "memory"
format = "glob"
comment = '#'
values = ["spf-dkim-allow.org"]
[store."spam/domains-allow"]
type = "memory"
format = "glob"
values = []
[store."spam/mime-types"]
type = "memory"
format = "map"
comment = '#'
values = ["html text/html|BAD",
"pdf application/pdf|NZ",
"txt text/plain|message/disposition-notification|text/rfc822-headers",
"zip AR",
"js BAD|NZ",
"hta BAD|NZ"]
[store."spam/trap-address"]
type = "memory"
format = "glob"
comment = '#'
values = ["spamtrap@*"]
[store."spam/scores"]
type = "memory"
format = "map"
values = "file://%CFG_PATH%/maps/scores.map"
[lookup]
"spam-free" = {"gmail.com", "googlemail.com", "yahoomail.com", "*.freemail.org"}
"spam-disposable" = {"guerrillamail.com", "*.disposable.org"}
"spam-redirect" = {"bit.ly", "redirect.io", "redirect.me", "redirect.org", "redirect.com", "redirect.net", "t.ly", "tinyurl.com"}
"spam-dmarc" = {"dmarc-allow.org"}
"spam-spdk" = {"spf-dkim-allow.org"}
"spam-mime" = { "html" = "text/html|BAD",
"pdf" = "application/pdf|NZ",
"txt" = "text/plain|message/disposition-notification|text/rfc822-headers",
"zip" = "AR",
"js" = "BAD|NZ",
"hta" = "BAD|NZ" }
"spam-trap" = {"spamtrap@*"}
"spam-allow" = {"stalw.art"}
[resolver]
public-suffix = "file://%LIST_PATH%/public-suffix.dat"
public-suffix = "file://{LIST_PATH}/public-suffix.dat"
[sieve.trusted.scripts]
"#;
#[tokio::test(flavor = "multi_thread")]
async fn antispam() {
/*tracing::subscriber::set_global_default(
/*let disable = true;
tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(
tracing_subscriber::EnvFilter::builder()
.parse(
"smtp=debug,imap=debug,jmap=debug,store=debug,utils=debug,directory=debug",
"smtp=debug,imap=debug,jmap=debug,store=debug,utils=debug,directory=debug,common=debug",
)
.unwrap(),
)
@ -166,8 +149,7 @@ async fn antispam() {
"reputation",
"pyzor",
];
let mut inner = Inner::default();
let qr = inner.init_test_queue("smtp_antispam_test");
let tmp_dir = TempDir::new("smtp_antispam_test", true);
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
@ -176,24 +158,19 @@ async fn antispam() {
.join("config")
.join("spamfilter");
let mut config = CONFIG
.replace("%PATH%", qr._temp_dir.temp_dir.as_path().to_str().unwrap())
.replace("{PATH}", tmp_dir.temp_dir.as_path().to_str().unwrap())
.replace(
"%LIST_PATH%",
"{LIST_PATH}",
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("resources")
.join("smtp")
.join("lists")
.to_str()
.unwrap(),
)
.replace("%CFG_PATH%", base_path.as_path().to_str().unwrap());
let base_path = base_path.join("scripts");
let script_config = fs::read_to_string(base_path.join("config.sieve"))
.unwrap()
.replace(
"AUTOLEARN_SPAM_HAM_BALANCE\" \"0.9",
"AUTOLEARN_SPAM_HAM_BALANCE\" \"0.0",
);
let scores = fs::read_to_string(base_path.join("maps").join("scores.map")).unwrap();
let base_path = base_path.join("scripts");
let script_config = fs::read_to_string(base_path.join("config.sieve")).unwrap();
let script_prelude = fs::read_to_string(base_path.join("prelude.sieve")).unwrap();
let mut all_scripts = script_config.clone() + "\n" + script_prelude.as_str();
for test_name in tests {
@ -214,7 +191,7 @@ async fn antispam() {
}
config.push_str(&format!(
"{test_name} = '''{script_config}\n{script_prelude}\n{script}\n'''\n"
"{test_name}.contents = '''{script_config}\n{script_prelude}\n{script}\n'''\n"
));
}
for test_name in ["composites", "scores", "epilogue"] {
@ -225,15 +202,16 @@ async fn antispam() {
.as_str();
}
config.push_str(&format!("combined = '''{all_scripts}\n'''\n"));
config.push_str(&format!(
"combined.contents = '''{all_scripts}\n'''\n[lookup]\n"
));
config.push_str(&scores);
// Parse config
let mut config = Config::new(&config).unwrap();
config.resolve_macros().await;
let stores = Stores::parse(&mut config).await;
let mut core = Core::parse(&mut config, stores).await;
let config = &mut core.smtp.session;
config.rcpt.relay = IfBlock::new(true);
qr.set_core_stores(&mut core);
let core = Core::parse(&mut config, stores).await;
// Add mock DNS entries
for (domain, ip) in [

View file

@ -37,7 +37,7 @@ use smtp::{
use super::{QueueReceiver, ReportReceiver};
//pub mod antispam;
pub mod antispam;
pub mod auth;
pub mod basic;
pub mod data;
@ -85,7 +85,6 @@ impl QueueReceiver {
pub async fn assert_report_is_empty(&self) {
assert_eq!(self.read_report_events().await, vec![]);
let todo = "fix antispam";
for (from_key, to_key) in [
(

View file

@ -21,29 +21,24 @@
* for more details.
*/
use std::{
sync::Arc,
time::{Duration, Instant},
};
use std::time::{Duration, Instant};
use ahash::{AHashMap, HashMap, HashSet};
use common::{config::server::ServerProtocol, expr::if_block::IfBlock};
use common::config::server::ServerProtocol;
use mail_auth::MX;
use mail_parser::DateTime;
use reqwest::{header::AUTHORIZATION, Method, StatusCode};
use store::Store;
use utils::config::Config;
use crate::smtp::{management::send_manage_request, session::TestSession, TestSMTP};
use crate::smtp::{management::send_manage_request, outbound::TestServer, session::TestSession};
use smtp::{
core::{management::Message, Session, SMTP},
core::management::Message,
queue::{manager::SpawnQueue, QueueId, Status},
};
const DIRECTORY: &str = r#"
const LOCAL: &str = r#"
[storage]
lookup = "dummy"
directory = "local"
[directory."local"]
type = "memory"
@ -53,8 +48,28 @@ name = "admin"
type = "admin"
description = "Superuser"
secret = "secret"
member-of = ["superusers"]
class = "admin"
[queue.schedule]
retry = "1000s"
notify = "2000s"
expire = "3000s"
[session.rcpt]
relay = true
max-recipients = 100
[session.extensions]
dsn = true
future-release = "1h"
"#;
const REMOTE: &str = r#"
[session.ehlo]
reject-non-fqdn = false
[session.rcpt]
relay = true
"#;
#[derive(serde::Deserialize)]
@ -69,23 +84,22 @@ pub(super) struct List<T> {
async fn manage_queue() {
/*tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.with_max_level(tracing::Level::TRACE)
.finish(),
)
.unwrap();*/
// Start remote test server
let mut inner = Inner::default();
let mut core = Core::default();
core.smtp.session.rcpt.relay = IfBlock::new(true);
let mut remote_qr = core.init_test_queue("smtp_manage_queue_remote");
let remote_core = Arc::new(core);
let _rx_remote = start_test_server(remote_core.clone(), &[ServerProtocol::Smtp]);
let mut remote = TestServer::new("smtp_manage_queue_remote", REMOTE, true).await;
let _rx = remote.start(&[ServerProtocol::Smtp]).await;
let remote_core = remote.build_smtp();
// Start local management interface
let local = TestServer::new("smtp_manage_queue_local", LOCAL, true).await;
// Add mock DNS entries
let mut inner = Inner::default();
let mut core = Core::default();
core.smtp.resolvers.dns.mx_add(
let core = local.build_smtp();
core.core.smtp.resolvers.dns.mx_add(
"foobar.org",
vec![MX {
exchanges: vec!["mx1.foobar.org".to_string()],
@ -94,30 +108,13 @@ async fn manage_queue() {
Instant::now() + Duration::from_secs(10),
);
core.smtp.resolvers.dns.ipv4_add(
core.core.smtp.resolvers.dns.ipv4_add(
"mx1.foobar.org",
vec!["127.0.0.1".parse().unwrap()],
Instant::now() + Duration::from_secs(10),
);
// Start local management interface
let directory = Config::new(DIRECTORY)
.unwrap()
.parse_directory(&dummy_stores(), Store::default())
.await
.unwrap();
core.storage.directory = directory.directories.get("local").unwrap().clone();
core.smtp.session.rcpt.relay = IfBlock::new(true);
core.smtp.session.rcpt.max_recipients = IfBlock::new(100);
core.smtp.session.extensions.future_release = IfBlock::new(Duration::from_secs(86400));
core.smtp.session.extensions.dsn = IfBlock::new(true);
core.smtp.queue.retry = IfBlock::new(Duration::from_secs(1000));
core.smtp.queue.notify = IfBlock::new(Duration::from_secs(2000));
core.smtp.queue.expire = IfBlock::new(Duration::from_secs(3000));
let local_qr = core.init_test_queue("smtp_manage_queue_local");
let core = Arc::new(core);
local_qr.queue_rx.spawn(core.clone());
let _rx_manage = start_test_server(core.clone(), &[ServerProtocol::Http]);
let _rx_manage = local.start(&[ServerProtocol::Http]).await;
// Send test messages
let envelopes = HashMap::from_iter([
@ -156,7 +153,8 @@ async fn manage_queue() {
("e", ("bill5@foobar.net", vec!["john@foobar.org"])),
("f", ("", vec!["success@foobar.org", "delay@foobar.org"])),
]);
let mut session = Session::test(build_smtp(core, Inner::default()));
let mut session = local.new_session();
local.qr.queue_rx.spawn(local.instance.clone());
session.data.remote_ip_str = "10.0.0.1".to_string();
session.eval_session_params().await;
session.ehlo("foobar.net").await;
@ -181,7 +179,8 @@ async fn manage_queue() {
// Expect delivery to success@foobar.org
tokio::time::sleep(Duration::from_millis(100)).await;
assert_eq!(
remote_qr
remote
.qr
.consume_message(&remote_core)
.await
.recipients
@ -332,7 +331,8 @@ async fn manage_queue() {
// Expect delivery to john@foobar.org
tokio::time::sleep(Duration::from_millis(100)).await;
assert_eq!(
remote_qr
remote
.qr
.consume_message(&remote_core)
.await
.recipients

View file

@ -24,10 +24,7 @@
use std::sync::Arc;
use ahash::{AHashMap, HashSet};
use common::{
config::{server::ServerProtocol, smtp::report::AggregateFrequency},
expr::if_block::IfBlock,
};
use common::config::{server::ServerProtocol, smtp::report::AggregateFrequency};
use mail_auth::{
common::parse::TxtRecordParser,
@ -39,19 +36,19 @@ use mail_auth::{
},
};
use reqwest::Method;
use store::Store;
use tokio::sync::mpsc;
use utils::config::Config;
use crate::smtp::management::{queue::List, send_manage_request};
use crate::smtp::{
management::{queue::List, send_manage_request},
outbound::TestServer,
};
use smtp::{
core::{management::Report, SMTP},
core::management::Report,
reporting::{scheduler::SpawnReport, DmarcEvent, TlsEvent},
};
const DIRECTORY: &str = r#"
const CONFIG: &str = r#"
[storage]
lookup = "dummy"
directory = "local"
[directory."local"]
type = "memory"
@ -61,8 +58,16 @@ name = "admin"
type = "admin"
description = "Superuser"
secret = "secret"
member-of = ["superusers"]
class = "admin"
[session.rcpt]
relay = true
[report.dmarc.aggregate]
max-size = 1024
[report.tls.aggregate]
max-size = 1024
"#;
#[tokio::test]
@ -76,22 +81,10 @@ async fn manage_reports() {
.unwrap();*/
// Start reporting service
let mut inner = Inner::default();
let mut core = Core::default();
let config = &mut core.smtp.report;
config.dmarc_aggregate.max_size = IfBlock::new(1024);
config.tls.max_size = IfBlock::new(1024);
let directory = Config::new(DIRECTORY)
.unwrap()
.parse_directory(&dummy_stores(), Store::default())
.await
.unwrap();
core.storage.directory = directory.directories.get("local").unwrap().clone();
let (report_tx, report_rx) = mpsc::channel(1024);
core.report.tx = report_tx;
let core = Arc::new(core);
report_rx.spawn(core.clone());
let _rx_manage = start_test_server(core.clone(), &[ServerProtocol::Http]);
let local = TestServer::new("smtp_manage_reports", CONFIG, true).await;
let _rx = local.start(&[ServerProtocol::Http]).await;
let core = local.build_smtp();
local.rr.report_rx.spawn(local.instance.clone());
// Send test reporting events
core.schedule_report(DmarcEvent {

View file

@ -31,12 +31,11 @@ use tokio::sync::mpsc;
pub mod config;
pub mod inbound;
/*
pub mod management;
pub mod queue;
pub mod reporting;*/
pub mod lookup;
pub mod management;
pub mod outbound;
pub mod queue;
pub mod reporting;
pub mod session;
pub struct TempDir {
@ -46,7 +45,6 @@ pub struct TempDir {
impl TempDir {
pub fn new(name: &str, delete: bool) -> TempDir {
let todo = "make sure all includes are there";
let mut temp_dir = std::env::temp_dir();
temp_dir.push(name);
if !temp_dir.exists() {

View file

@ -29,7 +29,10 @@ use std::{
use mail_auth::MX;
use store::write::now;
use crate::smtp::{inbound::TestQueueEvent, outbound::TestServer, session::TestSession};
use crate::smtp::{
inbound::TestQueueEvent, outbound::TestServer, queue::manager::new_message,
session::TestSession,
};
use smtp::queue::{Message, QueueEnvelope};
const CONFIG: &str = r#"
@ -78,25 +81,6 @@ rate = '1/50m'
enable = true
"#;
pub fn new_message(id: u64) -> Message {
let todo = "remove";
Message {
size: 0,
id,
created: 0,
return_path: "sender@foobar.org".to_string(),
return_path_lcase: "".to_string(),
return_path_domain: "foobar.org".to_string(),
recipients: vec![],
domains: vec![],
flags: 0,
env_id: None,
priority: 0,
quota_keys: vec![],
blob_hash: Default::default(),
}
}
#[tokio::test]
async fn throttle_outbound() {
/*tracing::subscriber::set_global_default(

View file

@ -21,19 +21,31 @@
* for more details.
*/
use std::{
sync::Arc,
time::{Duration, Instant},
};
use std::time::{Duration, Instant};
use common::{config::server::ServerProtocol, expr::if_block::IfBlock};
use common::config::server::ServerProtocol;
use mail_auth::MX;
use crate::smtp::{session::TestSession, TestSMTP};
use smtp::{
core::{Session, SMTP},
queue::manager::Queue,
};
use crate::smtp::{outbound::TestServer, session::TestSession};
use smtp::queue::manager::Queue;
const LOCAL: &str = r#"
[session.rcpt]
relay = true
[session.data.limits]
messages = 200
"#;
const REMOTE: &str = r#"
[session.ehlo]
reject-non-fqdn = false
[session.rcpt]
relay = true
"#;
#[tokio::test]
#[serial_test::serial]
@ -47,16 +59,14 @@ async fn concurrent_queue() {
.unwrap();*/
// Start test server
let mut inner = Inner::default();
let mut core = Core::default();
core.smtp.session.rcpt.relay = IfBlock::new(true);
let remote_qr = core.init_test_queue("smtp_concurrent_queue_remote");
let _rx = start_test_server(core.into(), &[ServerProtocol::Smtp]);
let remote = TestServer::new("smtp_concurrent_queue_remote", REMOTE, true).await;
let _rx = remote.start(&[ServerProtocol::Smtp]).await;
let local = TestServer::new("smtp_concurrent_queue_local", LOCAL, true).await;
// Add mock DNS entries
let mut inner = Inner::default();
let mut core = Core::default();
core.smtp.resolvers.dns.mx_add(
let core = local.build_smtp();
core.core.smtp.resolvers.dns.mx_add(
"foobar.org",
vec![MX {
exchanges: vec!["mx.foobar.org".to_string()],
@ -64,17 +74,13 @@ async fn concurrent_queue() {
}],
Instant::now() + Duration::from_secs(100),
);
core.smtp.resolvers.dns.ipv4_add(
core.core.smtp.resolvers.dns.ipv4_add(
"mx.foobar.org",
vec!["127.0.0.1".parse().unwrap()],
Instant::now() + Duration::from_secs(100),
);
let local_qr = core.init_test_queue("smtp_concurrent_queue_local");
core.smtp.session.rcpt.relay = IfBlock::new(true);
core.smtp.session.data.max_messages = IfBlock::new(200);
let core = Arc::new(core);
let mut session = Session::test(build_smtp(core, Inner::default()));
let mut session = local.new_session();
session.data.remote_ip_str = "10.0.0.1".to_string();
session.eval_session_params().await;
session.ehlo("mx.test.org").await;
@ -88,27 +94,28 @@ async fn concurrent_queue() {
// Spawn 20 concurrent queues at different times
for _ in 0..10 {
let core = core.clone();
let local = local.instance.clone();
tokio::spawn(async move {
Queue::new(core).process_events().await;
Queue::new(local).process_events().await;
});
}
tokio::time::sleep(Duration::from_millis(500)).await;
for _ in 0..10 {
let core = core.clone();
let local = local.instance.clone();
tokio::spawn(async move {
Queue::new(core).process_events().await;
Queue::new(local).process_events().await;
});
}
tokio::time::sleep(Duration::from_millis(1500)).await;
local_qr.assert_queue_is_empty().await;
let remote_messages = remote_qr.read_queued_messages().await;
local.qr.assert_queue_is_empty().await;
let remote_messages = remote.qr.read_queued_messages().await;
assert_eq!(remote_messages.len(), 100);
// Make sure local store is queue
core.storage
core.core
.storage
.data
.assert_is_empty(core.storage.blob.clone())
.assert_is_empty(core.core.storage.blob.clone())
.await;
}

View file

@ -27,12 +27,28 @@ use smtp_proto::{Response, RCPT_NOTIFY_DELAY, RCPT_NOTIFY_FAILURE, RCPT_NOTIFY_S
use store::write::now;
use utils::BlobHash;
use crate::smtp::{inbound::sign::TextConfigContext, QueueReceiver, TestSMTP};
use smtp::{
core::SMTP,
queue::{Domain, Error, ErrorDetails, HostResponse, Message, Recipient, Schedule, Status},
use crate::smtp::{inbound::sign::SIGNATURES, outbound::TestServer, QueueReceiver};
use smtp::queue::{
Domain, Error, ErrorDetails, HostResponse, Message, Recipient, Schedule, Status,
};
const CONFIG: &str = r#"
[report]
submitter = "'mx.example.org'"
[session.ehlo]
reject-non-fqdn = false
[session.rcpt]
relay = true
[report.dsn]
from-name = "'Mail Delivery Subsystem'"
from-address = "'MAILER-DAEMON@example.org'"
sign = "['rsa']"
"#;
#[tokio::test]
async fn generate_dsn() {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
@ -91,14 +107,11 @@ async fn generate_dsn() {
let span = tracing::span!(tracing::Level::INFO, "hi");
// Load config
let mut inner = Inner::default();
let mut core = Core::default();
core.storage.signers = ConfigContext::new().parse_signatures().signers;
let config = &mut core.smtp.queue.dsn;
config.sign = "\"['rsa']\"".parse_if();
let mut local = TestServer::new("smtp_dsn_test", CONFIG.to_string() + SIGNATURES, true).await;
let core = local.build_smtp();
let qr = &mut local.qr;
// Create temp dir for queue
let mut qr = core.init_test_queue("smtp_dsn_test");
qr.blob_store
.put_blob(message.blob_hash.as_slice(), dsn_original.as_bytes())
.await

View file

@ -21,24 +21,28 @@
* for more details.
*/
use std::{sync::Arc, time::Duration};
use std::time::Duration;
use mail_auth::hickory_resolver::proto::op::ResponseCode;
use smtp::{
core::SMTP,
queue::{Domain, Message, Schedule, Status},
};
use smtp::queue::{Domain, Message, Schedule, Status};
use store::write::now;
use crate::smtp::TestSMTP;
use crate::smtp::outbound::TestServer;
const CONFIG: &str = r#"
[session.ehlo]
reject-non-fqdn = false
[session.rcpt]
relay = true
"#;
#[tokio::test]
async fn queue_due() {
let mut inner = Inner::default();
let mut core = Core::default();
let qr = core.init_test_queue("smtp_queue_due_test");
let core = Arc::new(core);
let local = TestServer::new("smtp_queue_due_test", CONFIG, true).await;
let core = local.build_smtp();
let qr = &local.qr;
let mut message = new_message(0);
message.domains.push(domain("c", 3, 8, 9));

View file

@ -21,20 +21,35 @@
* for more details.
*/
use std::{sync::Arc, time::Duration};
use std::time::Duration;
use crate::smtp::{
inbound::{TestMessage, TestQueueEvent},
outbound::TestServer,
session::{TestSession, VerifyResponse},
TestSMTP,
};
use common::expr::if_block::IfBlock;
use smtp::{
core::{Session, SMTP},
queue::{DeliveryAttempt, Event},
};
use smtp::queue::{DeliveryAttempt, Event};
use store::write::now;
const CONFIG: &str = r#"
[session.ehlo]
reject-non-fqdn = false
[session.rcpt]
relay = true
[session.extensions]
deliver-by = "1h"
future-release = "1h"
[queue.schedule]
retry = "[1s, 2s, 3s]"
notify = [{if = "sender_domain = 'test.org'", then = "[1s, 2s]"},
{else = ['15h', '22h']}]
expire = [{if = "sender_domain = 'test.org'", then = "6s"},
{else = '1d'}]
"#;
#[tokio::test]
async fn queue_retry() {
/*tracing::subscriber::set_global_default(
@ -44,30 +59,14 @@ async fn queue_retry() {
)
.unwrap();*/
let mut inner = Inner::default();
let mut core = Core::default();
// Create temp dir for queue
let mut qr = core.init_test_queue("smtp_queue_retry_test");
let config = &mut core.smtp.session.rcpt;
config.relay = IfBlock::new(true);
let config = &mut core.smtp.session.extensions;
config.deliver_by = IfBlock::new(Duration::from_secs(86400));
config.future_release = IfBlock::new(Duration::from_secs(86400));
let config = &mut core.smtp.queue;
config.retry = r#""[1s, 2s, 3s]""#.parse_if();
config.notify = r#"[{if = "sender_domain = 'test.org'", then = "[1s, 2s]"},
{else = ['15h', '22h']}]"#
.parse_if();
config.expire = r#"[{if = "sender_domain = 'test.org'", then = "6s"},
{else = '1d'}]"#
.parse_if();
let mut local = TestServer::new("smtp_queue_retry_test", CONFIG, true).await;
// Create test message
let core = Arc::new(core);
let core = local.build_smtp();
let mut session = local.new_session();
let qr = &mut local.qr;
let mut session = Session::test(build_smtp(core, Inner::default()));
session.data.remote_ip_str = "10.0.0.1".to_string();
session.eval_session_params().await;
session.ehlo("mx.test.org").await;
@ -83,7 +82,7 @@ async fn queue_retry() {
assert_eq!(message.domains.first().unwrap().domain, "test.org");
assert_eq!(message.recipients.first().unwrap().address, "john@test.org");
message
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("Content-Type: multipart/report")
.assert_contains("Final-Recipient: rfc822;bill@foobar.org")
@ -140,7 +139,7 @@ async fn queue_retry() {
dsn.next()
.unwrap()
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("<bill@foobar.org> (failed to lookup 'foobar.org'")
.assert_contains("Final-Recipient: rfc822;bill@foobar.org")
@ -148,7 +147,7 @@ async fn queue_retry() {
dsn.next()
.unwrap()
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("<jane@_dns_error.org> (failed to lookup '_dns_error.org'")
.assert_contains("Final-Recipient: rfc822;jane@_dns_error.org")
@ -156,7 +155,7 @@ async fn queue_retry() {
dsn.next()
.unwrap()
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("<jane@_dns_error.org> (failed to lookup '_dns_error.org'")
.assert_contains("Final-Recipient: rfc822;jane@_dns_error.org")
@ -164,7 +163,7 @@ async fn queue_retry() {
dsn.next()
.unwrap()
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("<jane@_dns_error.org> (failed to lookup '_dns_error.org'")
.assert_contains("Final-Recipient: rfc822;jane@_dns_error.org")

View file

@ -21,45 +21,36 @@
* for more details.
*/
use std::{sync::Arc, time::Duration};
use std::time::Duration;
use crate::smtp::{inbound::TestQueueEvent, outbound::TestServer, session::TestSession};
use crate::smtp::{inbound::TestQueueEvent, session::TestSession, TestSMTP};
use common::{config::smtp::report::AddressMatch, expr::if_block::IfBlock};
use smtp::core::{Session, SMTP};
use store::{
write::{ReportClass, ValueClass},
IterateParams, ValueKey,
};
const CONFIG: &str = r#"
[session.rcpt]
relay = true
[session.data.limits]
messages = 100
[report.analysis]
addresses = ["reports@*", "*@dmarc.foobar.org", "feedback@foobar.org"]
forward = false
store = "1s"
"#;
#[tokio::test(flavor = "multi_thread")]
async fn report_analyze() {
let mut inner = Inner::default();
let mut core = Core::default();
// Create temp dir for queue
let mut qr = core.init_test_queue("smtp_analyze_report_test");
let config = &mut core.smtp.session.rcpt;
config.relay = IfBlock::new(true);
let config = &mut core.smtp.session.data;
config.max_messages = IfBlock::new(1024);
let config = &mut core.smtp.report.analysis;
config.addresses = vec![
AddressMatch::StartsWith("reports@".to_string()),
AddressMatch::EndsWith("@dmarc.foobar.org".to_string()),
AddressMatch::Equals("feedback@foobar.org".to_string()),
];
config.forward = false;
config.store = Duration::from_secs(1).into();
//config.store = Duration::from_secs(86400).into();
let mut local = TestServer::new("smtp_analyze_report_test", CONFIG, true).await;
// Create test message
let core = Arc::new(core);
/*let rx_manage = crate::smtp::outbound::start_test_server(
core.clone(),
&[utils::config::ServerProtocol::Http],
);*/
let mut session = Session::test(build_smtp(core, Inner::default()));
let mut session = local.new_session();
let qr = &mut local.qr;
session.data.remote_ip_str = "10.0.0.1".to_string();
session.eval_session_params().await;
session.ehlo("mx.test.org").await;

View file

@ -27,7 +27,7 @@ use std::{
time::{Duration, Instant},
};
use common::{config::smtp::report::AggregateFrequency, expr::if_block::IfBlock};
use common::config::smtp::report::AggregateFrequency;
use mail_auth::{
common::parse::TxtRecordParser,
dmarc::Dmarc,
@ -35,12 +35,31 @@ use mail_auth::{
};
use store::write::QueueClass;
use smtp::reporting::DmarcEvent;
use crate::smtp::{
inbound::{sign::TextConfigContext, TestMessage},
inbound::{sign::SIGNATURES, TestMessage},
outbound::TestServer,
session::VerifyResponse,
TestSMTP,
};
use smtp::{core::SMTP, reporting::DmarcEvent};
const CONFIG: &str = r#"
[session.rcpt]
relay = true
[report]
submitter = "'mx.example.org'"
[report.dmarc.aggregate]
from-name = "'DMARC Report'"
from-address = "'reports@example.org'"
org-name = "'Foobar, Inc.'"
contact-info = "'https://foobar.org/contact'"
send = "daily"
max-size = 4096
sign = "['rsa']"
"#;
#[tokio::test]
async fn report_dmarc() {
@ -52,27 +71,21 @@ async fn report_dmarc() {
.unwrap();*/
// Create scheduler
let mut inner = Inner::default();
let mut core = Core::default();
core.storage.signers = ConfigContext::new().parse_signatures().signers;
let config = &mut core.smtp.report;
config.dmarc_aggregate.sign = "\"['rsa']\"".parse_if();
config.dmarc_aggregate.max_size = IfBlock::new(4096);
config.submitter = IfBlock::new("mx.example.org".to_string());
config.dmarc_aggregate.address = IfBlock::new("reports@example.org".to_string());
config.dmarc_aggregate.org_name = IfBlock::new("Foobar, Inc.".to_string());
config.dmarc_aggregate.contact_info = IfBlock::new("https://foobar.org/contact".to_string());
let mut local = TestServer::new(
"smtp_report_dmarc_test",
CONFIG.to_string() + SIGNATURES,
true,
)
.await;
// Authorize external report for foobar.org
core.smtp.resolvers.dns.txt_add(
let core = local.build_smtp();
core.core.smtp.resolvers.dns.txt_add(
"foobar.org._report._dmarc.foobar.net",
Dmarc::parse(b"v=DMARC1;").unwrap(),
Instant::now() + Duration::from_secs(10),
);
// Create temp dir for queue
let mut qr = core.init_test_queue("smtp_report_dmarc_test");
let core = Arc::new(core);
let qr = &mut local.qr;
// Schedule two events with a same policy and another one with a different policy
let dmarc_record = Arc::new(
@ -129,7 +142,7 @@ async fn report_dmarc() {
);
assert_eq!(message.return_path, "reports@example.org");
message
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("DKIM-Signature: v=1; a=rsa-sha256; s=rsa; d=example.com;")
.assert_contains("To: <reports@foobar.net>")
@ -137,7 +150,7 @@ async fn report_dmarc() {
.assert_contains("Submitter: mx.example.org");
// Verify generated report
let report = Report::parse_rfc5322(message.read_message(&qr).await.as_bytes()).unwrap();
let report = Report::parse_rfc5322(message.read_message(qr).await.as_bytes()).unwrap();
assert_eq!(report.domain(), "foobar.org");
assert_eq!(report.email(), "reports@example.org");
assert_eq!(report.org_name(), "Foobar, Inc.");

View file

@ -23,7 +23,7 @@
use std::sync::Arc;
use common::{config::smtp::report::AggregateFrequency, expr::if_block::IfBlock};
use common::config::smtp::report::AggregateFrequency;
use mail_auth::{
common::parse::TxtRecordParser,
dmarc::{Dmarc, URI},
@ -32,11 +32,21 @@ use mail_auth::{
};
use store::write::QueueClass;
use crate::smtp::TestSMTP;
use smtp::{
core::SMTP,
reporting::{dmarc::DmarcFormat, DmarcEvent, PolicyType, TlsEvent},
};
use crate::smtp::outbound::TestServer;
use smtp::reporting::{dmarc::DmarcFormat, DmarcEvent, PolicyType, TlsEvent};
const CONFIG: &str = r#"
[session.rcpt]
relay = true
[report.dmarc.aggregate]
max-size = 500
send = "daily"
[report.tls.aggregate]
max-size = 550
send = "daily"
"#;
#[tokio::test]
async fn report_scheduler() {
@ -48,12 +58,9 @@ async fn report_scheduler() {
.unwrap();*/
// Create scheduler
let mut inner = Inner::default();
let mut core = Core::default();
let qr = core.init_test_queue("smtp_report_queue_test");
let config = &mut core.smtp.report;
config.dmarc_aggregate.max_size = IfBlock::new(500);
config.tls.max_size = IfBlock::new(550);
let local = TestServer::new("smtp_report_queue_test", CONFIG, true).await;
let core = local.build_smtp();
let qr = &local.qr;
// Schedule two events with a same policy and another one with a different policy
let dmarc_record =

View file

@ -23,7 +23,7 @@
use std::{io::Read, sync::Arc, time::Duration};
use common::{config::smtp::report::AggregateFrequency, expr::if_block::IfBlock};
use common::config::smtp::report::AggregateFrequency;
use mail_auth::{
common::parse::TxtRecordParser,
flate2::read::GzDecoder,
@ -32,41 +32,50 @@ use mail_auth::{
};
use store::write::QueueClass;
use smtp::reporting::{tls::TLS_HTTP_REPORT, TlsEvent};
use crate::smtp::{
inbound::{sign::TextConfigContext, TestMessage},
inbound::{sign::SIGNATURES, TestMessage},
outbound::TestServer,
session::VerifyResponse,
TestSMTP,
};
use smtp::{
core::SMTP,
reporting::{tls::TLS_HTTP_REPORT, TlsEvent},
};
const CONFIG: &str = r#"
[session.rcpt]
relay = true
[report]
submitter = "'mx.example.org'"
[report.tls.aggregate]
from-name = "'Report Subsystem'"
from-address = "'reports@example.org'"
org-name = "'Foobar, Inc.'"
contact-info = "'https://foobar.org/contact'"
send = "daily"
max-size = 1532
sign = "['rsa']"
"#;
#[tokio::test]
async fn report_tls() {
/*let disable = "true";
tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.with_max_level(tracing::Level::TRACE)
.finish(),
)
.unwrap();*/
// Create scheduler
let mut inner = Inner::default();
let mut core = Core::default();
core.storage.signers = ConfigContext::new().parse_signatures().signers;
let config = &mut core.smtp.report;
config.tls.sign = "\"['rsa']\"".parse_if();
config.tls.max_size = IfBlock::new(1532);
config.submitter = IfBlock::new("mx.example.org".to_string());
config.tls.address = IfBlock::new("reports@example.org".to_string());
config.tls.org_name = IfBlock::new("Foobar, Inc.".to_string());
config.tls.contact_info = IfBlock::new("https://foobar.org/contact".to_string());
// Create temp dir for queue
let mut qr = core.init_test_queue("smtp_report_tls_test");
let core = Arc::new(core);
let mut local = TestServer::new(
"smtp_report_tls_test",
CONFIG.to_string() + SIGNATURES,
true,
)
.await;
let core = local.build_smtp();
let qr = &mut local.qr;
// Schedule TLS reports to be delivered via email
let tls_record = Arc::new(TlsRpt::parse(b"v=TLSRPTv1;rua=mailto:reports@foobar.org").unwrap());
@ -138,7 +147,7 @@ async fn report_tls() {
);
assert_eq!(message.return_path, "reports@example.org");
message
.read_lines(&qr)
.read_lines(qr)
.await
.assert_contains("DKIM-Signature: v=1; a=rsa-sha256; s=rsa; d=example.com;")
.assert_contains("To: <reports@foobar.org>")
@ -146,7 +155,7 @@ async fn report_tls() {
.assert_contains("Submitter: mx.example.org");
// Verify generated report
let report = TlsReport::parse_rfc5322(message.read_message(&qr).await.as_bytes()).unwrap();
let report = TlsReport::parse_rfc5322(message.read_message(qr).await.as_bytes()).unwrap();
assert_eq!(report.organization_name.unwrap(), "Foobar, Inc.");
assert_eq!(report.contact_info.unwrap(), "https://foobar.org/contact");
assert_eq!(report.policies.len(), 3);
@ -166,10 +175,10 @@ async fn report_tls() {
}
PolicyType::Sts => {
seen[1] = true;
assert_eq!(policy.summary.total_failure, 3);
assert_eq!(policy.summary.total_failure, 2);
assert_eq!(policy.summary.total_success, 0);
assert_eq!(policy.policy.policy_domain, "foobar.org");
assert_eq!(policy.failure_details.len(), 3);
assert_eq!(policy.failure_details.len(), 2);
assert!(policy
.failure_details
.iter()
@ -181,10 +190,10 @@ async fn report_tls() {
}
PolicyType::NoPolicyFound => {
seen[2] = true;
assert_eq!(policy.summary.total_failure, 0);
assert_eq!(policy.summary.total_failure, 1);
assert_eq!(policy.summary.total_success, 2);
assert_eq!(policy.policy.policy_domain, "foobar.org");
assert_eq!(policy.failure_details.len(), 0);
assert_eq!(policy.failure_details.len(), 1);
/*assert_eq!(
policy.failure_details.first().unwrap().result_type,
ResultType::CertificateExpired