git subrepo clone https://github.com/mailcow/mailcow-dockerized.git mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "a832becb"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "a832becb"
git-subrepo: version: "0.4.3"
origin: "???"
commit: "???"
Change-Id: If5be2d621a211e164c9b6577adaa7884449f16b5
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/actions.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/actions.conf
new file mode 100644
index 0000000..3de63a5
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/actions.conf
@@ -0,0 +1,3 @@
+reject = 15;
+add_header = 8;
+greylist = 7;
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/antivirus.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/antivirus.conf
new file mode 100644
index 0000000..c8d31d1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/antivirus.conf
@@ -0,0 +1,11 @@
+clamav {
+ # Scan whole message
+ scan_mime_parts = false;
+ #scan_text_mime = true;
+ #scan_image_mime = true;
+ symbol = "CLAM_VIRUS";
+ type = "clamav";
+ log_clean = true;
+ servers = "clamd:3310";
+ max_size = 20971520;
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/arc.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/arc.conf
new file mode 100644
index 0000000..a857fc4
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/arc.conf
@@ -0,0 +1,32 @@
+# If false, messages with empty envelope from are not signed
+allow_envfrom_empty = true;
+# If true, envelope/header domain mismatch is ignored
+allow_hdrfrom_mismatch = true;
+# If true, multiple from headers are allowed (but only first is used)
+allow_hdrfrom_multiple = false;
+# If true, username does not need to contain matching domain
+allow_username_mismatch = false;
+# If false, messages from authenticated users are not selected for signing
+sign_authenticated = false;
+# Default path to key, can include '$domain' and '$selector' variables
+path = "/data/dkim/keys/$domain.dkim";
+# Default selector to use
+selector = "dkim";
+# If false, messages from local networks are not selected for signing
+sign_local = false;
+# Symbol to add when message is signed
+symbol = "ARC_SIGNED";
+# Whether to fallback to global config
+try_fallback = true;
+# Domain to use for DKIM signing: can be "header" or "envelope"
+use_domain = "recipient";
+# Whether to normalise domains to eSLD
+use_esld = false;
+# Whether to get keys from Redis
+use_redis = true;
+# Hash for DKIM keys in Redis
+key_prefix = "DKIM_PRIV_KEYS";
+# Selector map
+selector_prefix = "DKIM_SELECTORS";
+sign_inbound = true;
+use_domain_sign_inbound = "recipient";
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/asn.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/asn.conf
new file mode 100644
index 0000000..42b6780
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/asn.conf
@@ -0,0 +1,6 @@
+provider_type = "rspamd";
+provider_info {
+ ip4 = "asn.rspamd.com";
+ ip6 = "asn6.rspamd.com";
+}
+symbol = "ASN";
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/composites.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/composites.conf
new file mode 100644
index 0000000..13c977c
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/composites.conf
@@ -0,0 +1,51 @@
+MX_IMPLICIT {
+ expression = "MX_GOOD & MX_MISSING";
+ score = -0.01;
+}
+VIRUS_FOUND {
+ expression = "CLAM_VIRUS & !MAILCOW_WHITE";
+ score = 2000.0;
+}
+# Bad policy from free mail providers
+FREEMAIL_POLICY_FAILURE {
+ expression = "-g+:policies & !DMARC_POLICY_ALLOW & !MAILLIST & ( FREEMAIL_ENVFROM | FREEMAIL_FROM ) & !WHITELISTED_FWD_HOST";
+ score = 16.0;
+}
+# Bad policy from non-whitelisted senders
+# Remove SOGO_CONTACT symbol for fwd hosts and senders with broken policy
+SOGO_CONTACT_EXCLUDE {
+ expression = "(-WHITELISTED_FWD_HOST | -g+:policies) & ^SOGO_CONTACT & !DMARC_POLICY_ALLOW";
+}
+# Spoofed header from and broken policy (excluding sieve host, rspamd host, whitelisted senders, authenticated senders and forward hosts)
+SPOOFED_UNAUTH {
+ expression = "!MAILCOW_AUTH & !MAILCOW_WHITE & !RSPAMD_HOST & !SIEVE_HOST & MAILCOW_DOMAIN_HEADER_FROM & !WHITELISTED_FWD_HOST & -g+:policies";
+ score = 50.0;
+}
+# Only apply to inbound unauthed and not whitelisted
+OLEFY_MACRO {
+ expression = "!MAILCOW_AUTH & !MAILCOW_WHITE & OLETOOLS";
+ score = 20.0;
+ policy = "remove_weight";
+}
+# Applies to a content filter map
+BAD_WORD_BAD_TLD {
+ expression = "FISHY_TLD & ( BAD_WORDS | BAD_WORDS_DE )"
+ score = 10.0;
+}
+# Forged with bad policies and not fwd host, keep bad policy symbols
+FORGED_W_BAD_POLICY {
+ expression = "( -g+:policies | -R_SPF_NA) & ( ~FROM_NEQ_ENVFROM | ~FORGED_SENDER ) & !WHITELISTED_FWD_HOST & !DMARC_POLICY_ALLOW"
+ score = 3.0;
+}
+# Keep negative (good) scores for rbl, policies and hfilter, disable neural group
+WL_FWD_HOST {
+ expression = "-WHITELISTED_FWD_HOST & (^g+:rbl | ^g+:policies | ^g+:hfilter | ^g:neural)"
+}
+# Exclude X-Spam like flags from scoring from fwd and sieve hosts
+UPSTREAM_CHECKS_EXCLUDE_FWD_HOST {
+ expression = "(-SIEVE_HOST | -WHITELISTED_FWD_HOST) & (^UNITEDINTERNET_SPAM | ^SPAM_FLAG | ^KLMS_SPAM | ^AOL_SPAM | ^MICROSOFT_SPAM)"
+}
+# Remove fuzzy group from bounces
+BOUNCE_FUZZY {
+ expression = "-BOUNCE & ^g+:fuzzy";
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/dkim_signing.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/dkim_signing.conf
new file mode 100644
index 0000000..13eb094
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/dkim_signing.conf
@@ -0,0 +1,35 @@
+# If false, messages with empty envelope from are not signed
+allow_envfrom_empty = true;
+# If true, envelope/header domain mismatch is ignored
+allow_hdrfrom_mismatch = true;
+# If true, multiple from headers are allowed (but only first is used)
+allow_hdrfrom_multiple = true;
+# If true, username does not need to contain matching domain
+allow_username_mismatch = true;
+# If false, messages from authenticated users are not selected for signing
+sign_authenticated = true;
+# Default path to key, can include '$domain' and '$selector' variables
+path = "/data/dkim/keys/$domain.dkim";
+# Default selector to use
+selector = "dkim";
+# If false, messages from local networks are not selected for signing
+sign_local = true;
+# Symbol to add when message is signed
+symbol = "DKIM_SIGNED";
+# Whether to fallback to global config
+try_fallback = true;
+# Domain to use for DKIM signing: can be "header" or "envelope"
+use_domain = "envelope";
+# Whether to normalise domains to eSLD
+use_esld = false;
+# Whether to get keys from Redis
+use_redis = true;
+# Hash for DKIM keys in Redis
+key_prefix = "DKIM_PRIV_KEYS";
+# Selector map
+selector_prefix = "DKIM_SELECTORS";
+# Sieve is in sign_networks only
+# forwards are arc signed, rejects are dkim signed
+sign_networks = "/etc/rspamd/custom/dovecot_trusted.map";
+use_domain_sign_networks = "header";
+sign_headers = "from:sender:reply-to:subject:date:message-id:to:cc:mime-version:content-type:content-transfer-encoding:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:in-reply-to:references:list-id:list-help:list-owner:list-unsubscribe:list-subscribe:list-post:openpgp:autocrypt";
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/external_services.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/external_services.conf
new file mode 100644
index 0000000..f05314b
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/external_services.conf
@@ -0,0 +1,9 @@
+oletools {
+ # default olefy settings
+ servers = "olefy:10055";
+ # needs to be set explicitly for Rspamd < 1.9.5
+ scan_mime_parts = true;
+ # mime-part regex matching in content-type or filename
+ # block all macros
+ extended = true;
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/force_actions.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/force_actions.conf
new file mode 100644
index 0000000..a1b9899
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/force_actions.conf
@@ -0,0 +1,12 @@
+rules {
+ WHITELIST_FORWARDING_HOST_NO_REJECT {
+ action = "add header";
+ expression = "WHITELISTED_FWD_HOST";
+ require_action = ["reject"];
+ }
+ WHITELIST_FORWARDING_HOST_NO_GREYLIST {
+ action = "no action";
+ expression = "WHITELISTED_FWD_HOST";
+ require_action = ["greylist", "soft reject"];
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/fuzzy_check.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/fuzzy_check.conf
new file mode 100644
index 0000000..855e8d0
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/fuzzy_check.conf
@@ -0,0 +1,54 @@
+rule "local" {
+ # Fuzzy storage server list
+ servers = "localhost:11445";
+ # Default symbol for unknown flags
+ symbol = "LOCAL_FUZZY_UNKNOWN";
+ # Additional mime types to store/check
+ mime_types = ["application/*"];
+ # Hash weight threshold for all maps
+ max_score = 100.0;
+ # Whether we can learn this storage
+ read_only = no;
+ # Ignore unknown flags
+ skip_unknown = yes;
+ # Hash generation algorithm
+ algorithm = "mumhash";
+
+ # Map flags to symbols
+ fuzzy_map = {
+ LOCAL_FUZZY_DENIED {
+ max_score = 10.0;
+ flag = 11;
+ }
+ LOCAL_FUZZY_WHITE {
+ max_score = 5.0;
+ flag = 13;
+ }
+ }
+}
+
+rule "mailcow" {
+ # Fuzzy storage server list
+ servers = "fuzzy.mailcow.email:11445";
+ # Default symbol for unknown flags
+ symbol = "MAILCOW_FUZZY_UNKNOWN";
+ # Additional mime types to store/check
+ mime_types = ["application/*"];
+ # Hash weight threshold for all maps
+ max_score = 100.0;
+ # Whether we can learn this storage
+ read_only = yes;
+ # Ignore unknown flags
+ skip_unknown = yes;
+ # Hash generation algorithm
+ algorithm = "mumhash";
+ # Encrypt connection
+ encryption_key = "oa7xjgdr9u7w3hq1xbttas6brgau8qc17yi7ur5huaeq6paq8h4y";
+ # Map flags to symbols
+ fuzzy_map = {
+ MAILCOW_FUZZY_DENIED {
+ max_score = 10.0;
+ flag = 11;
+ }
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/fuzzy_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/fuzzy_group.conf
new file mode 100644
index 0000000..561ac4e
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/fuzzy_group.conf
@@ -0,0 +1,17 @@
+symbols = {
+ "LOCAL_FUZZY_UNKNOWN" {
+ weight = 0.1;
+ }
+ "LOCAL_FUZZY_DENIED" {
+ weight = 15.0;
+ }
+ "MAILCOW_FUZZY_UNKNOWN" {
+ weight = 0.1;
+ }
+ "MAILCOW_FUZZY_DENIED" {
+ weight = 7.0;
+ }
+ "LOCAL_FUZZY_WHITE" {
+ weight = -10.0;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/greylist.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/greylist.conf
new file mode 100644
index 0000000..c43c907
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/greylist.conf
@@ -0,0 +1,4 @@
+whitelisted_ip = "http://nginx:8081/forwardinghosts.php";
+ipv4_mask = 24;
+ipv6_mask = 64;
+message = "Greylisted, please try again later";
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/groups.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/groups.conf
new file mode 100644
index 0000000..ef599ef
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/groups.conf
@@ -0,0 +1,50 @@
+symbols {
+ "MAILCOW_AUTH" {
+ description = "mailcow authenticated";
+ score = -20.0;
+ }
+ "CTYPE_MIXED_BOGUS" {
+ score = 0.0;
+ }
+ "BAD_REP_POLICIES" {
+ score = 2.0;
+ }
+ "BULK_HEADER" {
+ score = 4.0;
+ }
+}
+
+group "MX" {
+ "MX_INVALID" {
+ score = 0.5;
+ description = "No connectable MX";
+ one_shot = true;
+ }
+ "MX_MISSING" {
+ score = 2.0;
+ description = "No MX record";
+ one_shot = true;
+ }
+ "MX_GOOD" {
+ score = -0.01;
+ description = "MX was ok";
+ one_shot = true;
+ }
+}
+
+group "reputation" {
+ symbols = {
+ "IP_REPUTATION_HAM" {
+ weight = 1.0;
+ }
+ "IP_REPUTATION_SPAM" {
+ weight = 4.0;
+ }
+ "SENDER_REP_HAM" {
+ weight = 1.0;
+ }
+ "SENDER_REP_SPAM" {
+ weight = 2.0;
+ }
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/headers_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/headers_group.conf
new file mode 100644
index 0000000..1df92b5
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/headers_group.conf
@@ -0,0 +1,7 @@
+symbols = {
+ "R_MIXED_CHARSET" {
+ weight = 1.0;
+ description = "Mixed characters in a message";
+ one_shot = true;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/hfilter_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/hfilter_group.conf
new file mode 100644
index 0000000..3c908c5
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/hfilter_group.conf
@@ -0,0 +1,5 @@
+symbols = {
+ "HFILTER_HOSTNAME_UNKNOWN" {
+ score = 8.5;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/history_redis.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/history_redis.conf
new file mode 100644
index 0000000..68a59b0
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/history_redis.conf
@@ -0,0 +1 @@
+nrows = 1000;
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/metadata_exporter.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/metadata_exporter.conf
new file mode 100644
index 0000000..f29f480
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/metadata_exporter.conf
@@ -0,0 +1,72 @@
+rules {
+ QUARANTINE {
+ backend = "http";
+ url = "http://nginx:9081/pipe.php";
+ selector = "reject_no_global_bl";
+ formatter = "default";
+ meta_headers = true;
+ }
+ RLINFO {
+ backend = "http";
+ url = "http://nginx:9081/pipe_rl.php";
+ selector = "ratelimited";
+ formatter = "json";
+ }
+ PUSHOVERMAIL {
+ backend = "http";
+ url = "http://nginx:9081/pushover.php";
+ selector = "mailcow_rcpt";
+ # Only return msgid, do not parse the full message
+ formatter = "msgid";
+ meta_headers = true;
+ }
+}
+
+custom_select {
+ mailcow_rcpt = <<EOD
+return function(task)
+ local action = task:get_metric_action('default')
+ if task:has_symbol('NO_LOG_STAT') or (action == 'reject' or action == 'add header' or action == 'rewrite subject') then
+ return false
+ else
+ if task:get_symbol("RCPT_MAILCOW_DOMAIN") then
+ return true
+ end
+ return false
+ end
+end
+EOD;
+ ratelimited = <<EOD
+return function(task)
+ local ratelimited = task:get_symbol("RATELIMITED")
+ if ratelimited then
+ return true
+ end
+ return false
+end
+EOD;
+ reject_no_global_bl = <<EOD
+return function(task)
+ if not task:has_symbol('GLOBAL_SMTP_FROM_BL')
+ and not task:has_symbol('GLOBAL_MIME_FROM_BL')
+ and not task:has_symbol('LOCAL_BL_ASN')
+ and not task:has_symbol('GLOBAL_RCPT_BL')
+ and not task:has_symbol('MAILCOW_BLACK') then
+ local action = task:get_metric_action('default')
+ if action == 'reject' or action == 'add header' or action == 'rewrite subject' then
+ return true
+ end
+ end
+ return false
+end
+EOD;
+}
+
+custom_format {
+ msgid = <<EOD
+return function(task)
+ return task:get_message_id()
+end
+EOD;
+}
+
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/milter_headers.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/milter_headers.conf
new file mode 100644
index 0000000..f61c3b9
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/milter_headers.conf
@@ -0,0 +1,43 @@
+use = ["spam-header", "x-spamd-result", "x-rspamd-queue-id", "authentication-results", "fuzzy-hashes"];
+skip_local = false;
+skip_authenticated = true;
+routines {
+ spam-header {
+ header = "X-Spam-Flag";
+ value = "YES";
+ remove = 1;
+ }
+ fuzzy-hashes {
+ header = "X-Rspamd-Fuzzy";
+ }
+ authentication-results {
+ header = "Authentication-Results";
+ add_smtp_user = false;
+ remove = 1;
+ spf_symbols {
+ pass = "R_SPF_ALLOW";
+ fail = "R_SPF_FAIL";
+ softfail = "R_SPF_SOFTFAIL";
+ neutral = "R_SPF_NEUTRAL";
+ temperror = "R_SPF_DNSFAIL";
+ none = "R_SPF_NA";
+ permerror = "R_SPF_PERMFAIL";
+ }
+ dkim_symbols {
+ pass = "R_DKIM_ALLOW";
+ fail = "R_DKIM_REJECT";
+ temperror = "R_DKIM_TEMPFAIL";
+ none = "R_DKIM_NA";
+ permerror = "R_DKIM_PERMFAIL";
+ }
+ dmarc_symbols {
+ pass = "DMARC_POLICY_ALLOW";
+ permerror = "DMARC_BAD_POLICY";
+ temperror = "DMARC_DNSFAIL";
+ none = "DMARC_NA";
+ reject = "DMARC_POLICY_REJECT";
+ softfail = "DMARC_POLICY_SOFTFAIL";
+ quarantine = "DMARC_POLICY_QUARANTINE";
+ }
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mime_types.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mime_types.conf
new file mode 100644
index 0000000..5d82982
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mime_types.conf
@@ -0,0 +1,47 @@
+# Extensions that are treated as 'bad'
+# Number is score multiply factor
+bad_extensions = {
+ scr = 20,
+ lnk = 20,
+ exe = 20,
+ msi = 1,
+ msp = 1,
+ msu = 1,
+ jar = 2,
+ com = 20,
+ bat = 4,
+ cmd = 4,
+ ps1 = 4,
+ ace = 4,
+ arj = 4,
+ cab = 3,
+ vbs = 20,
+ hta = 4,
+ shs = 4,
+ wsc = 4,
+ wsf = 4,
+ iso = 8,
+ img = 8
+};
+
+# Extensions that are particularly penalized for archives
+bad_archive_extensions = {
+ pptx = 0.5,
+ docx = 0.5,
+ xlsx = 0.5,
+ pdf = 1.0,
+ jar = 3,
+ js = 0.5,
+ vbs = 20,
+ exe = 20
+};
+
+# Used to detect another archive in archive
+archive_extensions = {
+ zip = 1,
+ arj = 1,
+ rar = 1,
+ ace = 1,
+ 7z = 1,
+ cab = 1
+};
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mime_types_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mime_types_group.conf
new file mode 100644
index 0000000..b8dae7d
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mime_types_group.conf
@@ -0,0 +1,7 @@
+symbols = {
+ "MIME_DOUBLE_BAD_EXTENSION" {
+ weight = 0; # This rule has dynamic weight up to 4.0
+ description = "Bad extension cloaking";
+ one_shot = true;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/multimap.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/multimap.conf
new file mode 100644
index 0000000..0f05bb5
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/multimap.conf
@@ -0,0 +1,157 @@
+RCPT_MAILCOW_DOMAIN {
+ type = "rcpt";
+ filter = "email:domain";
+ map = "redis://DOMAIN_MAP";
+ symbols_set = ["RCPT_MAILCOW_DOMAIN"];
+}
+
+WHITELISTED_FWD_HOST {
+ type = "ip";
+ map = "redis://WHITELISTED_FWD_HOST";
+ symbols_set = ["WHITELISTED_FWD_HOST"];
+}
+
+BULK_HEADER {
+ type = "content";
+ map = "${LOCAL_CONFDIR}/custom/bulk_header.map";
+ filter = "headers"
+ regexp = true;
+ symbols_set = ["BULK_HEADER"];
+}
+
+LOCAL_BL_ASN {
+ require_symbols = "!MAILCOW_WHITE";
+ type = "asn";
+ map = "${LOCAL_CONFDIR}/custom/bad_asn.map";
+ score = 5;
+ description = "Sender's ASN is on the local blacklist";
+ symbols_set = ["LOCAL_BL_ASN"];
+}
+
+GLOBAL_SMTP_FROM_WL {
+ type = "from";
+ map = "${LOCAL_CONFDIR}/custom/global_smtp_from_whitelist.map";
+ regexp = true;
+ score = -2050;
+}
+
+GLOBAL_SMTP_FROM_BL {
+ type = "from";
+ map = "${LOCAL_CONFDIR}/custom/global_smtp_from_blacklist.map";
+ regexp = true;
+ score = 2050;
+}
+
+GLOBAL_MIME_FROM_WL {
+ type = "header";
+ header = "from";
+ filter = "email:addr";
+ map = "${LOCAL_CONFDIR}/custom/global_mime_from_whitelist.map";
+ regexp = true;
+ score = -2050;
+}
+
+GLOBAL_MIME_FROM_BL {
+ type = "header";
+ header = "from";
+ filter = "email:addr";
+ map = "${LOCAL_CONFDIR}/custom/global_mime_from_blacklist.map";
+ regexp = true;
+ score = 2050;
+}
+
+GLOBAL_RCPT_WL {
+ type = "rcpt";
+ map = "${LOCAL_CONFDIR}/custom/global_rcpt_whitelist.map";
+ regexp = true;
+ prefilter = true;
+ action = "accept";
+}
+
+GLOBAL_RCPT_BL {
+ type = "rcpt";
+ map = "${LOCAL_CONFDIR}/custom/global_rcpt_blacklist.map";
+ regexp = true;
+ prefilter = true;
+ action = "reject";
+}
+
+SIEVE_HOST {
+ type = "ip";
+ map = "${LOCAL_CONFDIR}/custom/dovecot_trusted.map";
+ symbols_set = ["SIEVE_HOST"];
+ score = -15;
+}
+
+RSPAMD_HOST {
+ type = "ip";
+ map = "${LOCAL_CONFDIR}/custom/rspamd_trusted.map";
+ symbols_set = ["RSPAMD_HOST"];
+}
+
+MAILCOW_DOMAIN_HEADER_FROM {
+ type = "header";
+ header = "from";
+ filter = "email:domain";
+ map = "redis://DOMAIN_MAP";
+}
+
+IP_WHITELIST {
+ type = "ip";
+ map = "${LOCAL_CONFDIR}/custom/ip_wl.map";
+ symbols_set = ["IP_WHITELIST"];
+ score = -2050;
+}
+
+FISHY_TLD {
+ type = "from";
+ filter = "email:domain";
+ map = "${LOCAL_CONFDIR}/custom/fishy_tlds.map";
+ regexp = true;
+ score = 0.1;
+}
+
+BAD_WORDS {
+ type = "content";
+ filter = "text";
+ map = "${LOCAL_CONFDIR}/custom/bad_words.map";
+ regexp = true;
+ score = 0.1;
+}
+
+BAD_WORDS_DE {
+ type = "content";
+ filter = "text";
+ map = "${LOCAL_CONFDIR}/custom/bad_words_de.map";
+ regexp = true;
+ score = 0.1;
+}
+
+BAD_LANG {
+ type = 'selector';
+ selector = 'languages';
+ map = "${LOCAL_CONFDIR}/custom/bad_languages.map";
+ symbols_set = ["LANG_FILTER"];
+ regexp = true;
+ score = 5.0;
+}
+
+BAZAR_ABUSE_CH {
+ type = "selector";
+ selector = "attachments(hex,md5)";
+ map = "https://bazaar.abuse.ch/export/txt/md5/recent/";
+ score = 10.0;
+}
+
+URLHAUS_ABUSE_CH {
+ type = "url";
+ filter = "full";
+ map = "https://urlhaus.abuse.ch/downloads/text_online/";
+ score = 10.0;
+}
+
+SMTP_LIMITED_ACCESS {
+ type = "user";
+ map = "redis://SMTP_LIMITED_ACCESS";
+ symbols_set = ["SMTP_LIMITED_ACCESS"];
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mx_check.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mx_check.conf
new file mode 100644
index 0000000..22fcedf
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/mx_check.conf
@@ -0,0 +1,7 @@
+timeout = 8.0;
+symbol_bad_mx = "MX_INVALID";
+symbol_no_mx = "MX_MISSING";
+symbol_good_mx = "MX_GOOD";
+expire = 86400;
+key_prefix = "rmx";
+enabled = true;
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/neural.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/neural.conf
new file mode 100644
index 0000000..f4658db
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/neural.conf
@@ -0,0 +1,24 @@
+rules {
+ "LONG" {
+ train {
+ max_trains = 200;
+ max_usages = 20;
+ max_iterations = 25;
+ learning_rate = 0.01,
+ }
+ symbol_spam = "NEURAL_SPAM_LONG";
+ symbol_ham = "NEURAL_HAM_LONG";
+ ann_expire = 45d;
+ }
+ "SHORT" {
+ train {
+ max_trains = 100;
+ max_usages = 10;
+ max_iterations = 15;
+ learning_rate = 0.01,
+ }
+ symbol_spam = "NEURAL_SPAM_SHORT";
+ symbol_ham = "NEURAL_HAM_SHORT";
+ ann_expire = 7d;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/neural_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/neural_group.conf
new file mode 100644
index 0000000..fca5cec
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/neural_group.conf
@@ -0,0 +1,18 @@
+symbols = {
+ "NEURAL_SPAM_LONG" {
+ weight = 3.7; # sample weight
+ description = "Neural network spam (long)";
+ }
+ "NEURAL_HAM_LONG" {
+ weight = -4.0; # sample weight
+ description = "Neural network ham (long)";
+ }
+ "NEURAL_SPAM_SHORT" {
+ weight = 2.5; # sample weight
+ description = "Neural network spam (short)";
+ }
+ "NEURAL_HAM_SHORT" {
+ weight = -2.0; # sample weight
+ description = "Neural network ham (short)";
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/options.inc b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/options.inc
new file mode 100644
index 0000000..4fbdfba
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/options.inc
@@ -0,0 +1,9 @@
+dns {
+ enable_dnssec = true;
+}
+map_watch_interval = 30s;
+dns {
+ timeout = 4s;
+ retransmits = 2;
+}
+disable_monitoring = true;
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/phishing.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/phishing.conf
new file mode 100644
index 0000000..69be164
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/phishing.conf
@@ -0,0 +1 @@
+phishtank_enabled = false;
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/policies_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/policies_group.conf
new file mode 100644
index 0000000..8799db1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/policies_group.conf
@@ -0,0 +1,23 @@
+symbols = {
+ "ARC_REJECT" {
+ score = 0.01;
+ }
+ "R_SPF_FAIL" {
+ score = 8.0;
+ }
+ "R_SPF_PERMFAIL" {
+ score = 8.0;
+ }
+ "R_DKIM_REJECT" {
+ score = 8.0;
+ }
+ "DMARC_POLICY_REJECT" {
+ weight = 16.0;
+ }
+ "DMARC_POLICY_QUARANTINE" {
+ weight = 8.0;
+ }
+ "DMARC_POLICY_SOFTFAIL" {
+ weight = 0.0;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/rbl.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/rbl.conf
new file mode 100644
index 0000000..c44b9ef
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/rbl.conf
@@ -0,0 +1,46 @@
+rbls {
+ uceprotect1 {
+ symbol = "RBL_UCEPROTECT_LEVEL1";
+ rbl = "dnsbl-1.uceprotect.net";
+ }
+ uceprotect2 {
+ symbol = "RBL_UCEPROTECT_LEVEL2";
+ rbl = "dnsbl-2.uceprotect.net";
+ }
+ sorbs {
+ symbol = "RBL_SORBS";
+ rbl = "dnsbl.sorbs.net";
+ returncodes {
+ # http:// www.sorbs.net/general/using.shtml
+ RBL_SORBS_HTTP = "127.0.0.2";
+ RBL_SORBS_SOCKS = "127.0.0.3";
+ RBL_SORBS_MISC = "127.0.0.4";
+ RBL_SORBS_SMTP = "127.0.0.5";
+ RBL_SORBS_RECENT = "127.0.0.6";
+ RBL_SORBS_WEB = "127.0.0.7";
+ RBL_SORBS_DUL = "127.0.0.10";
+ RBL_SORBS_BLOCK = "127.0.0.8";
+ RBL_SORBS_ZOMBIE = "127.0.0.9";
+ }
+ }
+ interserver_ip {
+ symbol = "RBL_INTERSERVER_IP";
+ rbl = "rbl.interserver.net";
+ ipv6 = false;
+ returncodes {
+ RBL_INTERSERVER_BAD_IP = "127.0.0.2";
+ }
+ }
+ interserver_uri {
+ symbol = "RBL_INTERSERVER_URI";
+ rbl = "rbluri.interserver.net";
+ ignore_defaults = true;
+ no_ip = true;
+ dkim = true;
+ emails = true;
+ urls = true;
+ returncodes = {
+ RBL_INTERSERVER_BAD_URI = "127.0.0.2";
+ }
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/rbl_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/rbl_group.conf
new file mode 100644
index 0000000..4e3dce7
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/rbl_group.conf
@@ -0,0 +1,60 @@
+symbols = {
+ "RBL_UCEPROTECT_LEVEL1" {
+ score = 3.5;
+ }
+ "RBL_UCEPROTECT_LEVEL2" {
+ score = 1.5;
+ }
+ "RBL_SORBS" {
+ score = 0.0;
+ description = "Unrecognised result from SORBS RBL";
+ }
+ "RBL_SORBS_HTTP" {
+ score = 2.5;
+ description = "List of Open HTTP Proxy Servers.";
+ }
+ "RBL_SORBS_SOCKS" {
+ score = 2.5;
+ description = "List of Open SOCKS Proxy Servers.";
+ }
+ "RBL_SORBS_MISC" {
+ score = 1.0;
+ description = "List of open Proxy Servers not listed in the SOCKS or HTTP lists.";
+ }
+ "RBL_SORBS_SMTP" {
+ score = 4.0;
+ description = "List of Open SMTP relay servers.";
+ }
+ "RBL_SORBS_RECENT" {
+ score = 2.0;
+ description = "List of hosts that have been noted as sending spam/UCE/UBE to the admins of SORBS within the last 28 days (includes new.spam.dnsbl.sorbs.net).";
+ }
+ "RBL_SORBS_WEB" {
+ score = 2.0;
+ description = "List of web (WWW) servers which have spammer abusable vulnerabilities (e.g. FormMail scripts)";
+ }
+ "RBL_SORBS_DUL" {
+ score = 2.0;
+ description = "Dynamic IP Address ranges (NOT a Dial Up list!)";
+ }
+ "RBL_SORBS_BLOCK" {
+ score = 0.5;
+ description = "List of hosts demanding that they never be tested by SORBS.";
+ }
+ "RBL_SORBS_ZOMBIE" {
+ score = 2.0;
+ description = "List of networks hijacked from their original owners, some of which have already used for spamming.";
+ }
+ "RECEIVED_SPAMHAUS_XBL" {
+ weight = 0.0;
+ description = "Received address is listed in ZEN XBL";
+ }
+ "RBL_INTERSERVER_BAD_URI" {
+ score = 4.0;
+ description = "Listed on Interserver RBL";
+ }
+ "RBL_INTERSERVER_BAD_IP" {
+ score = 4.0;
+ description = "Listed on Interserver RBL";
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/redis.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/redis.conf
new file mode 100644
index 0000000..5ee0ac1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/redis.conf
@@ -0,0 +1,2 @@
+servers = "redis:6379";
+timeout = 10;
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/reputation.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/reputation.conf
new file mode 100644
index 0000000..0e3d03e
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/reputation.conf
@@ -0,0 +1,10 @@
+rules {
+ ip_reputation = {
+ selector "ip" {
+ }
+ backend "redis" {
+ servers = "redis";
+ }
+ symbol = "IP_REPUTATION";
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/spamassassin.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/spamassassin.conf
new file mode 100644
index 0000000..d091af6
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/spamassassin.conf
@@ -0,0 +1 @@
+ruleset = "/etc/rspamd/custom/sa-rules";
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/statistic.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/statistic.conf
new file mode 100644
index 0000000..1ca3e08
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/statistic.conf
@@ -0,0 +1,24 @@
+classifier "bayes" {
+ tokenizer {
+ name = "osb";
+ }
+ backend = "redis";
+ min_tokens = 11;
+ min_learns = 5;
+ new_schema = true;
+ expire = 2592000;
+ statfile {
+ symbol = "BAYES_HAM";
+ spam = false;
+ }
+ statfile {
+ symbol = "BAYES_SPAM";
+ spam = true;
+ }
+ autolearn {
+ spam_threshold = 12.0;
+ ham_threshold = -4.5;
+ check_balance = true;
+ min_balance = 0.9;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/statistics_group.conf b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/statistics_group.conf
new file mode 100644
index 0000000..7ed35b1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/conf/rspamd/local.d/statistics_group.conf
@@ -0,0 +1,10 @@
+symbols = {
+ "BAYES_SPAM" {
+ weight = 2.5;
+ description = "Message probably spam, probability: ";
+ }
+ "BAYES_HAM" {
+ weight = -5.5;
+ description = "Message probably ham, probability: ";
+ }
+}