{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreigx2rtq2vtb5b6hyjcwml557ix3nsns75n3ksglgafq5lhdjn7kaq",
"uri": "at://did:plc:nkxz2ojdvmieg2nhphvputvp/app.bsky.feed.post/3mmnwqzk562x2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreiea7ivkrx7rquzobck3adrb67kkiizwgtb2ml2aowpt5baqsmmv4e"
},
"mimeType": "image/png",
"size": 793311
},
"description": "Rspamds Webinterface ist praktisch zum Testen, aber fuer produktives Spam/Ham-Lernen unbrauchbar. Automatisierung mit Dovecot, IMAPSieve und einem Learn-Ordner pro Nutzer. Falsch klassifizierte Mails einfach in den Ordner schieben, Rspamd lernt mit.",
"path": "/2020/05/04/rspamd-automatisch-spam-ham-lernen-mit-dovecot-und-imapsieve/",
"publishedAt": "2026-05-25T07:17:57.000Z",
"site": "https://www.kernel-error.de",
"tags": [
"Dovecot",
"Email",
"InfoSec",
"MailServer",
"RSPAMD",
"SelfHosted",
"SPAM",
"Sysadmin",
"IMAPSieve",
"Bayes-Klassifikator",
"GPT-basierte Spam-Erkennung in rspamd integriert",
"Postfix und AMaViS: content_filter oder smtpd_proxy_filter?",
"DMARC-Prüfung in Postfix: OpenDMARC und rspamd im Vergleich",
"Kontaktseite"
],
"textContent": "Rspamd hat ein Webinterface. Da kann man E-Mails reinkopieren und als Spam oder Ham markieren. Klingt erstmal praktisch. Ist es aber nicht. Niemand kopiert ernsthaft den Quellcode jeder fehlklassifizierten Mail in ein Webformular. Das macht man einmal zum Testen und dann nie wieder.\n\nWas man eigentlich will: Wenn ein Benutzer eine Mail in den Junk-Ordner verschiebt, soll rspamd das automatisch als Spam lernen. Und wenn eine Mail aus dem Junk-Ordner rausgeholt wird, soll rspamd sie als Ham lernen. Kein Webinterface, kein manueller Eingriff. Der Benutzer sortiert einfach seine Mails — und rspamd lernt mit.\n\nGenau das geht mit Dovecot und IMAPSieve. Hier beschreibe ich, wie ich das bei mir eingerichtet habe. Die Konfiguration läuft seit Mai 2020 unverändert — über sechs Jahre, ohne eine einzige Anpassung. Das darf man ruhig als stabil bezeichnen.\n\n### Was passiert da eigentlich\n\nDer Datenfluss ist simpel:\n\n * Benutzer verschiebt eine Mail in den Ordner „Junk“\n * Dovecot erkennt die Verschiebung per IMAPSieve\n * IMAPSieve startet ein Sieve-Script\n * Das Sieve-Script ruft ein Shell-Script auf\n * Das Shell-Script übergibt die Mail per `rspamc` an rspamd\n * Rspamd lernt die Mail als Spam (Bayes-Klassifikator)\n\n\n\nIn die andere Richtung genauso: Mail raus aus Junk, Dovecot erkennt es, rspamd lernt Ham. Egal ob der Benutzer über Thunderbird, Roundcube, ein Smartphone oder was auch immer sortiert — solange es IMAP ist, greift das.\n\n### Voraussetzungen\n\n * **Dovecot** mit Sieve-Support (`dovecot-pigeonhole` unter FreeBSD, `dovecot-sieve` unter Debian/Ubuntu)\n * **Rspamd** mit laufendem Controller-Worker\n * **rspamc** CLI-Tool (kommt mit rspamd mit)\n\n\n\nMein Setup läuft auf FreeBSD. Die Pfade beginnen daher mit `/usr/local/`. Unter Linux ist es `/etc/dovecot/` statt `/usr/local/etc/dovecot/` und `/usr/lib/dovecot/` statt `/usr/local/libexec/dovecot/`. Ansonsten ist alles identisch.\n\nMein rspamd läuft in einer eigenen Jail und lauscht auf `127.0.0.3:11334`. Wer rspamd lokal auf dem gleichen System hat, nimmt stattdessen `127.0.0.1:11334` oder den Unix-Socket.\n\n### Dovecot konfigurieren\n\nZuerst muss das Sieve-Plugin für IMAP aktiviert werden.\n\n**20-imap.conf:**\n\n\n protocol imap {\n mail_plugins = $mail_plugins sieve\n }\n\nDann die IMAPSieve-Konfiguration. Hier wird festgelegt, welche Ordner-Aktionen welches Sieve-Script auslösen.\n\n**90-plugin.conf:**\n\n\n plugin {\n sieve_plugins = sieve_imapsieve sieve_extprograms\n\n # Wenn eine Mail in den Junk-Ordner kopiert oder dort ein Flag geaendert wird\n imapsieve_mailbox1_name = Junk\n imapsieve_mailbox1_causes = COPY FLAG\n imapsieve_mailbox1_before = file:/usr/local/etc/dovecot/sieve/report-spam.sieve\n\n # Wenn eine Mail AUS dem Junk-Ordner woanders hin verschoben wird\n imapsieve_mailbox2_name = *\n imapsieve_mailbox2_from = Junk\n imapsieve_mailbox2_causes = COPY\n imapsieve_mailbox2_before = file:/usr/local/etc/dovecot/sieve/report-ham.sieve\n\n sieve_pipe_bin_dir = /usr/local/libexec/dovecot\n\n sieve_global_extensions = +vnd.dovecot.pipe\n }\n\nZwei Trigger: Einer für „Mail landet im Junk“ (→ Spam lernen), einer für „Mail verlässt Junk“ (→ Ham lernen). `COPY` deckt Verschieben ab, `FLAG` fängt den Fall ab, dass ein Mail-Client den Junk-Status per Flag statt per Verschieben setzt.\n\n### Sieve-Scripts\n\nJetzt die beiden Sieve-Scripts, die von IMAPSieve aufgerufen werden.\n\n**report-spam.sieve** — wird ausgelöst, wenn eine Mail im Junk-Ordner landet:\n\n\n require [\"vnd.dovecot.pipe\", \"copy\", \"imapsieve\", \"environment\", \"imap4flags\"];\n\n if environment :is \"imap.cause\" \"COPY\" {\n pipe :copy \"sa-learn-spam.sh\";\n }\n\n # Beantworteten oder weitergeleiteten Spam ebenfalls lernen\n elsif anyof (allof (hasflag \"\\\\Answered\",\n environment :contains \"imap.changedflags\" \"\\\\Answered\"),\n allof (hasflag \"$Forwarded\",\n environment :contains \"imap.changedflags\" \"$Forwarded\")) {\n pipe :copy \"sa-learn-spam.sh\";\n }\n\nDer erste Block fängt das normale Verschieben ab. Der zweite Block ist für einen Sonderfall: Wenn jemand auf eine Mail im Junk-Ordner antwortet oder sie weiterleitet, ändert sich das Flag — und auch das sollte als Spam gelernt werden.\n\n**report-ham.sieve** — wird ausgelöst, wenn eine Mail den Junk-Ordner verlässt:\n\n\n require [\"vnd.dovecot.pipe\", \"copy\", \"imapsieve\", \"environment\", \"variables\"];\n\n if environment :matches \"imap.mailbox\" \"*\" {\n set \"mailbox\" \"${1}\";\n }\n\n if string \"${mailbox}\" [ \"Trash\", \"train_ham\", \"train_prob\", \"train_spam\" ] {\n stop;\n }\n\n pipe :copy \"sa-learn-ham.sh\";\n\nHier passiert etwas Wichtiges: Bevor die Mail als Ham gelernt wird, prüfen wir wohin sie verschoben wurde. Wenn sie im Papierkorb landet, war das vermutlich kein „Das ist kein Spam“ sondern ein „Ich lösche den Spam“. Deshalb: `stop;` für Trash und die Trainingsordner. Nur wenn die Mail in einen echten Ordner verschoben wird, ist es ein Ham-Signal.\n\nBeide Scripts müssen kompiliert werden:\n\n\n sievec /usr/local/etc/dovecot/sieve/report-spam.sieve\n sievec /usr/local/etc/dovecot/sieve/report-ham.sieve\n\n### Shell-Scripts für rspamc\n\nDie Sieve-Scripts rufen Shell-Scripts auf, die die Mail per `rspamc` an rspamd übergeben. Simpel — jeweils ein Einzeiler.\n\n**/usr/local/libexec/dovecot/sa-learn-spam.sh:**\n\n\n #!/bin/sh\n exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_spam\n\n**/usr/local/libexec/dovecot/sa-learn-ham.sh:**\n\n\n #!/bin/sh\n exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_ham\n\nDie Dateinamen `sa-learn-*` kommen historisch von SpamAssassin. Verwirrend, wenn man rspamd nutzt. Man könnte sie auch `rspamd-learn-spam.sh` nennen — funktional ist es egal. Ich habe sie so gelassen, weil man funktionierende Dinge nicht anfasst.\n\nBeide ausführbar machen:\n\n\n chmod +x /usr/local/libexec/dovecot/sa-learn-spam.sh /usr/local/libexec/dovecot/sa-learn-ham.sh\n\nWer rspamd lokal laufen hat, ersetzt `127.0.0.3` durch `127.0.0.1` oder nutzt den Unix-Socket (`-h /var/run/rspamd/rspamd.sock`). Unter Linux liegen die Scripts in `/usr/lib/dovecot/` statt `/usr/local/libexec/dovecot/`. Der Pfad in `sieve_pipe_bin_dir` muss natürlich dazu passen.\n\n**Wichtig:** Damit `rspamc` ohne Passwort trainieren darf, muss die IP im rspamd Controller-Worker als vertrauenswürdig eingetragen sein. In `/usr/local/etc/rspamd/local.d/worker-controller.inc` (FreeBSD) bzw. `/etc/rspamd/local.d/worker-controller.inc` (Linux):\n\n\n secure_ip = \"127.0.0.0/8\";\n secure_ip = \"::1\";\n\nOhne das schlägt `rspamc learn_spam` mit einem Authentifizierungsfehler fehl. Bei Jail-Setups wie meinem muss die Jail-IP (`127.0.0.3`) in der Liste stehen.\n\n### Testen\n\nDovecot neu laden:\n\n\n service dovecot reload\n\nDann eine beliebige Mail in den Junk-Ordner verschieben und im rspamd-Log nachschauen:\n\n\n rspamd_controller_learn_fin_task: <127.0.0.3> learned message as spam: MESSAGE-ID\n\nMail wieder raus aus Junk in den Posteingang:\n\n\n rspamd_controller_learn_fin_task: <127.0.0.3> learned message as ham: MESSAGE-ID\n\nWenn das im Log steht, funktioniert alles. Kein Neustart nötig, kein Cache-Flush, kein Warten.\n\n### Wie viel Training braucht rspamd\n\nRspamd nutzt einen Bayes-Klassifikator. Der braucht eine Mindestmenge an gelernten Nachrichten, bevor er aktiv wird. Die Standardeinstellung ist 200 — also mindestens 200 Spam-Mails und 200 Ham-Mails. Vorher ignoriert rspamd die Bayes-Ergebnisse komplett.\n\nDas klingt nach viel, geht aber schneller als man denkt. Wer ein paar Dutzend Benutzer auf dem Server hat, kommt da in wenigen Wochen hin. Und danach wird rspamd mit jeder sortierten Mail ein bisschen besser.\n\nDen aktuellen Stand kann man jederzeit prüfen:\n\n\n rspamc stat\n\nUnter `Statfile` sieht man wie viele Nachrichten rspamd bereits gelernt hat.\n\nRspamd trainiert standardmäßig einen globalen Bayes-Klassifikator — alle Benutzer lernen in denselben Pool. Wer das pro Benutzer trennen will, setzt in der `classifier-bayes.conf`:\n\n\n per_user = true;\n\nFür die meisten Setups mit einer Handvoll Domains ist der globale Pool sinnvoller — mehr Trainingsdaten, schneller gute Ergebnisse.\n\n### Hinweise\n\nDie Konfiguration ist stabil — Dovecot-Updates, rspamd-Updates, FreeBSD-Upgrades, alles durchgelaufen ohne Anpassung.\n\nWer rspamd danach noch eine Stufe weiter bringen will: Ich habe einen eigenen Beitrag geschrieben, wie man GPT-basierte Spam-Erkennung in rspamd integriert. Das läuft zusätzlich zum Bayes-Klassifikator und fängt die Mails ab, die durch das statistische Netz rutschen.\n\nSiehe auch: Postfix und AMaViS: content_filter oder smtpd_proxy_filter?, DMARC-Prüfung in Postfix: OpenDMARC und rspamd im Vergleich\n\nFragen? Schreib mir über die Kontaktseite.",
"title": "Rspamd: Automatisches Spam/Ham-Lernen mit Dovecot und IMAPSieve"
}