85.1.21. pepsi-stage-list-deliver

finalise one member’s copy of a mailing-list post

Handbuchabschnitt:

1

85.1.21.1.1. Name

pepsi-stage-list-deliver - die Stage der Pepsi-Mailinglisten-Pipeline für die Zustellung je Mitglied.

85.1.21.1.2. Übersicht

pepsi-stage-list-deliver [GLOBAL-OPTIONS] worker

85.1.21.1.3. Beschreibung

pepsi-stage-list-deliver ist ein Stage-Programm, das von pepsi-dispatch(1) ausgeführt wird. pepsi-stage-list-post(1) hat bereits eine Zeile je Empfänger angelegt; diese Stage macht aus jeder davon die Kopie dieses Mitglieds statt einer weiteren Kopie derselben Nachricht. Eine Zeile hinein, eine Zeile heraus.

Drei Dinge geschehen:

  • ``List-Unsubscribe`` wird fertiggestellt mit der One-Click-https:-URI dieses Mitglieds neben der mailto:-Form, und List-Unsubscribe-Post: List-Unsubscribe=One-Click wird hinzugefügt (RFC 8058).

  • Die Nachricht wird dekoriert — mit Kopf- und Fußzeile der Liste in der Sprache des Mitglieds —, wenn personalize der Liste individual oder full ist.

  • ``To:`` wird umgeschrieben, sodass es das Mitglied nennt, nur bei full. Upstreams personalize_to ist bei individual eine Nulloperation, und dies hier ebenso.

Eine Kopie, die avoid-duplicates markiert hat — das Mitglied war bereits im eigenen To oder Cc der Nachricht genannt und hat seine Listenkopie trotzdem behalten —, wird mit X-Pepsi-List-Copy: yes gekennzeichnet, damit der Leser sieht, warum er zwei hat.

Warnung

Diese Stage muss vor dem Signieren laufen. Jeder Header, den sie berührt, gehört in die DKIM-h=-Liste, und List-Unsubscribe ist genau der Header, den ein Mailbox-Anbieter prüft, wenn er entscheidet, ob er eine Abmelde-Schaltfläche anzeigt. Eine Pipeline, die zuerst signiert, würde Mail erzeugen, die signiert und danach verändert wird, was DKIM überall scheitern lässt. Daher zeigt NEXT_STAGE auf pepsi-stage-dkim-sign(1), nicht auf ein Relay, und pepsi-setup weist die umgekehrte Reihenfolge zurück. Upstream sagt dasselbe in dem Kommentar, der arc-sign aus seiner eigenen Pipeline entfernt.

85.1.21.1.4. One-Click-Abmeldung

Das Token in der https:-URI ist ein Schlüssel-Hash über die Liste, die Adresse des Mitglieds und eine Seriennummer, die das Mitglied erneuern kann. Es wird nicht gespeichert: Eine List-Unsubscribe-URI wird einmal je Mitglied je Beitrag ausgegeben, sodass eine Tabelle davon mit den Zustellungen statt mit den Mitgliedern wachsen würde. Daraus folgen drei Dinge:

  • Das Token wandert nie zwischen Stages — diese Stage hat das Geheimnis und berechnet es je Kopie;

  • jede je für ein Abonnement ausgegebene URI zu widerrufen, bedeutet, die unsubscribe_serial dieses Mitglieds hochzuzählen — eine Zähleraktualisierung statt eines Tabellendurchlaufs;

  • und es gibt nichts ablaufen zu lassen, weil ein nicht mehr existierendes Abonnement an der Mitgliedschaftsprüfung scheitert, was auch immer das Token sagt.

Das Geheimnis ist [pepsi-list] UNSUBSCRIBE_SECRET. Ohne Geheimnis oder ohne BASE_URL, aus der sich eine URI bauen ließe, steht die mailto:-Form allein, wie bei Upstream: Eine nicht überprüfbare URI ist schlechter als keine. Das Rotieren des Geheimnisses macht jede URI ungültig, die bereits im Postfach jedes Abonnenten liegt.

85.1.21.1.5. Dekoration

Kopf- und Fußzeile werden aus dem [pepsi] TEMPLATE_DIR als list-header.<lang>.body und list-footer.<lang>.body gerendert, wobei zuerst die Sprache des Mitglieds gewählt wird und en der Rückfall ist. Eine Liste ohne Vorlagendateien wird nicht dekoriert; das ist der Normalfall und kostet nichts. Eine Vorlage, die existiert, sich aber nicht lesen oder rendern lässt, ist ein Fehler, und die Kopie wird wiederholt, statt ohne die vom Eigentümer konfigurierte Fußzeile gesendet zu werden.

Die Fußzeile wird an den ersten ``text/plain``-Teil angehängt und an nichts sonst. Anhängen an einen multipart/signed-Teil zerstört die Signatur und Anhängen an ein PDF beschädigt es, sodass eine Nachricht ohne Klartextteil undekoriert zugestellt wird, statt verstümmelt zu werden.

