A native SMTP plugin DLL for MailEnable that marks inbound junk so a MailEnable message filter can route it to the Junk folder. It does not reject mail — it tags only, which keeps false positives recoverable.
Evaluated at DATAEND (the only stage where MailEnable hands the plugin the full
message via <messagepath>). Any layer firing tags the message; the whitelist
short-circuits everything.
- Whitelist — trusted domains (subdomains included) and specific addresses are delivered untouched.
- TLD allow-list — the
From:header domain's TLD must be inAllowedTlds, else tag. Matches the final label, soukcoversco.uk. - Subject keywords — file-based list; plain lines match whole-word
(case-insensitive),
re:lines are regex. The file is live-reloaded. - SpamAssassin (optional) —
spamdperforms SPF + DKIM verification and a content/Bayesian score. - DMARC — computed in-process from the SPF/DKIM results + a
_dmarcTXT lookup; tagged when it fails underp=quarantine/p=reject(only whenspamdanswered).
When a message is tagged the plugin injects:
X-Spam-Flag: YESX-Spam-Reason:— which layers fired, e.g.TLD_NOT_ALLOWED(xyz), SUBJECT_KEYWORD(lottery)X-Spam-Status:and (if spamd answered)X-Spam-Score:/Authentication-Results:
A MailEnable filter then moves anything with X-Spam-Flag: YES to Junk.
SpamAssassin is optional. With
UseSpamAssassin=0(or spamd simply not installed yet) the whitelist/TLD/keyword layers still run — so you can deploy those first and add SPF/DKIM/DMARC later. The plugin fails open: if spamd is unreachable the message is delivered, and DMARC is not enforced on guessed results.
- (Optional, for SPF/DKIM/DMARC + scoring) SpamAssassin for Windows (JAM
Software, freeware) running as a service with the SPF and DKIM plugins enabled,
spamdlistening on127.0.0.1:783. - MailEnable 3.5 or later (32- and 64-bit services).
- Visual Studio with the C++ toolset.
Build both architectures. The exported entry point comes from SpamFilter.def.
From the x64 Native Tools Command Prompt for VS:
cl /LD /EHsc /O2 /DNDEBUG SpamFilter.cpp /Fe:SpamFilter.dll /link /DEF:SpamFilter.defFrom the x86 Native Tools Command Prompt for VS (separate prompt): same command.
(ws2_32.lib and dnsapi.lib are linked automatically via #pragma comment(lib,…).)
-
Copy the 32-bit
SpamFilter.dll+SpamFilter.ini+SpamKeywords.txttoC:\Program Files (x86)\Mail Enable\bin\. -
Copy the 64-bit
SpamFilter.dll+SpamFilter.ini+SpamKeywords.txttoC:\Program Files (x86)\Mail Enable\bin64\. -
Register the plugin (use
Wow6432Nodeon 64-bit Windows):HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mail Enable\Mail Enable\Connectors\SMTP Plugin DLL = SpamFilter.dll (REG_SZ, filename only)Or command line: reg add "HKLM\SOFTWARE\Wow6432Node\Mail Enable\Mail Enable\Connectors\SMTP" /v "Plugin DLL" /t REG_SZ /d "SpamFilter.dll" /f
-
Edit
SpamFilter.ini(see below) and setKeywordFileto the correct folder for each build (bin\for x86,bin64\for x64). -
Restart the MailEnable SMTP connector/service.
The plugin only tags; something has to move the message. There are two ways.
When a message is tagged the plugin injects MailEnable's own routing header:
X-ME-Content: Deliver-To=Junk
MailEnable's delivery agent honours this and drops the message straight into the
mailbox's Junk E-Mail folder — no content filter required, so it works on
Standard edition. Controlled by DeliverToJunkHeader=1 (default on).
You must enable junk delivery on the post office:
- MailEnable Admin → Post Offices → [your post office] → Properties.
- On the Feature Selection tab, enable the option that delivers messages marked as spam to the Junk E-Mail folder. (Exact wording varies by version.)
- Make sure the mailbox has a Junk E-Mail folder (IMAP/WebMail auto-creates it).
If you prefer to act on X-Spam-Flag instead, create a message/content filter:
- Criteria: header
X-Spam-FlagcontainsYES - Action: Mark as spam (which adds
X-ME-Content: Deliver-To=Junk)
This requires the content-filtering feature that Standard does not have.
| Key | Default | Meaning |
|---|---|---|
UseSpamAssassin |
1 |
Call spamd. 0 = local checks only. |
SpamdHost / SpamdPort |
127.0.0.1 / 783 |
Where spamd listens. |
SpamThreshold |
5.0 |
SA score at/above which to tag. |
EnforceDmarc |
1 |
Tag DMARC fails under p=quarantine/reject (needs spamd). |
TldFilter |
1 |
Enable the TLD allow-list. |
AllowedTlds |
com uk net org us |
Allowed final-label TLDs (space/comma sep). |
SubjectKeywordFilter |
1 |
Enable the subject keyword filter. |
KeywordFile |
(path) | Path to SpamKeywords.txt. |
KeywordReloadSeconds |
5 |
Min seconds between keyword-file reload checks. |
WhitelistDomains |
(empty) | Trusted domains, subdomains included. |
WhitelistSenders |
(empty) | Trusted exact addresses. |
DeliverToJunkHeader |
1 |
Inject X-ME-Content: Deliver-To=Junk on tagged mail (routes to Junk on Standard). |
AuthServId |
mail.local |
authserv-id in Authentication-Results (use your hostname). |
TimeoutMs |
10000 |
spamd socket timeout. |
Debug / DebugLog |
0 / (path) |
One log line per scanned message. |
# comment
lottery # whole-word, case-insensitive
wire transfer # phrases work
re:v[i1]@?gra # regex (ECMAScript, case-insensitive)
re:\bact now\b
Edits take effect within KeywordReloadSeconds — no restart needed for keyword
changes (other INI settings still need an SMTP restart).
- Set
Debug=1, restart SMTP, send test mail, and read theDebugLogline:from=[…] dom=[…] tld=[…] tag=0/1 reasons=[…] sa-ok/sa-off/sa-unreachable. - Send from a disallowed TLD (e.g. a
.xyzaddress) → should be taggedTLD_NOT_ALLOWED(xyz)and land in Junk. - Put a word from
SpamKeywords.txtin a subject → taggedSUBJECT_KEYWORD(...). - Add the sender's domain to
WhitelistDomains→ next message delivers untouched. - (If spamd is up) GTUBE forces a spam verdict:
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
- The TLD allow-list is aggressive — your 5 TLDs also block
.edu .gov .ca .de .au .io .co .info …. WidenAllowedTlds, or lean onWhitelistDomainsfor the exceptions you trust. - Whole-word keyword matching is ASCII-boundary based; for obfuscated text use a
re:regex. Substring-style catches can be done with regex too (re:cialis). - Org-domain alignment uses a "last two labels" rule, not a full Public Suffix
List — imperfect for multi-part TLDs (
co.uk). Swap in a PSL table later if needed. - Only the first
DKIM-Signatureis considered for alignment. - The plugin marks only. To hard-reject the worst offenders, return
0with a5xxinResponse(e.g. forp=rejectDMARC failures). - Validate that header injection into
<messagepath>is honored by your exact MailEnable version before relying on it in production.