Policyguard - Early-Reject Postfix Policy Spamfilter für Google & Co.

PolicyGuard — Intelligenter Postfix-Spamfilter mit automatischer Lernfunktion

PolicyGuard ist ein in Python geschriebener Policy-Daemon für den Mail Transfer Agent Postfix. Er schaltet sich in den SMTP-Dialog ein und entscheidet in Echtzeit — noch bevor eine E-Mail vollständig angenommen wird — ob eine eingehende Nachricht zugestellt, abgelehnt oder temporär zurückgestellt wird.

Wie es mit Postfix zusammenarbeitet

Postfix leitet bei jeder eingehenden Verbindung Metadaten an den Daemon weiter: Absenderadresse, Empfänger, IP-Adresse des sendenden Servers, HELO-Name und Client-Hostname. PolicyGuard wertet diese Daten aus und antwortet mit einer Postfix-Direktive — entweder dunno (durchlassen), reject (sofort ablehnen) oder defer (temporär zurückstellen). Die eigentliche E-Mail wird dabei gar nicht erst übertragen, was den Server-Ressourcenverbrauch minimal hält.

Mehrstufige Filterkaskade

Jede eingehende E-Mail durchläuft mehrere Prüfebenen in fester Reihenfolge:

Empfänger-Blocklist — bestimmte Zieladressen werden pauschal abgewiesen

Client-Hostname-Blocklist — bekannte Spam-Infrastrukturen (z. B. google-usercontent) werden direkt geblockt

Regex-Filter — verdächtige Absender-Muster, typisch für Google-Groups-Missbrauch, werden erkannt

SPF-Prüfung — der sendende Server wird gegen den SPF-Eintrag der Absender-Domain geprüft; bei fail wird die Mail abgelehnt, bei Google-HELO zusätzlich softfail und permerror

Firebase-Erkennung — Domains, die Firebase-Mailversand nutzen, werden über SPF-Includes und TXT-Records erkannt und geblockt

Hunter.io-Erkennung — Domains, die im Abuse-Verzeichnis von Hunter.io gelistet sind, werden blockiert

Unbekannte Clients — Server ohne rDNS erhalten ein temporäres defer 450, was legitime Mailserver automatisch wiederholen lässt, Spam-Schleudern jedoch oft nicht

Das lernende Kernelement: die Auto-Blocklist

Das intelligenteste Feature ist die automatische Blocklist, die sich aus dem eigenen Mail-Journal aufbaut. Das Programm liest fortlaufend die Postfix-Logs via journalctl aus und zählt pro Absender-Domain, wie viele E-Mails blockiert versus akzeptiert wurden. Überschreitet eine Domain den konfigurierbaren Schwellenwert — standardmäßig 76% Blockierrate bei mindestens 4 Mails in den letzten 50 Tagen — wird sie automatisch zur Blocklist hinzugefügt. Das System lernt also aus dem eigenen Filterverhalten, ohne manuelles Eingreifen.

Effizienz durch Caching und inkrementelles Logging

Um bei jedem eingehenden Mail nicht neu rechnen zu müssen, hält PolicyGuard sämtliche Daten im RAM: die Auto-Blocklist, SPF-Auflösungen, DNS-TXT-Abfragen und Hunter.io-Ergebnisse werden gecacht. Die Journal-Daten vergangener Tage werden in einer lokalen JSON-Datei persistiert und nur einmalig eingelesen. Während des Betriebs liest das Programm lediglich inkrementell neue Journal-Einträge ein — höchstens alle 30 Sekunden — und aktualisiert die Blocklist bei Bedarf im Hintergrund. Über eine einfache Textschnittstelle lassen sich per stats- und blocklist-Kommando jederzeit Einblicke in das Filtergeschehen abrufen.


Installation unter Proxmox Mail-Gateway

Voraussetzungen

PolicyGuard läuft als Postfix Policy-Daemon unter Proxmox Mail Gateway (PMG). Für die Installation werden Root-Rechte benötigt.

1. Python-Abhängigkeiten installieren

apt install python3-spf python3-dnspython

2. Skript installieren

Das Skript nach /usr/local/bin/ kopieren und ausführbar machen:

cp policyguard.py /usr/local/bin/policyguard.py
chmod +x /usr/local/bin/policyguard.py

3. Arbeitsverzeichnis anlegen

PolicyGuard benötigt /t/ für den Journal-Cursor und den Cache:

mkdir -p /t/
chmod 777 /t/

4. Journal-Zugriff für nobody erlauben

PolicyGuard läuft unter dem Benutzer nobody und benötigt Lesezugriff auf das systemd-Journal. Dazu eine sudo-Regel anlegen:

visudo -f /etc/sudoers.d/policyguard

Folgenden Inhalt eintragen und speichern:

nobody ALL=(root) NOPASSWD: /usr/bin/journalctl

5. PMG-Konfigurationstemplates vorbereiten

Damit Änderungen an der Postfix-Konfiguration PMG-Updates überstehen, müssen die Templates in das Override-Verzeichnis kopiert werden — sofern noch nicht geschehen:

mkdir -p /etc/pmg/templates/
cp /var/lib/pmg/templates/master.cf.in /etc/pmg/templates/
cp /var/lib/pmg/templates/main.cf.in /etc/pmg/templates/

6. Postfix main.cf
main.cf.in – Sender-Restriktionen erweitern

In /etc/pmg/templates/main.cf.in den Policy-Dienst zu den smtpd_sender_restrictions hinzufügen:

smtpd_sender_restrictions =
                   check_policy_service unix:private/policygrd

Alternativ: – Recipient-Restriktion erweitern (nicht beides auf einmal)

In /etc/pmg/templates/main.cf.in den Policy-Dienst zu den smtpd_recipient_restrictions hinzufügen:

