rspamd and PMG recommendations

Old thread but still quite interesting for me.
Any news about the combination of RPAMD and PMG?

How do those two compare today? / What would you recommend today?
 
I'm using Rspamd together with a custom script.
Rspamd has many advantages and works well alongside the SpamAssassin filters I’ve fine-tuned. You get a additional score which is great to sort out some additional spam. Bonus: Often it does NOT correlate with my other filters, so it is an added value.


The drawback of the custom script is that no further SpamAssassin checks are executed if the returned score is greater than 5.0 (nobody in the German forum could tell me why this happens). Therefore, I limit the score to 4.9 when outputting it—unless the score is extremely high (>9.0), in which case the email is blocked directly via before-queue filtering.


Follow the instructions to enable custom script from here: https://forum.proxmox.com/threads/integrate-rspamd-as-custom-script.159110/
(you do not need to install jq for my custom skript)

  1. Install rspamd
    apt install rspamd

  2. Open the PMG configuration file:

    nano /etc/pmg/pmg.conf

  3. Enable the custom check script by adding or updating the following section:

    section: admin
    custom_check 1
    custom_check_path /usr/local/bin/pmg-custom-check.sh

  4. Create the Custom Script


touch /usr/local/bin/pmg-custom-check.sh
chmod +x /usr/local/bin/pmg-custom-check.sh
cat > /usr/local/bin/pmg-custom-check.sh
Code:
#!/usr/bin/env bash
set -euo pipefail

# PMG custom check API v1: args: APIVERSION QUEUEFILENAME
if [[ $# -ne 2 ]]; then
  echo "usage: $0 APIVERSION QUEUEFILENAME" >&2
  exit 1
fi

apiver="$1"
queue_file="$2"
RSPAMD_HOST="127.0.0.1"
RSPAMD_PORT="11333"

echo "v1"

# Rspamd prüfen
 rspamc_out="$(rspamc -h "${RSPAMD_HOST}:${RSPAMD_PORT}" < "$queue_file" 2>/dev/null || true)"
 score="$(awk -F': ' '/^Score: /{split($2,a," "); print a[1]; exit}' <<<"$rspamc_out")"

if [[ -n "${score:-}" ]]; then
    capped_score=$(awk -v s="$score" 'BEGIN { if (s > 4.9 && s <= 8.9) print 4.9; else print s }')
    echo "SCORE: ${capped_score}"
else
     echo "OK"
fi
exit 0

Rspamd is very fast in this setup (faster than Spam Assassin), usually taking well under 1 second for the additional check.
SA check is skipped, if CustomScore > 5:
2026-03-05T07:13:14.348030+00:00 mx postfix/smtpd[5997]: connect from mail-wm1-f70.google.com[209.85.128.70]
2026-03-05T07:13:14.434342+00:00 mx postfix/smtpd[5997]: NOQUEUE: client=mail-wm1-f70.google.com[209.85.128.70]
2026-03-05T07:13:14.484592+00:00 mx pmg-smtp-filter[5639]: 184AA69A92D0A74AE2: new mail message-id=<0107019cbcd6edd2-c586dc99-d050-4bfb-bf78-46f9e95a80eb-000000@eu-central-1.amazonses.com>
2026-03-05T07:13:15.205887+00:00 mx pmg-smtp-filter[5639]: 184AA69A92D0A74AE2: SA score=21/5 time=0.000 bayes=undefined autolearn=no hits=CustomCheck(21.29)
2026-03-05T07:13:15.208205+00:00 mx pmg-smtp-filter[5639]: 184AA69A92D0A74AE2: block mail to <mymail> (rule: Block Spam (Level 7))
2026-03-05T07:13:15.211333+00:00 mx pmg-smtp-filter[5639]: 184AA69A92D0A74AE2: processing time: 0.73 seconds (0, 0.041, 0.676)

You can combine the custom Skript to filter Google Groups Messages, even before sending the message to rspamd or spamassassin:


Code:
#!/usr/bin/env bash
set -euo pipefail

# PMG custom check API v1: args: APIVERSION QUEUEFILENAME
if [[ $# -ne 2 ]]; then
  echo "usage: $0 APIVERSION QUEUEFILENAME" >&2
  exit 1
fi

apiver="$1"
queue_file="$2"
RSPAMD_HOST="127.0.0.1"
RSPAMD_PORT="11333"

echo "v1"

# Google Groups Header prüfen
if awk 'BEGIN{RS=""; FS="\n"} NR==1 { for(i=1;i<=NF;i++) if(tolower($i) !~ /^subject:/ && tolower($i) ~ /googlegroups\.com/) exit 0; exit 1 }' "$queue_file"; then
    echo "SCORE: 99"
else
# Rspamd prüfen
    rspamc_out="$(rspamc -h "${RSPAMD_HOST}:${RSPAMD_PORT}" < "$queue_file" 2>/dev/null || true)"
    score="$(awk -F': ' '/^Score: /{split($2,a," "); print a[1]; exit}' <<<"$rspamc_out")"

    if [[ -n "${score:-}" ]]; then
        capped_score=$(awk -v s="$score" 'BEGIN { if (s > 4.9 && s <= 8.9) print 4.9; else print s }')
        echo "SCORE: ${capped_score}"
    else
        echo "OK"
    fi
fi
exit 0


Google Groups decision is Insane fast:
2026-03-16T02:39:00.468154+00:00 mx postfix/smtpd[506]: connect from mail-wr1-f71.google.com[209.85.221.71]
2026-03-16T02:39:00.640994+00:00 mx postfix/smtpd[506]: NOQUEUE: client=mail-wr1-f71.google.com[209.85.221.71]
2026-03-16T02:39:00.697245+00:00 mx pmg-smtp-filter[496]: 245D469B76D44A7252: new mail message-id=<CALKtb2GmQuk4_JBXoGrg8LLtTOakvf7SEjgLcOEGv3_cELX=TQ@mail.gmail.com>
2026-03-16T02:39:00.753967+00:00 mx pmg-smtp-filter[496]: 245D469B76D44A7252: SA score=99/5 time=0.000 bayes=undefined autolearn=no hits=CustomCheck(99)
2026-03-16T02:39:00.756505+00:00 mx pmg-smtp-filter[496]: 245D469B76D44A7252: block mail to <mymail> (rule: Block Spam (Level 7))
2026-03-16T02:39:00.759871+00:00 mx pmg-smtp-filter[496]: 245D469B76D44A7252: processing time: 0.071 seconds (0, 0.031, 0.02)
 
Last edited: