I built an app that performs an AI check via a SpamAssassin filter.
What data is transmitted?
- Sending server
- Sender
- Subject
- Recipient
Sender, recipient, and subject may be a data protection issue!
What does it cost?
Depends on the chosen model and mailtraffic. There are free models on OpenRouter, but they change frequently (and you have to update them in your config to keep things working). You need to create an account and enter an API key.
It is possible to configure both free and paid models. The tool keeps track of models that do not work and pauses their usage for a configurable period of time. As long as free, non-blocked models are available, no paid models will be used. If you want to use a paid model, you can choose very inexpensive ones, e.g. DeepSeek v4 Flash.
Doesn't that generate a lot of traffic?
That depends. The integration is designed to conserve resources. First, all SpamAssassin checks are performed. The AI script runs last and evaluates the eventually score total. If it falls within a specific range (in this case: between 2 and 9; I reject emails starting from 7), the AI script becomes active and sends the data to an AI.
I suggest using something like my policyguard to filter many mails very early. In my case, 1000 daily mails will produce approx. 50 AI scans per day.
Can I use a local AI?
Yes. Local AIs use the same interfaces as OpenRouter and generally work. Qwen, for example, would probably work well, although I haven’t tested it myself yet.
Paste your API Key into /etc/ai-spamcheck.toml
Remove the txt file ending from attached files and copy them to
Restart Spamassassin
Changes you can made in AICheck.pm
Changes you can made in ai-spamcheck.toml
What data is transmitted?
- Sending server
- Sender
- Subject
- Recipient
Sender, recipient, and subject may be a data protection issue!
What does it cost?
Depends on the chosen model and mailtraffic. There are free models on OpenRouter, but they change frequently (and you have to update them in your config to keep things working). You need to create an account and enter an API key.
It is possible to configure both free and paid models. The tool keeps track of models that do not work and pauses their usage for a configurable period of time. As long as free, non-blocked models are available, no paid models will be used. If you want to use a paid model, you can choose very inexpensive ones, e.g. DeepSeek v4 Flash.
Doesn't that generate a lot of traffic?
That depends. The integration is designed to conserve resources. First, all SpamAssassin checks are performed. The AI script runs last and evaluates the eventually score total. If it falls within a specific range (in this case: between 2 and 9; I reject emails starting from 7), the AI script becomes active and sends the data to an AI.
I suggest using something like my policyguard to filter many mails very early. In my case, 1000 daily mails will produce approx. 50 AI scans per day.
Can I use a local AI?
Yes. Local AIs use the same interfaces as OpenRouter and generally work. Qwen, for example, would probably work well, although I haven’t tested it myself yet.
Code:
# Install requirements
apt install python3-openai
# Create Folder for Statistics
mkdir -p /t/
touch /t/ai-spamcheck.log
touch /t/ai-spamcheck-stats.json
chmod -R 777 /t/
Paste your API Key into /etc/ai-spamcheck.toml
Remove the txt file ending from attached files and copy them to
Code:
/etc/mail/spamassassin/aicheck.cf
/usr/local/lib/AICheck.pm
/usr/local/bin/ai-spamcheck.py
/etc/ai-spamcheck.toml
Restart Spamassassin
Code:
systemctl restart pmg-smtp-filter.service
Code:
# Test with E-Mail with score between 2 and 9
spamassassin -t < test.eml
Changes you can made in AICheck.pm
Code:
SCRIPT => "/usr/local/bin/ai-spamcheck.py",
TIMEOUT => 15, # hard kill for the external call (seconds)
RULENAME => "AI_SCORE",
MIN_GATE => 2.0, # run AI check only if SA score so far is >= this
MAX_GATE => 9.0, # ... and below this (PMG block level)
Changes you can made in ai-spamcheck.toml
Code:
API_KEY = "sk-or-v1-1<your API key>" # your OpenAI API key= "sk-or-v1-REPLACE-ME"
API_URL = "https://openrouter.ai/api/v1" # base URL
TIMEOUT = 4.0 # API request timeout in seconds
# List of model IDs. One is chosen at random per run. Free before paid.
MODEL = [
"minimax/minimax-m2.7:free",
"minimax/minimax-m3:free",
"google/gemma-4-31b-it:free",
"deepseek/deepseek-v4-flash-0731",
"upstage/solar-pro4",
]
# JSON dict tracking usage and errors per model.
# The directory must exist and be writable by the script's user.
STATISTIC_FILE = "/t/ai-spamcheck-stats.json"
# Table log file.
LOG_FILE = "/t/ai-spamcheck.log"
Code:
Content preview: Servus Herr XXXXX, sollten Sie noch Leute für Ihre Autowerkstatt
suchen, kann ich Ihnen hierfür gerade eine Einstellungsgarantie aussprechen.
Wäre das grundsätzlich für Sie interessant?
Content analysis details: (9.2 points, 5.0 required)
pts rule name description
---- ---------------------- --------------------------------------------------
8.0 URIBL_ABUSE_SURBL Contains an URL listed in the ABUSE SURBL blocklist
[URI: getrfmarketingagency.com]
-3.0 POS_XXXXX BODY: No description available.
1.2 AI_SCORE HEADER: AI-based spam score
3.0 HTML_MIME_NO_HTML_TAG HTML-only message, but there is no HTML tag
Code:
#cat /t/ai-spamcheck.log
2026-09-07 03:26:57 | -1 | nvidia/nemotron-3.5-lightni… | TYSPR03MB9145.apcprd03.prod… | Jofar Ben <jofararcherben@outlook.com> | Jofar Ben <jofararcherben@o… | Re: Android app development?
2026-09-07 03:27:26 | 2.9 | nvidia/nemotron-3.5-lightni… | sjc04p1infpx012.cb2.sjc04.t… | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | "info@XXXXXXXXXXXXXXXXXX" <… | Funds transfer remittance advice
2026-09-07 03:27:58 | -2 | nvidia/nemotron-3.5-lightni… | gu.d.sender-sib.com | XXXXXXXXXXXXXXXXXXXXXXXXX <no-reply@ser… | abwicklung@XXXXXXXXX, artur… | XXXXX / Eigenversand FZ-Dokumente / 14.08.2026
2026-09-07 03:28:00 | -1 | minimax/minimax-m3:free | localhost | Clara Becker <becker@getrfmarketingagen… | info@XXXXXXXXXXXXXXXXXX | Bewerbung
2026-09-07 03:28:03 | 2.5 | minimax/minimax-m3:free | localhost | Clara Becker <becker@getrfmarketingagen… | info@XXXXXXXXXXXXXXXXXX | Bewerbung
2026-09-07 03:28:06 | 3 | minimax/minimax-m3:free | by mail-oi1-f169.google.com… | Safiya Magnumikz | E & D KOKORIKO <safi… | undisclosed-recipients:; | Inquiry About Product Purchase and Shipping to Cyprus
2026-09-07 03:28:15 | -2 | nvidia/nemotron-3.5-lightni… | gu.d.sender-sib.com | XXXXXXXXXXXXXXXXXXXXXXXXX <no-reply@ser… | abwicklung@XXXXXXXXX, artur… | XXXXX / Eigenversand FZ-Dokumente / 14.08.2026
Attachments
Last edited: