If you manage a Plesk server and your clients are still drowning in spam despite SpamAssassin being enabled, you are not alone. Plesk SpamAssassin custom rules configuration is a step most admins skip entirely — and the default setup ships with Bayes training silently disabled, meaning the filter never learns from real-world spam patterns on your server.
This guide covers the complete fix: re-enabling the Bayes training cron job, writing effective custom rules in /etc/mail/spamassassin/local.cf, tuning score thresholds, and testing everything so spam actually stops landing in your clients' inboxes.
Why Plesk's Default SpamAssassin Settings Let Spam Through
When you enable SpamAssassin in Plesk (Tools & Settings → Mail Server Settings → SpamAssassin), it activates a basic ruleset. However, several critical features are either off by default or quietly broken:
- Default hit score threshold is 7.0 — too high. Spam scoring 5–6 slips through untouched.
- Bayes database starts empty — it has never seen your mail, so it gives every message a neutral Bayes score.
- The daily training cron job is disabled by the psa-spamassassin package — even if mailboxes fill with confirmed spam, the Bayes filter never trains on it.
- No custom header rules — bulk sending services and snowshoe spam use unusual X-Mailer or MIME patterns that the default ruleset misses.
- Per-domain and per-mailbox overrides are rarely configured — so a transactional sender that one client whitelists gets blocked for another.
The result: SpamAssassin is technically running, but operating in a near-default state that sophisticated spam campaigns bypass trivially.
How Bayes Training Works — and Why It's Disabled by Default
SpamAssassin's Bayes classifier analyses word and token frequencies in confirmed spam and ham (legitimate mail) to produce a probability score. After seeing enough messages (typically 200 spam + 200 ham), it starts contributing a BAYES_xx score to every message — often the decisive factor for borderline mail.
On a stock Plesk installation, the daily /etc/cron.daily/spamassassin file exists but contains this at the top:
# This task was disabled by psa-spamassassin package
exit 0
Plesk replaced it with its own maintenance command (plesk daily ExecuteSpamtrain), which runs as part of the nightly Plesk maintenance sweep. On many servers this works — but on others the Plesk daily task is mis-scheduled, runs as the wrong user, or simply skips SpamAssassin training silently. The result: autolearn=no in every SpamAssassin header, and a Bayes filter that never matures.
By default, each Plesk mailbox has its own isolated Bayes database at:
/var/qmail/mailnames/<domain>/<mailbox>/.spamassassin/bayes_toks
This per-mailbox isolation means a new mailbox starts from zero every time, and low-volume mailboxes may never accumulate the 200+200 minimum threshold needed to activate Bayes scoring.
Re-enabling the Daily Bayes Training Cron Job
The fix is straightforward. You have two options: fix the disabled cron file, or add a dedicated cron entry.
Option A — Fix the system cron file
Open the broken file and replace it entirely:
nano /etc/cron.daily/spamassassin
Replace the contents with:
#!/bin/bash
# Daily SpamAssassin Bayes training — restored after psa-spamassassin override
/usr/bin/plesk daily ExecuteSpamtrain
sa-update --no-gpg
exit 0
chmod +x /etc/cron.daily/spamassassin
Option B — Add a dedicated root cron job
If you prefer not to touch the system cron file:
crontab -e
Add:
0 2 * * * /usr/bin/plesk daily ExecuteSpamtrain > /var/log/spamtrain.log 2>&1
30 2 * * * /usr/bin/sa-update --no-gpg > /var/log/sa-update.log 2>&1
This runs training at 2:00 AM and rule updates at 2:30 AM daily.
Verify training is working
After letting the cron run once, check a mailbox Bayes database:
sa-learn --dbpath /var/qmail/mailnames/example.com/user/.spamassassin --dump magic | grep nspam
You should see the spam count increasing. If it stays at 0, manually seed it (see Step 6).
Writing Custom Rules in /etc/mail/spamassassin/local.cf
The file /etc/mail/spamassassin/local.cf is the correct place for server-wide custom rules in Plesk. It is not overwritten by SpamAssassin rule updates (which go to /etc/mail/spamassassin/ as dated .cf files). Plesk does manage two settings in this file — required_score and rewrite_header — so keep your custom additions below those lines.
nano /etc/mail/spamassassin/local.cf
Lower the threshold first
# Plesk default is 7. Lower to catch more spam
required_score 5.0
Rule syntax
Every SpamAssassin rule has four parts: type, name, pattern, and score. Example:
header FAKE_BANK_DOMAIN From =~ /paypal-secure[0-9]+\./i
describe FAKE_BANK_DOMAIN Sender domain resembles a fake PayPal address
score FAKE_BANK_DOMAIN 4.5
Useful rule types for common spam
header— matches any RFC 2822 header fieldbody— matches plain-text decoded body contentrawbody— matches raw (pre-decode) body including HTML tagsfull— matches the entire raw message (headers + body)uri— matches URIs found in the messagemeta— combines other rule hits with boolean logic
Practical rules to add immediately
# Flag messages with no plain-text alternative (image-only spam)
rawbody IMG_ONLY_SPAM /<img[^>]+>/i
rawbody NO_TEXT_BODY /^<html>/i
meta IMAGE_ONLY_MAIL IMG_ONLY_SPAM && NO_TEXT_BODY
score IMAGE_ONLY_MAIL 2.5
# Catch aggressive casino/betting subject lines
header CASINO_SUBJ Subject =~ /(casino|jackpot|bet now|spin to win)/i
score CASINO_SUBJ 3.0
# Flag suspicious X-Mailer strings common in bulk tools
header BULK_MAILER X-Mailer =~ /(phpmailer|mass mailer|bulk|dkim signer)/i
score BULK_MAILER 2.0
# Catch common crypto scam body phrases
body CRYPTO_SPAM /(double your bitcoin|crypto profit|satoshi giveaway)/i
score CRYPTO_SPAM 4.0
# Whitelist known legitimate senders (negative score)
header OUR_CRM_SENDER From =~ /\@yourbusiness\.com$/i
score OUR_CRM_SENDER -5.0
Important: Do not add rules that duplicate the built-in ruleset (e.g., do not re-score URIBL_BLACK) unless you specifically want to override the default weight.
Tuning SpamAssassin Score Thresholds Per Domain and Per Mailbox
You do not have to apply the same threshold to every mailbox. SpamAssassin checks for per-user preferences before applying global rules.
Per-mailbox override (user_prefs)
Create or edit the preferences file for a specific mailbox:
nano /var/qmail/mailnames/example.com/user/.spamassassin/user_prefs
Add overrides for that mailbox only:
required_score 4.0
whitelist_from newsletters@trustedsender.com
blacklist_from *@known-spammer.ru
Per-domain override via Plesk GUI
In Plesk, go to: Mail → domain → Mail Settings → SpamAssassin. Here you can set a per-domain spam score threshold without touching the CLI. Changes made here write to the per-domain user_prefs and do not conflict with local.cf.
Whitelist entire TLDs or IP ranges globally
# In /etc/mail/spamassassin/local.cf
whitelist_from_rcvd *@gov.in .gov.in
trusted_networks 192.168.1.0/24
💡 None of these worked? Skip the guesswork.
Get Expert Help →Testing Your Rules with spamassassin --lint and sa-learn
Always run a lint check after editing local.cf. A syntax error will stop SpamAssassin from loading.
spamassassin --lint
If the command returns without output, the config is clean. Any errors are printed to stdout with the line number.
spamassassin -t < /path/to/sample-spam.eml
The output shows every rule that fired, its score, and the total. Look for your new custom rules in the list to confirm they match.
If the Bayes database is empty or undertrained, seed it manually from existing mailbox folders:
# Train on confirmed spam (Junk/Spam folder)
sa-learn --spam --maildir /var/qmail/mailnames/example.com/user/Maildir/.Junk
# Train on confirmed ham (Inbox)
sa-learn --ham --maildir /var/qmail/mailnames/example.com/user/Maildir
# Check token count
sa-learn --dbpath /var/qmail/mailnames/example.com/user/.spamassassin --dump magic
You need at least 200 spam tokens and 200 ham tokens before Bayes produces BAYES_xx scores. The ideal ratio is roughly equal numbers of each.
service spamassassin restart
# or on systemd:
systemctl restart spamassassin
plesk repair mail -y
Send a test message to one of your mailboxes and check the received headers:
X-Spam-Status: Yes, score=8.4 required=5.0 tests=BAYES_99,CASINO_SUBJ,...
If you see BAYES_99 or BAYES_80 in the test list, Bayes is working. If all BAYES_ entries show BAYES_00 or are absent, training is still incomplete.
FAQs
See the FAQ section below for answers to the most common questions about SpamAssassin configuration in Plesk.
Managing SpamAssassin correctly across dozens of domains on a busy Plesk server takes time — and a misconfigured filter can cause legitimate mail to be silently dropped. If you would rather hand this off to experts, the team at CloudHouse server management handles full Plesk mail server tuning, including SpamAssassin rule writing, Bayes seeding, and ongoing monitoring — so your clients stop getting spam without losing real email.
Conclusion
Plesk's out-of-the-box SpamAssassin setup is a starting point, not a finished solution. The three changes that make the biggest difference are: lowering required_score from 7 to 5, fixing the disabled Bayes training cron job, and writing at least a handful of domain-specific custom rules in local.cf. Combine these with manual sa-learn seeding and regular sa-update runs, and you will see a dramatic drop in spam reaching your clients' inboxes within days.
