How to Configure DirectAdmin Spam Protection

Configuring proper server-wide spam protection is essential for maintaining server reputation, preserving bandwidth, and ensuring optimal mail deliverability. This guide outlines a complete, weighted spam-scoring procedure for DirectAdmin running on Debian 13, using Exim + Easy Spam Fighter (ESF) + SpamAssassin together as one coordinated system.

Prerequisites: Root SSH access to your Debian 13 server with DirectAdmin, Exim, Easy Spam Fighter, and SpamAssassin already installed.
Read this first — how the three layers actually work together:

DirectAdmin's mail stack is not three independent filters. It is one pipeline:

  1. ESF (RCPT stage) checks SPF, DKIM, reverse DNS, and RBL membership before the message body arrives, and starts a running score (acl_m_easy69).
  2. SpamAssassin (DATA stage) scans the message content and produces its own score. This score is added directly into ESF's running total — multiplied by 10 (a SpamAssassin score of 3.4 adds 34 points to ESF's tally).
  3. ESF's final check compares the combined total against EASY_HIGH_SCORE_DROP and drops the message if it's equal or higher.

Because of step 2, any SpamAssassin rule score you set is not independent — it always flows into ESF's single combined decision. This guide treats EASY_HIGH_SCORE_DROP = 100 as the reference "100% = kill" scale, and calibrates every other setting against it.


Step 1: Configure a Reliable DNS Resolver Path

RBL and Spamhaus lookups depend on how your resolver reaches the outside world.
Using a large public resolver like 1.1.1.1 directly can get your queries throttled or blocked by Spamhaus, returning 127.255.255.254 instead of a real answer — silently disabling every RBL check on your server.

  1. Follow the documentation at:
    https://frankwebhost.com/knowledgebase/3/How-to-Configure-Unbound-DNS-Resolver-on-Debian-13-Cloud-VPS.html
  2. Verify:
    dig +short 2.0.0.127.zen.spamhaus.org
    You should consistently see 127.0.0.2, 127.0.0.4, or 127.0.0.10 — never 127.255.255.254.

Step 2: Enable Sender Callout Verification (Not Recommended)

Sender callout verification checks if the sender address actually exists at the source mail server before accepting incoming mail. This drastically cuts down on dictionary attacks and fake sender spam.

  1. Edit the pre-recipient ACL Exim file:
    nano /etc/exim.acl_check_recipient.pre.conf
  2. Append the sender verification rule:
    deny
      !sender_domains = outlook.com : hotmail.com : live.com : msn.com : yahoo.com : ymail.com : aol.com : gmail.com : google.com : googlemail.com
      !verify = sender/callout=20s,random
      message = Verification failed: Sender address does not exist
  3. Rebuild the Exim configuration:
    da build exim_conf

Step 3: Configure Real-time Blackhole Lists (RBLs)

RBLs allow Exim to block incoming emails from known spammer IP addresses directly during the SMTP connection phase.

  1. Edit the custom Exim strings file:
    nano /etc/exim.strings.conf.custom
  2. Define your preferred RBL lists (Barracuda, Spamhaus, SpamCop, PSBL, Mailspike, MSRBL):
    RBL_DNS_LIST==b.barracudacentral.org : zen.spamhaus.org : bl.spamcop.net : psbl.surriel.com : bl.mailspike.net : combined.rbl.msrbl.net

    smtp_banner = "$primary_hostname ESMTP Mail Server Ready"
  3. Rebuild the Exim configuration to activate the RBLs:
    da build exim_conf

Step 4: Easy Spam Fighter — Weighted Scoring (RCPT stage)

