self-hosted · open source · Rust + Python
A drop-in mail gateway
for your mail server.
postArmor sits in front of Postfix, Exchange, or any SMTP backend. It scans every inbound message through 30+ layered checks — from IP reputation to ClamAV to a cascaded ML classifier with LLM fallback — and quarantines threats without touching your existing mail configuration.
What it does
Inbound mail hits a small Rust binary (~5 MB RSS) that runs rejection gates cheapest-first: IP reputation, rDNS, SPF, protocol compliance, content blocklists, and an inline FastText classifier — all before the message leaves the DATA phase. Survivors get DKIM / DMARC verification and hand off to an async worker for deep analysis.
The worker runs ClamAV antivirus, Tesseract OCR, archive extraction with password cracking, file type verification, and a four-stage cascade classifier: FastText, Bayesian, transformer, then LLM. A neural network post-filter and safety guards produce the final verdict. Results are cached; operator labels retrain the models in-place with no restart.
Quarantined messages are held for admin review or recipient self-service via HMAC-signed links — no accounts needed. Periodic digest emails summarize pending items with one-click release, delete, and block-sender actions.
Everything runs in Docker Compose on a single machine: SMTP, API, worker, classifier, ClamAV, OCR, Valkey, PostgreSQL, and an nginx + React dashboard. Point your MX records at it and you have a full filtering tier in under ten minutes.
Features
120+ capabilities across SMTP hardening, content analysis, machine learning, and operations. Every check is individually toggleable from the dashboard.
SMTP & Protocol Hardening
- Rust + tokio server, ~5 MB idle RSS, ports 25 / 587, STARTTLS, full ESMTP state machine
- RBL / DNSBL with IPv4 + IPv6, reverse DNS, Forward-Confirmed rDNS
- SPF check, DKIM verify (RFC 6376), DMARC evaluate (RFC 7489) with off / tag / reject
- ARC sealing (RFC 8617) for downstream forwarders, with startup DNS sanity-check
- REQUIRETLS (RFC 8689) — mandate TLS on every delivery hop
- SMTP smuggling hardening (CVE-2023-51764) — strict CRLF enforcement in DATA
- EHLO LIMITS extension (RFC 9422) — advertise session constraints to clients
- HELO/EHLO validation, pre-banner detection, unsolicited pipelining detection
- Sender domain MX/A validation, null sender rate limiting, per-IP rate limiting (4 dimensions)
- Automatic IP blocking with sliding-window rejection counter
- Homoglyph / IDN punycode detection in addresses, display names, and URLs
- VIP impersonation / display-name spoofing detection with protected name list
Content Analysis & Threat Detection
- ClamAV antivirus (INSTREAM TCP) — scans HTML bodies and attachments, fail-open
- Tesseract OCR sidecar — extracts text from image attachments before classification
- Archive scanning (ZIP, tar.gz) with password cracking (common + body-extracted passwords)
- Nested archive recursive extraction with zip bomb protection (depth, size, file count limits)
- File type verification — magic bytes vs declared extension, catches renamed executables
- SURBL / URIBL URL reputation checking with configurable blocklists
- Cross-recipient burst scoring — detects spam campaigns via attachment hash + URL tracking
- Content-hash blocklist (exact SHA-256) and fuzzy SimHash blocklist (Hamming distance)
- Header analysis — injection detection, routing-loop detection, RFC 5322 compliance
- BEC intent detection — wire transfer requests, authority impersonation, Reply-To mismatch, urgency/secrecy pressure
- External sender warning banner — inline body or
X-External-Senderheader
Cascaded ML Classification
- Stage 1: FastText — sub-5 ms prediction, runs inline during DATA for early rejection
- Stage 2: Bayesian — Robinson-Fisher classifier, incremental learning from feedback
- Stage 3: Transformer — CPU-based model for borderline cases
- Stage 4: LLM — Ollama (local) or Claude API with SPF/DKIM/DMARC context injected
- Neural post-filter — PyTorch network blends all upstream signals into final probability
- Safety guards — final guard forces quarantine on strong malware/phishing signals; phishing guard suppresses reputation bonuses for compromised senders
- Content-hash caching — duplicate messages skip the entire pipeline
- Per-stage verdict source tracked and shown in the dashboard
- Decision confidence level (HIGH / MEDIUM / LOW) derived from signal strength
Sender Reputation
- Per-IP and per-domain scores (0.0–1.0), computed hourly from spam/ham/reject/virus ratios
- Configurable bad-sender action: reject at SMTP or penalize in analysis pipeline
- Score decay toward neutral after inactivity, minimum sample threshold
- Phishing guard suppresses positive reputation when compromise indicators appear
- Admin dashboard page with sortable table, manual score override, and reset
- Domain age check via RDAP — flags recently registered sender domains with tiered TTL caching
- Received chain hop analysis — detects excessive hops, backwards timestamps, and unusual relay delays
- Threat intelligence feeds (abuse.ch) — URLhaus, Feodo Tracker, ThreatFox with periodic sync and Valkey-cached lookups
Quarantine & Delivery
- Full quarantine management: view, preview, bulk release / delete, auto-expire
- Recipient self-service portal via HMAC-signed URLs — no accounts or passwords
- Periodic digest emails with one-click release, delete, and block-sender actions
- Release guards: virus-infected blocked, high-score requires confirmation
- RFC 5321 delivery retry with exponential backoff (5 min → 96 h), per-domain routing
- Allow / block lists by email address, domain, or IP
Feedback & Model Training
- One-click mark-as-spam / mark-as-ham from email log and quarantine
- Auto-labeling: LLM disagreements with fast stages generate training rows
- Admin-triggered FastText and neural network retraining from the dashboard
- Atomic model swap — no container restart needed
- Humans-only retrain toggle to exclude auto-labels when drift is suspected
Dashboard & Operations
- React dashboard with real-time WebSocket email feed and TanStack Query
- Stats: 24 h volume, spam rate, analysis latency, threat distribution chart
- Email detail drawer with full LLM reasoning, scores, categories, and body preview
- System health panel: SMTP, DB, Valkey, Ollama, ClamAV (signature version), Anthropic
- SMTP debug trace: per-session protocol log with swaks-style view, toggleable at runtime
- Blocked page: paginated log of all SMTP-level rejections with phase and reason
- Cache management panel with live counts and one-click clear
Self-Hosted & Auditable
- Runs entirely on your hardware — no SaaS dependency, no phone-home
- Full source on GitHub: Rust (SMTP + worker), Python (API + classifier), React (dashboard)
- Docker Compose deployment — one machine, ten-minute setup
- Every setting toggleable live from the dashboard, no restart required
How it works
One sending MTA talks to one Rust binary. Everything else hangs off Valkey and PostgreSQL.
Sending MTA
|
v
+---------------------------------------------------------------+
| smtp_rust DATA-phase pipeline (cheapest first) |
| |
| rate-limit --> RBL/SPF --> reputation --> header/attach --> |
| homoglyph/IDN --> strict CRLF --> content-hash --> SimHash |
| --> FastText inline --> DKIM/DMARC --> REQUIRETLS --> insert |
| |
| EHLO: SIZE · PIPELINING · STARTTLS · REQUIRETLS · LIMITS |
+---------------------------------------------------------------+
| |
v v
PostgreSQL <------ worker_rust -------> Valkey
|
+---------+-------+-------+---------+---------+
v v v v v v
ClamAV file archive OCR classifier LLM
antivirus type scan Tesseract FastText Ollama
verify pw crack Bayesian Claude
transformer
|
reputation adjust
+ phishing guard
+ final guard (WFG)
+ neural post-filter
+ confidence level
Inbound mail gets rejected at the earliest stage that can decide — a spam-blast hit on the content-hash or SimHash blocklist never pays the DKIM DNS lookup cost. Messages that survive the DATA pipeline land in PostgreSQL, get enqueued in Valkey, and are picked up by the worker for antivirus scanning and cascade classification. Confident FastText or transformer verdicts write a final decision directly; borderline cases escalate to the LLM tier.
Quick start
postArmor runs on Linux, macOS, or anything that runs Docker. On a fresh Debian 12 / 13 host the bootstrap script installs every dependency in one shot.
Clone & configure
git clone https://github.com/ahmetbuba/postarmor.git
cd postarmor
make setup # copies .env.example -> .env
$EDITOR .env # set DB password, backend SMTP host, admin password
Bootstrap the host (Debian 12 / 13)
sudo ./scripts/prepare_debian.sh # install everything
sudo ./scripts/prepare_debian.sh --check # verify-only
newgrp docker # activate group membership
Start the stack
make up # builds all images and starts services (~5 min first run)
make migrate # creates the database schema
make pull-model # downloads llama3.2:3b (~2 GB, one-time)
Open the dashboard
open http://localhost
# login with ADMIN_USERNAME / ADMIN_INITIAL_PASSWORD from .env
Point your MX records (or inbound SMTP relay) at this server on port
25. Set BACKEND_SMTP_HOST or configure domain routes in
the dashboard to send cleaned mail onward to your real backend.