85.1.21.1.6. Zwei Invarianten

Geschwisterzeilen beginnen hier, niemals am Kopf der Pipeline. Ein Wiedereinstieg bei init würde die ARC-Verifikation erneut ausführen und erneut in den Router eintreten, was bei einer Dachliste kombinatorisch explodiert.

Die persönlichen Einstellungen eines Mitglieds konfigurieren die Listenzustellung nicht um. Pepsi legt adressbezogene pepsi.settings-Überschreibungen automatisch darüber, und der einzige Empfänger einer Geschwisterzeile ist ein Mitglied, dessen Urlaubs- oder Sprachüberschreibung die Ziele dieser Stage nichts angehen — ein daraus übernommenes NEXT_STAGE könnte die Kopie am Signieren vorbeileiten. Daher werden NEXT_STAGE, die [pepsi-list]-Optionen und das [pepsi] TEMPLATE_DIR aus der standortweiten Konfiguration gelesen, die keine domain:- oder address:-Konfigurationsüberschreibung und keine pepsi.settings-Zeile erreicht, und die Sprache des Mitglieds stammt aus dem Deskriptor, den das Fan-out geschrieben hat. Nichts wird aus der Überlagerung übernommen.

85.1.21.1.7. Konfiguration

NEXT_STAGE (erforderlich)

Das Signier-Ende der Pipeline. pepsi-setup weist hier ein Relay zurück.

Alles andere, was diese Stage braucht, sind der Mitglieds-Deskriptor, den das Fan-out geschrieben hat, und die eigenen Attribute der Liste; [pepsi-list] BASE_URL und UNSUBSCRIBE_SECRET werden aus dem standortweiten Abschnitt gelesen.

85.1.21.1.8. State

Eingaben: state.list — die Listen-ID, die Sprache des Mitglieds, seine Abmelde-Seriennummer und das Duplikat-Flag — sowie das einzige rcpt_to der Zeile, das für die Adresse maßgeblich ist.

Ausgaben: ein umgeschriebener Header-Block und Nachrichtentext. state wird nicht verändert.

Übergänge: schaltet zu NEXT_STAGE weiter, der einzige Übergang.

85.1.21.1.9. Befehle

worker

Läuft als persistenter pepsi-dispatch(1)-Worker, der Nachrichten-IDs von der Standardeingabe liest.

85.1.21.1.10. Globale Optionen

Die übliche Gruppe — -c/–config, -L/–log, -v/–verbose, -h/–help und -V/–version —, die sich wie bei jedem Pepsi-Programm verhält; siehe pepsi-config(1).

85.1.21.1.11. Fehler und Wiederholungen

  • Eine Kopie, deren Liste nach dem Fan-out gelöscht wurde, wird mit einer Warnung im Log verworfen: Der Eigentümer hat die Liste gelöscht, eine jetzt zugestellte Kopie trüge einen Abmeldelink ins Leere, und es gibt niemanden mehr, dem etwas zu melden wäre.

  • Eine Kopie, die sich für die Dekoration nicht parsen lässt, wird mit einer Warnung undekoriert zugestellt. Das Fan-out hat diese Bytes aus einer Nachricht gebaut, die es geparst hatte; es liegt also nicht am Absender, und eine Wiederholung kann daran nichts ändern; die Kopie trägt weiterhin die eigenen List-*-Header der Liste (einschließlich der mailto:-Abmeldung), und sie zu verwerfen hieße, die Mail des Mitglieds zu verlieren.

  • Ein Datensatz ohne Mitglieds-Deskriptor schlägt sofort fehl.

  • Jeder andere Fehler (die Datenbank, eine Vorlage) wird mit Backoff bis MAX_LIFETIME wiederholt (siehe pepsi-dispatch(1)). Eine Kopie, die schließlich aufgegeben wird, wird von pepsi-failure-bouncer(1) gelöscht, nicht gebounct, und zählt daher nie gegen das Mitglied.

85.1.21.1.12. Exit-Status

0

Die Kopie wurde fertiggestellt und weitergeschaltet.

1

Der Worker konnte nicht laufen (seine Datenbank ließ sich nicht öffnen, oder Standardein-/-ausgabe schlug fehl). Der Grund wird in das Log geschrieben.

85.1.21.1.13. Beispiele

[stage-list-deliver]
PROGRAM = pepsi-stage-list-deliver
NEXT_STAGE = dkim-sign

85.1.21.1.14. Siehe auch

pepsi-list(1), pepsi-stage-list-post(1), pepsi-stage-list(1), pepsi-stage-dkim-sign(1), pepsi-stage-arc(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)

85.1.21.1.15. Fehler

Melden Sie Fehler an den Pepsi-Issue-Tracker.