smtpd_recipient_restrictions =
                   check_policy_service unix:private/policygrd

Bestehende Restriktionen bleiben erhalten — die neue Zeile einfach in die vorhandene Liste einreihen.

7. Postfix master.cf

master.cf.in — Daemon-Eintrag ergänzen

Am Ende von /etc/pmg/templates/master.cf.in folgende zwei Zeilen einfügen. Die Zahl "9" sorgt dafür, dass der Service maximal 9 Instanzen auf einmal starten kann. Zu viele Services können einen OOM verursachen. Im Fall der Fälle puffert der smtpd die E-Mails oder weißt sie temporär ab, sie treffen dann kurze Zeit später erneut ein, aber der Proxmox hängt sich nicht wegen Speichermangel auf.

policygrd unix - n n - 9 spawn
    user=nobody argv=/usr/local/bin/policyguard.py

8. Konfiguration übernehmen

Nach dem Bearbeiten der Templates die PMG-Konfiguration neu generieren und Postfix neu laden:

pmgconfig sync --restart 1

Überprüfung und Test

apt install socat
socat - UNIX-CONNECT:/var/spool/postfix/private/policygrd

blocklist domo
==== BEGIN CURRENT BLOCKLIST ====
domointelligence.com
==== END CURRENT BLOCKLIST ====
stats domo
==== TOTAL DOMAIN STATS (all days + today) ====
  domointelligence.com           accept: 4  blocked: 31  total: 35  percent blocked: 88 %
==== END TOTAL DOMAIN STATS ====
stats 60 80
==== TOTAL DOMAIN STATS (all days + today) ====
  texbangla.com                  accept: 6  blocked: 24  total: 30  percent blocked: 80 %
  dachser.com                    accept: 8  blocked: 29  total: 37  percent blocked: 78 %
  rsgsv.net                      accept: 5  blocked: 18  total: 23  percent blocked: 78 %
  premium-box.eu                 accept: 11  blocked: 34  total: 45  percent blocked: 75 %
  hipalanet.com                  accept: 6  blocked: 18  total: 24  percent blocked: 75 %
  dubaidutyfreetennischampionships.com accept: 2  blocked: 6  total: 8  percent blocked: 75 %
  bobsbonsai.com                 accept: 6  blocked: 16  total: 22  percent blocked: 72 %
  momentstudio.ca                accept: 7  blocked: 18  total: 25  percent blocked: 72 %
  table.media                    accept: 2  blocked: 5  total: 7  percent blocked: 71 %
  carvertical.com                accept: 2  blocked: 4  total: 6  percent blocked: 66 %
  andia-international.com        accept: 7  blocked: 14  total: 21  percent blocked: 66 %
  mandrillapp.com                accept: 2  blocked: 4  total: 6  percent blocked: 66 %
  o2lenses.com                   accept: 3  blocked: 6  total: 9  percent blocked: 66 %
  equinestar.net                 accept: 6  blocked: 11  total: 17  percent blocked: 64 %
==== END TOTAL DOMAIN STATS ====

Unterschied: Sender vs. Recipient Restriction

Wenn Policyguard in der Recipient Restriction eingesetzt wird, ist er in der Lage, einen 550 5.1.1-Statuscode zurückzugeben und vorzutäuschen, dass eine Mailbox nicht existiert. Dies kann bei einigen Newsletter-Anbietern effektiv sein, jedoch nicht bei echtem Spam.

Um mögliche Probleme zu vermeiden, gibt Policyguard diesen Fehler nur außerhalb der üblichen Geschäftszeiten zurück (22:00–06:00 Uhr, Montag–Samstag, sowie 00:00–24:00 Uhr am Sonntag) und auch nur innerhalb einer konfigurierbaren prozentualen Quote, die in der policyguard.toml festgelegt wird. Standardmäßig steht dieser Wert auf 0, das heißt, es wird immer 550 5.7.1 (policy reason) zurückgegeben.


Was ist der Unterschied zwischen Sender Restriction und Recipient Restriction?

Die Sender Restriction wird zeitlich vor der Recipient Restriction ausgewertet.

Sie erfolgt im gleichen Kontext wie die Verarbeitung von Configuration → Mail Proxy → Welcomelist.
Wenn Policyguard in der Sender Restriction unterhalb von /etc/postfix/senderaccess eingetragen wird, kann die Mail Proxy → Welcomelist effektiv als Whitelist für Policyguard genutzt werden. Dies kann für einige Administratoren ein hilfreiches Feature sein.

Während der Auswertung der Sender Restriction ist jedoch noch kein Empfänger bekannt. Daher verweigert Postfix an dieser Stelle die Rückgabe eines 550 5.1.1 (Mailbox existiert nicht)-Statuscodes, da noch keine Aussage über den Empfänger getroffen werden kann. Entsprechend sollte in der /etc/policyguard.toml die Einstellung pretend_non_existing_mailbox = 0 gesetzt werden. Dadurch wird sichergestellt, dass kein 550 5.1.1 zurückgegeben wird.


Die Recipient Restriction wird anschließend in einem separaten, späteren Verarbeitungsschritt ausgewertet.

In diesem Kontext greift die Mail Proxy → Welcomelist nicht mehr, und eine Ablehnung durch Policyguard kann darüber nicht umgangen werden. Für ein Whitelisting innerhalb von Policyguard müssen daher zwingend die vorgesehenen Whitelist-Mechanismen (Sender, HELO, Client) in der /etc/policyguard.toml verwendet werden.

In dieser Phase kann Policyguard einen 550 5.1.1 (Mailbox existiert nicht)-Statuscode zurückgeben.

Quellcode und config (/etc/policyguard.toml)

policyguard.py

policyguard.toml