This is where your protection level is defined. Every value below is calibrated against EASY_HIGH_SCORE_DROP = 100 as the "100% = kill" reference point, so each signal's weight can be read directly as a percentage of the kill threshold.

  1. nano /etc/exim.easy_spam_fighter/variables.conf.custom
  2. # The kill threshold itself — every weight below is a % of this number
    EASY_HIGH_SCORE_DROP == 100
    
    # Skip re-running SpamAssassin only once a message is already guaranteed
    # to be dropped anyway (pure CPU optimization, does not affect decisions)
    EASY_LIMIT == 100
    
    # SPF — any failure type, full weight (100%)
    EASY_SPF_FAIL == 100
    EASY_SPF_SOFT_FAIL == 100
    EASY_SPF_PASS == -02
    
    # DKIM — any failure type, 90%
    EASY_DKIM_FAIL == 90
    EASY_DKIM_PASS == -02
    
    # Reverse DNS — any failure type, 80%
    EASY_NO_REVERSE_IP == 80
    EASY_FORWARD_CONFIRMED_RDNS == -01
    
    # Confirmed content-spam bonus (SpamAssassin's own Global threshold reached), 50%
    EASY_IS_SPAM == 50
    
    # RBL match — carried over from previous config, not covered in your
    # specification. Adjust if you'd like a specific weight here too.
    EASY_DNS_BLACKLIST == 80
  3. Rebuild Exim configuration:
    da build exim_conf
What this means in practice:
Situation Score added Dropped alone?
SPF fail (hard or soft) only 100 Yes — matches your "100% rage"
DKIM fail only 90 No — needs 10 more points from any other signal
rDNS fail only 80 No — needs 20 more points
DKIM fail + rDNS fail together 170 Yes

Step 5: SpamAssassin — Content-Only Rules (No ESF Overlap)

SPF, DKIM, and rDNS are already fully handled in Step 4. Setting them again here would double-count the same signal and drop legitimate mail prematurely (a forwarded message with a relay that has no rDNS, for example, would be punished twice for the same reason). The rules below have no ESF equivalent, so they are safe to score here.

Remember the ×10 scale-up: a SpamAssassin score of 10 becomes 100 points once it reaches ESF's tally. To make a rule worth "100%" on ESF's scale, set its SpamAssassin score to 10, not 100.
  1. nano /etc/mail/spamassassin/local.cf
  2. Append:
    # ====================================================
    # Content-only rules — no ESF equivalent, safe to score independently.
    # Each "score 10" below becomes 100 points once added to ESF's tally
    # (SpamAssassin score x 10), i.e. a guaranteed drop on its own.
    # ====================================================
    
    # Freemail spoofing (sender name/domain forged as Gmail/Yahoo/etc.) - 100%
    score FREEMAIL_FORGED_FROMDOMAIN 10.0
    score FROM_MISSP_FREEMAIL 10.0
    score FREEMAIL_FORGED_REPLYTO 10.0
    
    # Confirmed bad-infrastructure signals - 100% each
    score HELO_DYNAMIC_IPADDR 10.0
    score NO_DNS_FOR_FROM 10.0
    
    # DMARC Failure (domain spoofing protection) - 100% if reject
    score DMARC_REJECT 10.0
    score DMARC_QUAR 8.0 
  3. # ====================================================
    # Bayes Auto-Learn Tuning for Aggressive Setup
    # ====================================================
    bayes_auto_learn 1
    bayes_auto_learn_threshold_nonspam -0.1
    bayes_auto_learn_threshold_spam 3.0
  4. # A 'contact address' users should contact for more info.
    report_contact https://yourdomain.com/support.html
  5. Verify syntax to make sure there are no errors in SpamAssassin configuration:
    spamassassin --lint
  6. Restart SpamAssassin and rebuild Exim configuration:
    systemctl restart spamassassin
    da build exim_conf
    Important Note on DMARC Scoring: Only define high DMARC scores (e.g., 10.0 or 8.0) in SpamAssassin if DMARC processing is completely disabled at the ESF level, or if variables.dmarc.conf does not exist or is empty. If ESF is already scoring DMARC independently, setting these scores here will result in double-counting the penalty and dropping legitimate mail prematurely.

