How it works · technical deep-dive

An 8-stage pipeline. A hybrid AI brain. A cluster built for redundancy.

Every inbound message passes through eight independent layers before a verdict is reached. The scoring layer combines a gradient-boosted classifier trained on a 30-year ISP's live honeypot corpus with Claude (Anthropic's large language model) on the borderline cases. Every component is horizontally scaled across redundant nodes.

8
Pipeline stages
~120
ML features
0.988
Model AUC
N+1
Node redundancy

Architecture

The 8-stage pipeline.

Every layer can reject. Every verdict is logged with a transparent score breakdown and, where Claude was involved, the reasoning it produced.

SMTP in TLS 1.2/1.3 Postfix smtpd 1. Postscreen DNSBLs ×6 PREGREET DNSWL whitelist 2. Envelope policyd-spf Rate limit 30/min, 60 msg/min 3. Recipient verify backend pgsql transport + verify cache 4. Content ClamAV scan DKIM · DMARC URIBL ×3 5. Milter scanner.py port 7358 feature extract 6. Hybrid AI brain ML scoring (LightGBM) AUC 0.988 · ~3.4 ms + Claude LLM eval verdict + reason REJECT score ≥ 0.97 550 at SMTP time QUARANTINE 0.85 ≤ score < 0.97 30-day retention PASS score < 0.85 delivered onward 7. ARC seal opendkim + openarc AuthservID set 8. Backend MX delivered to mailbox Reputation Redis · 7-day rolling per-domain ham/spam read/write Audit + metrics PostgreSQL 16 + Prometheus /metrics

Pipeline stages

Eight layers, in order.

Every numbered stage corresponds to the architecture diagram above.

01

Postscreen — connection-level triage

Before any SMTP command is processed, Postfix's postscreen daemon inspects the connecting IP. It applies pre-greet checks (talk-before-listen detection), pipelining checks, and queries six independent DNSBLs in parallel.

DNSBLs: zen.spamhaus.org ×3 · spam.dnsbl.sorbs.net ×2 · cbl.abuseat.org ×3 · bl.mailspike.net · psbl.surriel.com · threshold 3

DNSWL: list.dnswl.org — trusted senders bypass the postscreen tarpit

02

Envelope — SPF and rate limits

SPF is evaluated by policyd-spf via Postfix's check_policy_service. Hard-fail enforces; soft-fail contributes a feature to the ML score. Per-source rate limits cap abusive senders without blocking legitimate spikes.

Rate limits: 30 connections/min · 60 messages/min · 100 recipients/message

03

Recipient — verify backend exists

reject_unverified_recipient probes your backend mail server at SMTP time to confirm the recipient is real. Results are cached so probes don't repeat for every message. Eliminates backscatter on bad addresses.

Transport map: proxy:pgsql:/etc/postfix/pgsql-transport.cf · backend verified before any content is queued

04

Content — antivirus, DKIM, DMARC, URIBL

ClamAV scans every attachment, including archives and Office macros. DKIM signatures verified by opendkim, DMARC alignment enforced by opendmarc. Body URLs cross-referenced against three URIBLs.

URIBLs: multi.uribl.com · multi.surbl.org · dbl.spamhaus.org

05

Milter — feature extraction

The MxGuard milter (scanner.py) parses headers, body, URLs and attachments. It extracts ~120 features across six buckets (envelope, headers, subject/body, URLs, attachments, reputation) and assembles the feature vector for the classifier.

Implementation: Python 3 + python3-pymilter · in-process · loopback socket 127.0.0.1:7358

06

Hybrid AI brain — ML + Claude

The LightGBM classifier scores the feature vector in ~3.4 ms. If the score lands in the uncertain band (0.50–0.95), the message body is sent to Claude via the Anthropic API. Claude reads it for intent and impersonation cues, returns a verdict and a written reason, which is logged with the message.

Thresholds: ≥ 0.97 reject · 0.85–0.97 quarantine · 0.50–0.85 tag · < 0.50 pass

07

ARC seal — authentication preservation

openarc seals the message with an ARC signature carrying the original DKIM/SPF/DMARC results forward. Downstream receivers can trust the original authentication even though MxGuard re-routed the message. Critical for forwarders and mailing-list compatibility.

AuthservID: mx1.mxguard.uk · signs all forwarded mail · RFC 8617 compliant

08

Backend delivery

Clean mail is delivered to the customer's real mail server via SMTP. Standard retry behaviour if the backend is briefly unavailable. Local queue isolation per node means a slow backend on one customer doesn't slow other customers' mail.

Training data

