85.1.36. pepsi-stage-milter¶
run a message past a sendmail/Postfix milter mail filter
- Handbuchabschnitt:
1
85.1.36.1.1. Name¶
pepsi-stage-milter - die Milter-Client-Stage der Pepsi-Pipeline.
85.1.36.1.2. Übersicht¶
pepsi-stage-milter [GLOBAL-OPTIONS] worker
85.1.36.1.3. Beschreibung¶
pepsi-stage-milter ist ein Stage-Programm, das von pepsi-dispatch(1) als persistenter Worker ausgeführt wird, der Nachrichten-IDs von der Standardeingabe liest. Für jede Nachricht öffnet es eine Verbindung zu einem Milter — dem Mailfilter-Protokoll, das sendmail eingeführt und Postfix übernommen hat —, spielt die Nachricht als synthetische SMTP-Sitzung nach, wendet alle vom Filter verlangten Änderungen an und routet die Nachricht gemäß dem Urteil des Filters.
Die Stage ist ein Milter-Client und nichts weiter. Der Filter selbst ist ein bestehender langlebiger Daemon, der auf SOCKET lauscht, genau wie unter sendmail und Postfix: eigenes Paket, eigene systemd-Unit, eigenes Benutzerkonto. Pepsi startet ihn nicht, stoppt ihn nicht und sperrt ihn nicht in eine Sandbox — einen Daemon einzugrenzen ist Sache der Unit dieses Daemons, und unter Debian (opendkim, clamav-milter, rspamd, spamass-milter, milter-greylist) ist es dort bereits erledigt. Folglich trägt diese Stage kein eigenes Privileg: kein setuid-Bit, kein setgid-Bit, keinen Helper.
85.1.36.1.4. Filterung nach der Warteschlange¶
Ein Milter ist als Filter vor der Warteschlange konzipiert, und Pepsi führt ihn nach der Warteschlange aus. Das ist die eine Stelle, an der Pepsis Milter-Unterstützung der von sendmail oder Postfix nicht gleichwertig ist.
Unter sendmail und Postfix laufen die Milter-Callbacks innerhalb der SMTP-Sitzung, bevor der Server die Verantwortung für die Nachricht übernommen hat. Das erlaubt es einem Milter, einem gefälschten Absender mit 550 zu antworten und überhaupt keinen Bounce zu erzeugen.
Pepsis Pipeline läuft vollständig nach dem Einreihen der Nachricht: Wenn irgendeine Stage einen Datensatz sieht, hat pepsi-ingress(1) bereits 250 geantwortet. Ein Milter-REJECT kostet hier daher einen Bounce an die Adresse, die der Umschlag nannte — und das ist bei gefälschtem Spam ein unschuldiger Dritter. Ein von einer Postfix-Installation übernommener Greylisting- oder DNSBL-Milter filtert weiterhin korrekt, aber zum Preis von Backscatter, den eine Ablehnung vor der Warteschlange vermeidet.
Installationen, die sich das nicht leisten können, sollten REJECT_STAGE auf eine pepsi-stage-discard(1) statt auf eine pepsi-stage-bounce(1) richten, damit eine abgelehnte Nachricht stillschweigend verworfen wird. Filter, die nur annotieren — ein DKIM-Signierer, ein Spam-Bewerter, der einen Header für eine spätere pepsi-stage-if(1) zum Verzweigen hinzufügt —, sind nicht betroffen.
85.1.36.1.5. Platzierung¶
Auf dem eingehenden Pfad platzieren Sie die Stage nach pepsi-stage-decrypt(1), damit der Filter Klartext sieht statt eines PGP- oder S/MIME-Blobs.
Auf dem Submission-Pfad platzieren Sie sie vor pepsi-stage-dkim-sign(1), damit unsere eigene Signatur alles abdeckt, was der Filter geändert hat.
Ein Milter, der den Nachrichtentext umschreibt, bricht zwangsläufig den DKIM-Body-Hash des Urhebers und das eigene ARC-AMS dieser Installation, weil beide über Bytes berechnet werden, die es nicht mehr gibt. Das ist unvermeidlich — es ist derselbe Vorbehalt, den pepsi-stage-vacation(1) für seine Subject:-Markierung trägt — und es ist harmlos auf einem Zweig mit lokaler Zustellung, wo nichts weiter unten erneut verifiziert. Auf einem Zweig, der die Nachricht weiterleitet, ziehen Sie einen Filter vor, der nur Header hinzufügt.
85.1.36.1.6. Der Protokolldialog¶
Jede Nachricht ist eine Verbindung, die anschließend mit SMFIC_QUIT geschlossen wird. Die Sitzung wird aus dem rekonstruiert, was pepsi-ingress(1) unter state.origin festgehalten hat (siehe pepsi.state(7)): die verbindende Adresse und ihr PTR-Name, der HELO/EHLO-Name, die TLS-Version und die Chiffre, der Listener, auf dem die Nachricht ankam, und die BODY=/SMTPUTF8-Parameter, die der Client bei MAIL FROM angegeben hat.
Eine lokal injizierte Nachricht — ein Bounce, eine automatische Antwort, eine Submission über pepsi-sendmail(1) — hat kein entferntes Gegenüber. Statt die Connect-Phase zu überspringen, was {client_addr} undefiniert ließe und die Sonderbehandlung lokaler Mail in einem Filter unvorhersehbar auslösen würde, wird eine Loopback-Sitzung synthetisiert (127.0.0.1, localhost), wie sendmail sie für lokale Submission präsentiert.
85.1.36.1.6.1. Optionsaushandlung¶
Die Stage bietet die Protokollversion PROTOCOL_VERSION an (standardmäßig 6, wie in Postfix), die von ALLOW_ACTIONS erlaubten Änderungsaktionen und jede SMFIP_*-Protokolloption, die sie erfüllen kann. Der Filter handelt die Version von dort aus herunter, aber nicht unter 2: Ein Milter, das weniger anbietet, wird abgelehnt, und die Nachricht nimmt den ON_FAILURE-Pfad. Zwei weitere Regeln bestimmen die Antwort des Milters.
Eine Aktion, die der Milter verlangt, diese Stage aber nicht angeboten hat, ist ein Konfigurationsfehler. Sie wird gemeldet — unter Nennung des fehlenden Flags —, und die Nachricht nimmt den ON_FAILURE-Pfad. Postfix ignoriert eine solche Anfrage stillschweigend; stillschweigendes Ignorieren ist der Weg, auf dem ein Operator sechs Monate später entdeckt, dass ein signierender Milter nie etwas signiert hat.
Eine Protokolloption, die diese Stage nicht implementiert, wird abgelehnt. Eine zu beanspruchen und dann nicht zu erfüllen wäre ein Protokollverstoß auf unserer Seite; die Optionen SMFIP_MDS_256K/SMFIP_MDS_1M für größere Blöcke sind der einschlägige Fall und werden nie angeboten.
Das Bit SMFIF_SETSYMLIST wird nicht von ALLOW_ACTIONS geregelt und braucht keine Berechtigung. Es autorisiert keine Änderung an der Nachricht — es erlaubt dem Filter nur, einen engeren Satz von Makros anzufordern, als sonst gesendet würde —, sodass es neben „darf den Umschlag umschreiben“ zu regeln gewöhnliche Filter ohne Sicherheitsgewinn brechen würde. Wenn ein Milter für eine Phase seine eigene Makroliste nennt, wird diese Liste statt der entsprechenden MACROS_*-Option verwendet.
85.1.36.1.6.2. Makros¶
Die Standard-Makrosätze sind die von Postfix — milter_connect_macros, milter_helo_macros, milter_mail_macros, milter_rcpt_macros, milter_data_macros, milter_end_of_header_macros und milter_end_of_data_macros der stabilen Postfix-3.x-Versionen, Eintrag für Eintrag (connect: j {daemon_name} {daemon_addr} v _) —, sodass die eigene Dokumentation eines Filters unverändert gilt. {daemon_addr} (und sein Synonym {if_addr}) ist die lokale IP-Adresse, zu der sich der Client verbunden hat, wie pepsi-ingress(1) sie festgehalten hat; eine Sitzung, die über einen UNIX-Socket ankam, hat keine. {if_name} wird ebenfalls beantwortet, mit dem Hostnamen des Servers, wenn eine Liste es nennt. Ein Makro, dessen Wert diese Installation nicht kennt, wird gar nicht gesendet, und so unterscheidet libmilter „kein TLS“ von „TLS mit leerer Chiffre“; {cipher_bits}, {cert_subject} und {cert_issuer} stehen in der Standardliste, sind hier aber nie bekannt, weil pepsi-ingress(1) sie nicht festhält, sodass ein Filter sie genau so sieht, wie er sie aus einer Postfix-Sitzung sähe, die keine hatte.
Die RFC-4954-Authentifizierungsmakros stammen aus dem, was pepsi-ingress(1) über die Sitzung festgehalten hat (state.origin.auth_*, siehe pepsi.state(7)):
{auth_type}Der SASL-Mechanismus, der erfolgreich war —
PLAINoderLOGIN. Er wird genau so durchgereicht, wie er festgehalten wurde; die Großschreibung stammt von pepsi-ingress(1), das den Mechanismusnamen beim Parsen vonAUTH(RFC 4954 §4) kanonisiert, nicht von dieser Stage. Für die authentifizierten Pfade, die nicht SASL sind, absichtlich nicht gesetzt: ein Gegenüber am UNIX-Socket, ein gepinntes TLS-Client-Zertifikat, eineMYNETWORKS-Adresse. Das Makro ist als der SASL-Mechanismus definiert, und ein Filter, der es gegen eine Liste echter Mechanismen vergleicht, würde von einem Token in die Irre geführt, das keiner ist.{auth_authen}Die Authentifizierungsidentität: die SASL-authcid oder der Login, auf den die uid eines UNIX-Gegenübers aufgelöst wurde. Eine
peercred-Sitzung hat daher eine Identität ohne{auth_type}— die ehrliche Beschreibung einer Sitzung, die der Kernel authentifiziert hat und nicht SASL.mynetworksundclient-certnennen niemanden, sodass dort beide Makros ungesetzt bleiben.{auth_author}Die Autorisierungsidentität — als wen zu handeln der Client verlangt hat, ersatzweise, als wen er sich authentifiziert hat, was sendmails Regel ist. Sie unterscheidet sich von
{auth_authen}nur, wenn ein SASL-PLAIN-Austausch eine abweichende authzid geliefert hat.{auth_ssf}Die Stärke der SASL-Sicherheitsschicht, die für beide von Pepsi implementierten Mechanismen genau
0ist: keiner handelt eine eigene Schicht aus, und die Vertraulichkeit kommt vom darunterliegenden TLS — das{cipher}beschreibt. Ein Mechanismus, der doch eine Schicht mitbringt, ließe dies ungesetzt, statt es als0zu untertreiben.
85.1.36.1.7. Urteile¶
Milter-Urteil |
wohin die Nachricht geht |
|---|---|
|
NEXT_STAGE |
|
ACCEPT_STAGE, standardmäßig NEXT_STAGE |
|
REJECT_STAGE, standardmäßig das |
|
pausiert zur Wiederholung; das |
|
der Datensatz wird stillschweigend gelöscht |
|
QUARANTINE_STAGE; gelöscht, wenn das nicht gesetzt ist |
Ein SMFIR_REPLYCODE wird als Tempfail behandelt, wenn sein Code mit 4 beginnt, sonst als Ablehnung — dieselbe Regel, die SMTP selbst verwendet. Sein Code, der erweiterte Status nach RFC 3463 und der Text werden getrennt unter state.bounce festgehalten, sodass ein Bericht von pepsi-stage-bounce(1) die eigenen Worte des Filters zitieren und das DSN-Feld Status: aus dessen erweitertem Status setzen kann.
Ist weder REJECT_STAGE noch das BOUNCE_STAGE des Abschnitts gesetzt, hat eine abgelehnte Nachricht keinen Ort, an den sie gehen kann: Der Datensatz bleibt failed, statt still weitergeschaltet zu werden, sodass pepsi-failure-bouncer(1) oder der Betreiber entscheidet.
Ein Tempfail, der MAX_LIFETIME erschöpft hat — der Filter hat die Nachricht immer wieder zurückgestellt oder war mit ON_FAILURE = tempfail so lange nicht erreichbar —, wird nicht an REJECT_STAGE geschickt. Er ist kein Urteil über die Nachricht, und REJECT_STAGE ist oft eine Stage, die abgelehnte Mail verwirft, um Backscatter zu vermeiden (discard-rejected des Einrichtungsassistenten), was Mail verlieren würde, nur weil ein Filter ausgefallen war. Er geht mit einem Bounce-state an das BOUNCE_STAGE des Abschnitts, so wie ein MTA eine Nachricht bounct, die er nicht rechtzeitig weitergeben konnte, und ohne BOUNCE_STAGE bleibt die Nachricht failed, wo pepsi-status sie anzeigt und pepsi-failure-bouncer(1) sie bounct.
ACCEPT_STAGE existiert, weil Postfix eine Liste von Miltern anwendet, wo ACCEPT „die übrigen für diese Nachricht überspringen“ bedeutet. Ein Milter je Stage, durch NEXT_STAGE verkettet, kennt so etwas nicht, sodass ohne diese Option ACCEPT und CONTINUE ununterscheidbar wären. Richten Sie es hinter den Rest einer Filterkette, um die Unterscheidung wiederherzustellen; lassen Sie es ungesetzt, und die beiden Urteile sind dasselbe.
Quarantäne ist kein eigenes Urteil. Ein sendmail-Milter stellt unter Quarantäne und gibt danach dennoch ein Akzeptieren zurück, sodass eine Quarantäneanfrage die Route unabhängig vom darauf folgenden Urteil entscheidet. Pepsi hat keinen Quarantänespeicher — nur eine Route —, sodass die Nachricht ohne konfiguriertes QUARANTINE_STAGE verworfen wird.
85.1.36.1.7.1. Ablehnung je Empfänger¶
Wenn der Filter SMFIC_RCPT mit einer Ablehnung (5xx) beantwortet, wird dieser Empfänger auf einen eigenen Geschwisterdatensatz bei REJECT_STAGE abgezogen, auf sich selbst zerteilt, und der Rest der Nachricht läuft weiter — dieselbe Auffächerung, die pepsi-stage-relay-to-lmtp(1) verwendet. state.dsn.rcpt wird auf jedem entstehenden Datensatz im Gleichschritt mit rcpt_to zerteilt. Wird jeder Empfänger abgelehnt, wird der Quelldatensatz in derselben Anweisung gelöscht, die die Geschwister erzeugt, und nur die Geschwister bleiben. Das Token jedes Geschwisters benennt seinen Empfänger statt seiner Position, sodass ein wiederholter Durchlauf (nachdem der Quelldatensatz reduziert wurde) nicht mit einem kollidieren kann, das ein früherer Durchlauf erzeugt hat. Ist weder REJECT_STAGE noch BOUNCE_STAGE gesetzt, gibt es keinen Ort, an den sie abgezogen werden könnten, die Empfänger werden daher behalten und der Umstand als Warnung protokolliert: Sie zu verwerfen hieße Mail zu verlieren, und den Filter stillschweigend zu ignorieren ist genau die Fehlerart, die diese Stage verweigert.
Ein Tempfail (SMFIR_TEMPFAIL oder ein 4xx-Antwortcode) für einen Empfänger ist keine Ablehnung. Die Kopie dieses Empfängers wird auf einen Geschwisterdatensatz abgezogen, der paused bei dieser Stage wartet, mit state.attempts und state.last_error, und nach dem Wiederholungs-Backoff erneut gefiltert wird, ausgehend von den Bytes, mit denen er ankam; die übrigen Empfänger laufen weiter. Die Kopie behält die Ankunftszeit der Nachricht, sodass ihre MAX_LIFETIME ab dann zählt; ist diese abgelaufen, geht sie zu BOUNCE_STAGE oder bleibt failed, wenn es keine gibt — wie bei einem Tempfail der ganzen Nachricht, nie zu REJECT_STAGE. Ein Filter, der jeden Empfänger zurückstellt, hat die Nachricht zurückgestellt, die dann als Ganzes pausiert wird.
Das geschieht bei jedem Filter, gleich was er ausgehandelt hat. Insbesondere hängt es nicht von SMFIP_RCPT_REJ ab, das etwas ganz anderes verlangt: Mit diesem Flag bittet ein Filter darum, über die Empfänger unterrichtet zu werden, die der MTA selbst bereits abgelehnt hat. Pepsi läuft nach der Warteschlange und lehnt beim Nachspielen keinen eigenen Empfänger ab, sodass es nie einen solchen Empfänger zu melden gibt.
85.1.36.1.8. Änderungen¶
Die Änderungen am Nachrichtenende, die ein Filter anfordern darf, werden von ALLOW_ACTIONS geregelt. SMFIR_ADDHEADER hängt ans Ende des Blocks an; SMFIR_INSHEADER fügt an der 0-basierten absoluten Position ein, die es nennt, und SMFIR_CHGHEADER ersetzt das 1-basierte n-te Feld dieses Namens (ein leerer Wert löscht es, und ein Index hinter dem letzten Vorkommen hängt ein neues Feld an, wie es sendmail und Postfix beide tun). Die beiden Indizes zählen Verschiedenes, was der eine Teil dieses Protokolls ist, den man leicht falsch liest. SMFIR_REPLBODY ersetzt den Nachrichtentext vollständig. SMFIR_ADDRCPT/SMFIR_ADDRCPT_PAR/SMFIR_DELRCPT schreiben die Umschlagempfänger um, wobei state.dsn.rcpt passend neu aufgebaut wird (ein vom Filter hinzugefügter Empfänger erbt das NOTIFY des ersten ursprünglichen Empfängers und erhält ein ORCPT nach RFC 3461 §5.2.7, das ihn selbst benennt); SMFIR_CHGFROM schreibt den Umschlagabsender um.
Ein vom Filter gelieferter Header-Wert wird vor dem Speichern normalisiert: Zeilenenden werden zu CRLF, und jede Fortsetzungszeile muss zwingend mit Leerraum beginnen. Ohne das würde ein Wert, der einen Zeilenumbruch gefolgt von Bcc: somebody enthält, als zweites Header-Feld wiedergegeben — Header-Injektion durch eine Komponente, die die Nachricht nur annotieren soll. Ein ungültiger Feld**name** wird rundweg abgelehnt statt maskiert.
Ein ersetzender Nachrichtentext wird genauso normalisiert: Die SMFIR_REPLBODY-Blöcke werden zusammengefügt und jedes nackte LF wird zu einem CRLF, weil RFC 5321 §2.3.8 Nachrichtenzeilen mit CRLF beendet und §4.1.1.4 das Übertragen eines nackten CR oder LF verbietet. Ein Filter, der den Nachrichtentext als Text liest und mit \n-Zeilenenden zurückschreibt, erzeugt daher keine Nachricht, die der nächste Hop erraten muss.
Die denormalisierten Spalten from_header und subject werden aus dem umgeschriebenen Block aufgefrischt, sodass ein Filter, der einen Betreff markiert, pepsi-queue(1) und pepsi-stage-check-whitelist(1) nicht den alten lesen lässt.
Eine zurückgestellte Nachricht behält die Bytes, mit denen sie ankam: Änderungen aus einem Durchlauf, der in SMFIR_TEMPFAIL endete, werden verworfen, weil die Nachricht beim nächsten Versuch von Grund auf neu gefiltert wird und ein Anwenden jetzt sie je Wiederholung einmal markieren würde.
85.1.36.1.9. Konfiguration¶
Die Optionen liegen im eigenen [stage-<name>]-Abschnitt der Stage (PROGRAM = pepsi-stage-milter) und sind in pepsi.conf(5) dokumentiert: SOCKET, MILTER_NAME, ACCEPT_STAGE, REJECT_STAGE, QUARANTINE_STAGE, ON_FAILURE, ALLOW_ACTIONS, PROTOCOL_VERSION, die Timeouts CONNECT_TIMEOUT/COMMAND_TIMEOUT/CONTENT_TIMEOUT, die gemeinsamen Wiederholungsoptionen und die sieben MACROS_*-Listen.
NEXT_STAGE ist zwingend: SMFIR_CONTINUE ist das voreingestellte Urteil und reicht die Nachricht dorthin weiter, und ACCEPT_STAGE deckt nur SMFIR_ACCEPT ab, sodass weder es noch die Ablehnungs-/Quarantäneziele dafür einspringen können. pepsi-setup(1) weist einen Abschnitt ohne es zurück und prüft, dass ACCEPT_STAGE, REJECT_STAGE und QUARANTINE_STAGE allesamt vorhandene Stages benennen.
85.1.36.1.10. State¶
Eingaben: state.origin (die festgehaltene SMTP-Sitzung, aus der die Connect-/Helo-/Mail-Phasen und ihre Makros gebaut werden) und state.dsn (parallel zu jeder Empfängerumschreibung gehalten).
Ausgaben: state.milter — der Name des Filters (MILTER_NAME), das Urteil, die geltende Protokollversion, die verstrichene Zeit, die Liste der angewandten Änderungen und, wo vorhanden, der Antwortcode, der Quarantänegrund und die Anzahl der abgelehnten Empfänger. Auf dem ON_FAILURE-Pfad ist der Eintrag stattdessen die Kurzform: die eigene Bezeichnung der Stage, das Urteil failed und der Fehler. Bei ON_FAILURE = reject bleibt dieser Fehler im Eintrag und im Journal: Der Bounce, den der Absender erhält, besagt nur, dass der Filter nicht befragt werden konnte. Nichts liest den Eintrag; er existiert, damit pepsi-queue(1)
zeigen kann, warum eine Nachricht markiert wurde, und pepsi-stage-if(1) darauf verzweigen kann. Eine abgelehnte Nachricht trägt zusätzlich state.bounce. Das State-Layout wird in pepsi.state(7) beschrieben.
Übergänge: Weiterschalten zu NEXT_STAGE, ACCEPT_STAGE oder QUARANTINE_STAGE; Umleiten zu REJECT_STAGE oder, wenn ein Tempfail abgelaufen ist, zu BOUNCE_STAGE; Pausieren zur Wiederholung; Abschließen (Löschen). Eine Ablehnung oder ein Tempfail je Empfänger erzeugt zusätzlich Geschwisterdatensätze (der Datensatz eines Empfängers mit Tempfail wird paused bei dieser Stage angelegt).
85.1.36.1.11. Befehle¶
- worker
Läuft als persistenter pepsi-dispatch(1)-Worker, der Nachrichten-IDs von der Standardeingabe liest.
85.1.36.1.12. Globale Optionen¶
- -c FILE, –config FILE
Liest die Konfiguration aus FILE, statt die Standardorte zu durchsuchen.
- -L LOGLEVEL, –log LOGLEVEL
Setzt die Log-Ausführlichkeit (Standardwert
info).- -v, –verbose
Zeigt Log-Meldungen aus allen Quellen.
- -h, –help; -V, –version
Gibt eine Verwendungsübersicht / die Version aus und beendet sich.
85.1.36.1.13. Exit-Status¶
- 0
Die Nachricht wurde verarbeitet und geroutet.
- 1
Ein Fehler ist aufgetreten (Nachricht nicht gefunden oder nicht
running, eine fehlkonfigurierte Stage — z. B. ein nicht parsbares SOCKET — oder ein Datenbankfehler). Nichts, was der Filter tut, ist ein Fehler: weder ein Milter, das nicht erreicht werden konnte, noch eines, das eine unbrauchbare Änderung gesendet hat (ein ungültiger Header-Feldname, ein NUL in einem Wert), noch eines, das durchgegangen ist — mehr als 1024 Änderungen, mehr als 64 MiB Ersatz-Nachrichtentext oder einSMFIR_PROGRESS, das ein Antwort-Timeout um mehr als das Zehnfache verlängert. All diese nehmen den ON_FAILURE-Pfad; der Grund wird in das Journal geschrieben.
85.1.36.1.14. Beispiele¶
Ausgehende Mail mit opendkim vor Pepsis eigener DKIM-Stage signieren:
[stage-opendkim]
PROGRAM = pepsi-stage-milter
SOCKET = unix:/run/opendkim/opendkim.sock
NEXT_STAGE = dkim-sign
Eingehende Mail mit rspamd über TCP bewerten, für das Abgelehnte einen Bounce erzeugen und ihm erlauben, den Nachrichtentext umzuschreiben, wenn es eine Spam-Nachricht einpackt:
[stage-spam-filter]
PROGRAM = pepsi-stage-milter
SOCKET = inet:127.0.0.1:11332
ALLOW_ACTIONS = addhdrs chghdrs chgbody quarantine
QUARANTINE_STAGE = quarantine
REJECT_STAGE = bounce
NEXT_STAGE = deliver
BOUNCE_STAGE = bounce
Derselbe Filter in einer Installation, die keinen Backscatter aussenden will: Abgelehnte Mail wird verworfen, statt einen Bounce zu erzeugen:
[stage-spam-filter]
PROGRAM = pepsi-stage-milter
SOCKET = inet:127.0.0.1:11332
REJECT_STAGE = drop
NEXT_STAGE = deliver
[stage-drop]
PROGRAM = pepsi-stage-discard
DISPOSITION = failure
BOUNCE = no
Zwei Filter in einer Kette, bei der ein Akzeptieren durch den ersten den zweiten überspringt:
[stage-greylist]
PROGRAM = pepsi-stage-milter
SOCKET = unix:/run/milter-greylist/milter-greylist.sock
NEXT_STAGE = spam-filter
ACCEPT_STAGE = deliver
REJECT_STAGE = bounce
[stage-spam-filter]
PROGRAM = pepsi-stage-milter
SOCKET = inet:127.0.0.1:11332
NEXT_STAGE = deliver
REJECT_STAGE = bounce
85.1.36.1.15. Siehe auch¶
pepsi-dispatch(1), pepsi-stage-if(1), pepsi-stage-bounce(1), pepsi-stage-discard(1), pepsi-stage-dkim-sign(1), pepsi-stage-decrypt(1), pepsi-queue(1), pepsi-setup(1), pepsi.conf(5), pepsi.state(7)
85.1.36.1.16. Fehler¶
Melden Sie Fehler an den Pepsi-Issue-Tracker.