A mail gateway we run ourselves
Reference client: Logistics and trading group in Tyrol, Austria · ~100 employees · 4 sites
Customer data in copy and images has been neutralised.
Starting point
The group's mail gateway used to be a vendor's Windows software. We wanted to see what happens to every message and to be able to change the behaviour ourselves.
Since 23 September 2026 the gateway has run on our own Linux system, built by us. It accepts the mail, checks it and passes on only what has been checked.
The hard part
A mail filter can be wrong in two ways, and both cost money. If it lets malware through, there is an incident. If it holds back a genuine customer order, there is a phone call. When in doubt the gateway has to hold, but in a way that lets a person release the message within minutes and never loses one.
We also set ourselves a rule: protection functions and their display run inside the app itself. Only the AI scoring and the DNS blocklists come from outside.
Solution
Postfix accepts the mail, a Python service scores it, a PostgreSQL database holds rules, log and the held messages, and our own interface shows all of it.
Two virus scanners check every attachment, ClamAV and ESET, and both must report clean. If a scanner gives no verdict, the gateway rejects the message with a temporary error (451). It is retried later, nothing passes unchecked.
Suspicious messages go to a hold store, and a person releases or deletes them. An AI classifier scores along but decides nothing yet: it runs in shadow mode until its hit rate is proven.
How it is built
Every message passes a fixed sequence: acceptance, greylisting, virus scan, spam scoring, rules. The end result is one of three decisions: deliver, hold or reject. Every decision is logged with its reason.
Zip files stay on the message if the sender rule allows it and the zip and every file inside is clean at both scanners. Otherwise the attachment sits in the portal, and the message carries a notice file with the queue ID. A timer reports every removed attachment to the administrators every five minutes.
Every delivered message also goes as a journal copy to two archives. The journal is mirrored into the ERP database every hour.
The gateway queries the DNS blocklists itself and shows size and response time per list in the interface. A list counts as active only once it has its own probe in the app.
Day-to-day operation
A self-check runs every 15 minutes. On a new deviation or a critical finding, a mail goes to the administrators.
Updates run in a fixed evening window. Before anything is rolled out, the running version must be contained in the new branch, otherwise the script aborts. After every database restart Postfix reloads its tables, because otherwise dead connections remain.
Outcome
In the 30 days to 7 October 2026, 91,950 messages arrived from outside. The gateway rejected 10,108, which is 11 percent. It held 1,267 messages, 51 of them for malware. A person released 87 and deleted 1,056.
Measured in the gateway's message database, as of 7 October 2026.
What we learned
The AI classifier stays in shadow mode. On text alone it reached a separation (AUC) of 0.889 on our held messages, which does not protect genuine orders reliably enough. With metadata and our own model on the CPU it reaches 0.971. By 18 October 2026 we decide whether to switch it on.
Other projects we run

SIEM & security monitoring with real-time correlation
Company-wide logs in one place, and only the alerts that matter.

Migrating from VMware to Proxmox
Out of the licence trap: a six-node HA cluster across two sites, migrated during live operation.
Similar problem?
Tell us what you're planning, a short call clarifies whether it pays off.
senn-tech