Trained on a 30-year ISP's live honeypot network.

Most anti-spam vendors train on stale public corpora supplemented by a single feedback loop. MxGuard's classifier is trained on something rarer: real, fresh, labelled spam captured continuously by Transcom's own global honeypot network — the same data that has fed our blocklist and abuse-reporting operations since the mid-1990s.

Source 1

Global honeypot platform

SigmaNetworks / CentralMail operates relay honeypots in Brazil, Canada, India, Japan, Sydney, and the UK. Each node accepts mail it knows is spam (no real recipients) and ships every received message back to the central corpus.

≥ 6 geographic regions
continuous real-time capture
full headers + body retained
Source 2

30 years of ISP ham

Transcom has operated as a UK ISP since 1993. We have decades of labelled legitimate mail patterns — transactional, mailing list, business correspondence, newsletters — that anchor the “clean” side of the training set against false positives.

est. 1993
diverse legitimate traffic
realistic ham distribution
Source 3

Public reference corpora

Layered on top: Enron, SpamAssassin, TREC, and similar academic datasets used industry-wide. They give the model a stable, reproducible baseline; our honeypot data gives it the edge on what's actually being sent this week.

Enron email dataset
SpamAssassin public corpus
TREC spam tracks

Why this matters

Spam evolves weekly. New domains, new lure templates, new infrastructure, new social-engineering angles. A model trained on data from 2022 misses what was sent yesterday. MxGuard's training corpus is updated continuously from live honeypot capture — the same model retrain pipeline that feeds our DNSBL contributions and AbuseIPDB reports also feeds the classifier.

The result: the classifier sees fresh attack patterns within hours of them appearing in the wild, not months later when a quarterly model refresh ships.

The AI brain

Two layers. One verdict.

Layer 1 — an in-process gradient-boosted classifier — decides the easy 95% in milliseconds. Layer 2 hands the genuinely uncertain messages to Claude, Anthropic’s large language model, which reads them the way a person would on a second look.

LAYER 1

LightGBM classifier

A gradient-boosted decision-tree ensemble trained on hundreds of thousands of labelled messages from our honeypot corpus and the public datasets above. Runs in-process inside the milter; no external API call. Continuously retrained as new honeypot data arrives.

AlgorithmLightGBM v1
AUC0.988
Features~120
Median latency3.4 ms
Outputscore ∈ [0, 1]
Decides~95% of mail
LAYER 2

Claude (Anthropic)

When the LightGBM score lands in the uncertain band, the message body and headers are sent to Claude via the Anthropic API. Claude evaluates intent, urgency cues, impersonation patterns, lookalike-domain references and call-to-action structure — producing a verdict and a written reason that is logged with the message.

Triggered when0.50 ≤ score < 0.95
Readsfull body + headers
Outputsverdict + reason
Optimised forBEC, impersonation
Handles~5% of mail
Trainingnone on customer mail

The ~120 ML features, by bucket

What the gradient-boosted model is actually looking at.

Envelope

Source IP reputation, ASN, rDNS sanity, HELO/EHLO conformance, MAIL FROM domain age, SPF result.

Headers

From/Reply-To divergence, display-name impersonation, Message-ID structure, Received chain length, DKIM result, DMARC alignment.

Subject & body

Subject decoded (RFC 2047), urgency markers, gibberish local-part references, money/wire/invoice language, length and structure ratios.

URLs

Count, domain age, TLD distribution, URIBL hits, shorteners, IP-literal URLs, mixed-script hosts.

Attachments

MIME mismatch, archive depth, macro presence, suspicious extensions, ClamAV verdict, encrypted-payload flags.

Reputation

7-day rolling ham/spam ratio per sender domain (Redis-cached), recipient’s prior interaction with this sender, ham-discount status.

Cluster architecture

Built as a cluster, not a single server.

MxGuard runs as a horizontally-scaled cluster of identical MX nodes. Every component — SMTP, ML scoring, database, cache — is redundant. There is no single point of failure that can stop mail flowing.

Sender SMTP traffic DNS MX priority routing MX CLUSTER — UK datacentres mx1.mxguard.uk ACTIVE Postfix scanner.py milter ClamAV opendkim / opendmarc openarc /metrics mx2.mxguard.uk ACTIVE Postfix scanner.py milter ClamAV opendkim / opendmarc openarc /metrics mx3.mxguard.uk ACTIVE Postfix scanner.py milter ClamAV opendkim / opendmarc openarc /metrics mx-N EXPANSION Horizontal scale-out on demand. Identical stack per node. SHARED BACKEND — replicated PostgreSQL 16 primary streaming replication → hot standby automatic failover Redis (Sentinel) 3-node quorum reputation cache verify cache rate-limit counters Quarantine store object storage S3-compatible UK region 30-day retention app.mxguard.uk FastAPI + nginx console + REST API Prometheus scrape heartbeat monitor Every MX node connects to every backend. Lose any node, any database, any cache — mail keeps flowing.
MX layer

