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: ";
+    }
+}