Step 6: SpamAssassin Tuneup from the DirectAdmin GUI

  1. Log in to your DirectAdmin Control PanelUser TabE-Mail ManagerSpamAssassin Setup.
  2. Blocking strategy: User Spambox — messages that are flagged as spam by SpamAssassin's own Global threshold, but don't reach ESF's combined kill score, land in the spambox for review instead of being silently dropped.
  3. High score block: No (disabled)
    This setting creates an independent drop path that runs before ESF's combined check even executes (confirmed in /etc/exim/spamd.acl_smtp_data.conf). If left enabled, a purely content-based SpamAssassin score above its threshold will hard-drop a message on its own — completely bypassing the weighted percentages you just configured in Step 4, including the intentional "content alone shouldn't auto-kill" behavior for the 60% weight. Disabling it here means the single combined ESF score (Step 4) is the only thing that decides whether a message is dropped, which is what your weighted design assumes.
  4. Global threshold: Custom / 4.0 — this is the point at which SpamAssassin marks a message as confirmed spam internally and triggers the EASY_IS_SPAM (60%) bonus from Step 4. It does not drop mail by itself.
  5. Rewrite subject: Yes / Tag: *****SPAM*****
  6. Spam delivery: Don't use attachments
  7. Click Save Configuration.

Step 7: Enable RBL Blocking in the DirectAdmin GUI

  1. Admin TabServer ManagerAdministrator SettingsE-mail Tab.
  2. Enable RBL Blocking in Exim.
  3. Click Save Settings.

Step 8: Train the Bayesian Filter Manually (Optional)

SpamAssassin's Bayes filter is the single strongest content signal it has, but it is not pre-trained on install, and does not retroactively learn from mail already sitting in a Spam/Junk folder. It only learns automatically, in real time, from newly-scanned mail that crosses its own auto-learn thresholds — a large backlog of manually-sorted spam will not be picked up unless trained explicitly.

  1. Check current training state (per mail account, not server-wide):
    sa-learn --dump magic --dbpath=/home/<user>/.spamassassin/bayes
    Look at the nspam and nham counts — reliable classification needs at least ~200 of each.
  2. Train from an existing spam/junk folder:
    sa-learn --spam --dbpath=/home/<user>/.spamassassin/bayes \
      /home/<user>/imap/<domain>/<mailbox>/Maildir/.INBOX.spam/cur/* \
      /home/<user>/imap/<domain>/<mailbox>/Maildir/.INBOX.spam/new/*
  3. Optional: keep training current with a daily cron job:
    crontab -e
    0 3 * * * sa-learn --spam --dbpath=/home/<user>/.spamassassin/bayes /home/<user>/imap/<domain>/<mailbox>/Maildir/.INBOX.spam/cur/* --no-sync >/dev/null 2>&1
    30 3 * * * sa-learn --sync --dbpath=/home/<user>/.spamassassin/bayes >/dev/null 2>&1

Step 9: Apply and Verify

Finally, perform a full system reboot to ensure all network socket changes, Exim ACLs, and SpamAssassin services are reloaded cleanly:

reboot

Watch live processing:

tail -f /var/log/exim/mainlog

Check what's being rejected and why:

tail -100 /var/log/exim/rejectlog

Confirm your DNS/RBL path is healthy:

dig +short 2.0.0.127.zen.spamhaus.org
Tune gradually: After enabling this, monitor rejectlog and the SpamTally header on a sample of real mail for a few days. If legitimate mail is being caught — most commonly forwarded mail through a relay with no rDNS — adjust the specific weight in Step 4 rather than the overall kill threshold.
  • 1 Users Found This Useful
Was this answer helpful?

Related Articles

Integrating Roundcube "Mark as Junk" Plugin with SpamAssassin (Bayes) Train on DirectAdmin

This tutorial provides a complete, production-ready guide to integrating the Mark as Junk plugin...