mail: adressbezogene Abmeldung fuer Empfaenger ohne Konto (Roadmap 1d.3)

Der Abmeldelink in API-Benachrichtigungen zeigte auf das Konto des
Einlieferers - ein Klick des Pressekontakts haette connektar abgemeldet.
Jetzt traegt der Link die Empfaengeradresse (signiert), der Zustand liegt
als Unsubscribed in der Sperrliste. Anmeldelinks, die die Person selbst
anfordert, gehen weiter durch; harte Bounces sperren alles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-16 14:35:47 +00:00
parent 0692d892e0
commit 35db30e019
15 changed files with 362 additions and 20 deletions

View file

@ -146,7 +146,7 @@ Für selbst angelegte Firmendaten trägt der Nutzer die Verantwortung. Für die
|---|---|---|---|
| ~~1d.1~~ | Hilfeseite ohne kommerziellen Anteil — **gebaut 16.09.2026**: `/{edition}/gute-pressemitteilung` (DE/EN), Anlass, Aufbau, Sprache, Prüfablauf, sieben Qualitätsdimensionen offen, Pressebilder; Sitemap + Hilfe-Center | S | keine |
| ~~1d.2~~ | Textbaustein in die Ablehnungsmail — **16.09.2026**: Link auf dem Portal der Meldung, Herkunft `mail_reject`, nichts Kommerzielles (E6) | S | 1d.1 |
| 1d.3 | Abmeldemöglichkeit für Benachrichtigungen, Status in der Suppression-Logik geführt | S | Bounce-Suppression live |
| ~~1d.3~~ | Abmeldemöglichkeit für Benachrichtigungen — **16.09.2026**: für Empfänger ohne Konto (Pressekontakt, Firmen-E-Mail) adressbezogener Abmeldelink, Zustand als `Unsubscribed` in der Sperrliste; selbst angeforderte Anmeldelinks gehen weiter durch. Vorher zeigte der Link in API-Benachrichtigungen auf das Konto des Einlieferers | S | Bounce-Suppression live |
| ~~1d.4~~ | Prüfwerkzeug — **E3 entschieden 16.09.2026: kein eigenständiges Werkzeug.** Prüfung nur beim Freigeben, Ergebnis am Entwurf; „Zur Prüfung freigeben" mit Erklärung, was danach passiert; automatische Prüfung je Meldung `max_automatic_attempts` (3), danach geblockt in die Admin-Queue („Prüfung nötig"), Freischalten oder Kommentar, Automatik für die Meldung ab dann aus | M | 1d.1 |
| ~~1d.5~~ | Bewertung einer bestehenden Meldung über Magic Link — **mit 1c.2 erledigt**: der Beansprucher sieht Ablehnungsgrund, KI-Stufe und Content-Score auf der Meldungsseite | S | 1d.4, 1b.2 |
| ~~1d.6~~ | Partnerbereich am Seitenende als BALD — **16.09.2026** am Ende von 1d.1 | S | 1d.1 |

View file

@ -1406,3 +1406,31 @@ Beansprucher sieht Ablehnungsgrund, KI-Stufe, Content-Score).
Deploy: `migrate --force` (Millisekunden), `view:cache`, `queue:restart`.
Kein Backfill — bestehende Meldungen starten mit 0 Versuchen.
## 1d.3 — Abmeldung für Empfänger ohne Konto
**Befund:** Die Benachrichtigungen zu API-Meldungen gehen an Pressekontakt
oder Firmen-E-Mail — der Abmeldelink darin war aber für das *Konto des
Einlieferers* signiert (`configureUnsubscribe($user, …)`). Ein Klick des
Pressekontakts hätte connektar abgemeldet, nicht sich selbst.
**Umsetzung:** `EmailSuppressionReason::Unsubscribed` als dritter Zustand
in der Sperrliste. Mailables bekommen den tatsächlichen Empfänger
(`$recipientEmail`); weicht er vom Konto ab, trägt der Link die Adresse
(`/e-mail-benachrichtigungen/abmelden-adresse?email=…&type=…`, signiert,
One-Click-POST ohne CSRF wie bisher). Die Abmeldung gilt für alle
Benachrichtigungen an die Adresse; Rücknahme von der Bestätigungsseite.
Eine bestehende Zustellsperre wird nicht zur Abmeldung herabgestuft, und
eine Abmeldung löst nur der Empfänger selbst.
**Ausnahme im Gate:** `GateOutgoingMail` lässt `MagicLoginLink` an
abgemeldete Adressen durch (`suppressedAmong(…, includeUnsubscribed:
false)`), die Claim-Seite behandelt sie als erreichbar — den Anmeldelink
fordert die Person selbst an. Harte Bounces sperren weiterhin alles.
Tests: `AddressUnsubscribeTest` (5). Admin ▸ Mail-Sperrliste zeigt den
Grund „abgemeldet" ohne weitere Änderung.
**Damit ist Block 1d komplett.** Offen aus dem Block: ob der Autor beim
Block nach dem N-ten Rot eine kurze Mail bekommen soll („ein Mensch
prüft"); heute sieht er es nur im Konto.