N+1 SMTP nodes

Multiple active MX hosts; DNS MX priority spreads load. Any single node can be drained for maintenance with zero downtime.

Database

Primary + hot standby

PostgreSQL 16 with streaming replication. Automatic failover; reads can be served from the replica.

Cache

Redis Sentinel quorum

Reputation, verify, and rate-limit data live in a 3-node Redis cluster fronted by Sentinel. No single Redis node failure can stall scoring.

Queueing

Per-node Postfix queue

Each node maintains its own outbound queue. A slow backend on one customer cannot block another customer's mail.

Technical specification

Full spec sheet.

Every component, every standard, every number.

Transport
SMTP serverPostfix 3.x
TLSTLS 1.2 / 1.3, opportunistic; LE certs auto-renewed
Listening25 (mta), 465 (submissions), 587 (submission)
Rate limits30 conn/min, 60 msg/min, 100 rcpt/msg per source
Pre-content layer
Postscreen DNSBLszen.spamhaus.org ×3, spam.dnsbl.sorbs.net ×2, cbl.abuseat.org ×3, bl.mailspike.net, psbl.surriel.com; threshold 3
DNSWLlist.dnswl.org — trusted-sender bypass on hi/med scores
SPFpolicyd-spf (check_policy_service)
Recipient verificationreject_unverified_recipient via proxy:pgsql transport map
Content layer
AntivirusClamAV (clamav-milter); signature feed clamav-freshclam
URIBLsmulti.uribl.com, multi.surbl.org, dbl.spamhaus.org
DKIMopendkim — verify inbound, sign outbound
DMARCopendmarc — alignment + policy enforcement
ARCopenarc — AuthservID=mx1.mxguard.uk; seals forwarded mail
AI scoring
Milterscanner.py on 127.0.0.1:7358 (python3-pymilter)
ML modelLightGBM v1 gradient-boosted trees, ~120 features, AUC 0.988
ML latency~3.4 ms median, < 5 ms p95
LLM evaluatorClaude (Anthropic) via API — triggered on 0.50 ≤ score < 0.95; reads body + headers; outputs verdict + written reason
Verdict thresholds≥ 0.97 reject · 0.85–0.97 quarantine · 0.50–0.85 tag · < 0.50 pass
Cluster & storage
MX nodesN+1 active SMTP hosts behind DNS MX priority; horizontal scale-out
DatabasePostgreSQL 16, primary + hot-standby streaming replica, TZ Europe/London
CacheRedis 5+ with Sentinel quorum; reputation, verify, rate-limit data
Quarantine retention30 days default (0–365 configurable), purged daily 04:00
Audit logEvery release / delete / rule edit / label change; searchable, exportable
RegionUK only — processing and storage
Console & API
Web consoleFastAPI + HTMX, served via nginx at app.mxguard.uk
Live feedReal-time verdict stream; releases, allow/block from row
Daily digest600px mobile-first email, one-click release/delete/allow
REST APIDomain mgmt, rules, verdicts, quarantine actions; key-auth
MetricsPrometheus /metrics endpoint, per-domain counters

Standards

RFCs and protocols implemented

RFC 5321 · SMTP
RFC 5322 · Message format
RFC 2047 · Encoded headers
RFC 6376 · DKIM
RFC 7208 · SPF
RFC 7489 · DMARC
RFC 8617 · ARC
RFC 8058 · List-Unsubscribe-Post
RFC 2369 · List-Unsubscribe
RFC 3463 · Enhanced status codes
RFC 3461 · DSN
RFC 8689 · STARTTLS reporting

Setup

Protected in three steps.

From sign-up to live mail filtering: typically 10 minutes plus DNS propagation.

01

Add your domain

From your dashboard, enter the domain and the hostname of your real mail server (where clean mail should land). Done in 30 seconds.

02

Verify ownership

Add a single TXT record to your DNS. Click verify. We confirm via DNS lookup and flip the domain to active.

03

Point your MX

Add two MX records:

MX  10  mx1.mxguard.uk.
MX  20  mx2.mxguard.uk.

mx1 is primary; mx2 is automatic failover. Mail begins flowing through MxGuard within minutes.