DLR-Callbacks in A2P-SMS: idempotentes Design bei Duplikaten und falscher Reihenfolge
Gestalten Sie den Empfang von DLR-Callbacks als prüfbaren Verlauf und idempotente Statusprojektion, die Wiederholungen, Duplikate, verspätete Ereignisse und eine falsche Reihenfolge verarbeitet.

Die operative Frage: Was passiert, wenn ein Callback zweimal, verspätet oder in anderer Reihenfolge eintrifft?
Ein Delivery-Receipt-Callback (DLR) darf nicht als einmalige, geordnete und endgültige Aktualisierung behandelt werden. In einer HTTP-Integration kann eine Kommunikation fehlschlagen, bevor der Sender die Antwort erhält, und die Anfrage kann wiederholt werden. RFC 9110 definiert Idempotenz als die Eigenschaft, dass mehrere identische Anfragen denselben beabsichtigten Effekt haben wie eine einzelne Anfrage.
In der Praxis muss der Empfänger dieselbe Benachrichtigung mehrmals akzeptieren können, ohne sie mehrfach zu zählen oder den Nachrichtenstatus unzulässig zu verändern. Er muss auch einen Empfang erfassen können, der nach einem zuvor beobachteten Ereignis eintrifft, ohne Belege zu löschen oder anzunehmen, dass die Empfangsreihenfolge der tatsächlichen Verarbeitungsreihenfolge in der Messaging-Kette entspricht.
Die operative Regel ist einfach: Speichern Sie jeden Empfang, leiten Sie den aktuellen Status anhand expliziter Regeln ab und halten Sie beides getrennt. Der Verlauf beantwortet, was wann empfangen wurde; die Statusprojektion beantwortet, welches operative Ergebnis das System aus den verfügbaren Belegen berechnet.
- Nehmen Sie keine Zustellung an, nur weil Ihr Endpoint einen Callback empfangen hat.
- Gehen Sie nicht davon aus, dass der zuletzt empfangene Callback zwingend das zuletzt im Netz eingetretene Ereignis darstellt.
- Wenden Sie keine irreversible Aktualisierung ausschließlich auf Basis von Ziel, Inhalt oder einer ungefähren Übereinstimmung an.
- Reagieren Sie sicher auf Wiederholungen: Ein Retry darf keine doppelten buchhalterischen, analytischen oder operativen Effekte erzeugen.

Was ein DLR darstellt – und was nicht
In SMPP wird ein DLR in submit_sm über registered_delivery angefordert. Die Quittung kann, abhängig von Version, Implementierung und Konfiguration der Gegenpartei, über deliver_sm oder data_sm an das ESME zurückgegeben werden. Die Verfügbarkeit von Quittungen hängt daher davon ab, ob sie angefordert wurden und wie die Messaging-Plattform konfiguriert ist oder sich verhält.
SMPP unterscheidet anhand der Kodierung von esm_class zwischen einem SMSC Delivery Receipt und einer Zwischenbenachrichtigung. Zwischenbenachrichtigungen sind ein eigener Typ, dessen Unterstützung von der Implementierung des SMSC abhängt; sie dürfen nicht automatisch als endgültige Ergebnisse interpretiert werden.
Ein DLR informiert über den Status, den die Messaging-Kette innerhalb dieses Ablaufs meldet. DELIVERED bezeichnet einen von der Messaging-Kette gemeldeten Zustellstatus zum Ziel. Es ist keine unabhängige Bestätigung dafür, dass eine Person den Inhalt auf ihrem Endgerät gesehen, gelesen oder verstanden hat. In der SMPP-Semantik enthält der genannte Standard keinen Status für menschliches Lesen oder angezeigten Inhalt.
- Unterscheiden Sie die Annahme von submit_sm, die die Übergabe an das antwortende System bestätigt, von einem späteren DLR.
- Speichern Sie, ob ein DLR angefordert wurde und mit welcher registered_delivery-Option, sofern diese Angabe verfügbar ist.
- Kennzeichnen Sie das Ergebnis als von der Messaging-Kette gemeldeten Status, nicht als Lesebeleg des Empfängers.
- Behandeln Sie Zwischenbenachrichtigungen als separate Ereignisse von endgültigen Statuswerten.

Minimales Datenmodell für eine nützliche Nachvollziehbarkeit
Das Design muss die Daten bewahren, die zur Rekonstruktion einer Entscheidung erforderlich sind. Bewahren Sie für jede gesendete Nachricht eine unveränderliche interne Kennung und die vom Messaging-System zurückgegebene externe Kennung auf. In SMPP identifiziert receipted_message_id die Nachricht, auf die sich die Quittung bezieht, und entspricht der undurchsichtigen message_id, die bei der Bestätigung der ursprünglichen Übergabe zurückgegeben wurde.
Speichern Sie das Ziel in normalisierter Darstellung und bewahren Sie außerdem den empfangenen oder gesendeten Adressierungskontext auf. E.164 definiert den internationalen öffentlichen Nummerierungsplan; eine Normalisierung hilft, Formatvariationen zu vermeiden, darf jedoch nicht die ursprünglichen Werte ersetzen, die zur Fehleranalyse benötigt werden.
Das historische DLR-Format in short_message kann Kennung, Einreichungs- und Abschlusszeiten, Status und Fehler enthalten. Seine Einzelheiten können jedoch gateway- oder SMSC-spezifisch sein. Extrahieren Sie deshalb normalisierte Felder für den Betrieb, bewahren Sie aber immer die ursprüngliche Payload auf.
- Nachricht: interne ID, externe ID oder message_id, Absender, normalisiertes Ziel, ursprüngliche Adressierungswerte, Route oder Versandkontext und Einreichungszeitpunkt.
- Empfangenes Ereignis: Anbieter-Ereignis-ID, falls vorhanden, Empfangszeitpunkt, vom Sender gemeldeter Zeitpunkt, falls vorhanden, Ereignistyp, Rohstatus, Rohfehlercode und ursprüngliche Payload.
- Projektion: berechneter Status, Begründung der Entscheidung, das oder die Ereignisse, die diese Entscheidung stützen, sowie Aktualisierungszeitpunkt.
- Audit: Version des Parsers oder der angewendeten Regeln, Ergebnis der Korrelation und erkannte Ausnahmen.
Korrelation: stabile Schlüssel priorisieren und schwache Übereinstimmungen ablehnen
Die Korrelation zwischen der ursprünglichen Nachricht und dem DLR muss zuerst auf der externen Kennung basieren, die vom SMSC vergeben wurde. SMPP definiert receipted_message_id als Kennung der Nachricht, zu der die Quittung gehört. Außerdem verwendet query_sm die vom SMSC vergebene message_id zusammen mit der Quelladresse als Abgleichmechanismus.
Verwenden Sie Ziel, Text, Zeitfenster oder Absender nicht als automatische Ersatzwerte für die externe ID. Diese Attribute können sich bei legitimen Nachrichten wiederholen und eine falsche Zuordnung verursachen. Eine fehlerhafte Korrelation ist schädlicher als ein ausstehendes Ereignis: Sie kann den Status einer anderen Nachricht in eine Zustellung oder einen Fehler verwandeln, der ihr nie zuzuordnen war.
Wenn die Korrelation nicht eindeutig ist, erfassen Sie den Callback, ohne ihn zu verlieren, und leiten Sie ihn an eine Ausnahme-Warteschlange oder ein Ausnahmeprotokoll weiter. So lassen sich Formatänderungen, gekürzte IDs, Kodierungsvarianten oder andere Besonderheiten einer Integration untersuchen, ohne die Projektion bekannter Nachrichten zu verfälschen.
- Erste Wahl: receipted_message_id mit der beim Akzeptieren des Versands gespeicherten message_id verknüpfen.
- Bewahren Sie den externen Wert exakt wie empfangen auf, zusätzlich zu jeder von der Integration benötigten normalisierten Form.
- Verwenden Sie Absender, Ziel, Zeiten und Route als zusätzliche Validierungen, nicht als eindeutigen Zuordnungsschlüssel.
- Wenn es mehrere Kandidaten oder keinen Kandidaten gibt, markieren Sie die Korrelation als nicht eindeutig und materialisieren Sie keinen Status für eine konkrete Nachricht.
Idempotentes Muster für den Empfang und die Verarbeitung von Callbacks
Idempotenz bedeutet nicht, jede Wiederholung zu ignorieren. Sie ermöglicht, jede empfangene Anfrage als Beleg zu bewahren und gleichzeitig zu verhindern, dass die Wiederholung das operative Ergebnis mehrfach verändert. RFC 9110 stellt klar, dass ein Server jede einzelne Anfrage protokollieren kann, auch wenn der beabsichtigte Effekt der Operation idempotent ist.
Implementieren Sie zwei Ebenen. Die erste ist ein Empfangsprotokoll, vorzugsweise unveränderlich, das Payload, verfügbare relevante Header, Empfangszeitpunkt und Parser-Ergebnis speichert. Die zweite ist die Anwendung von Effekten: Deduplizierung, Korrelation und Statusberechnung. Nur diese zweite Ebene muss davor geschützt werden, dass dasselbe logische Ereignis zweimal angewendet wird.
Wenn der Sender eine stabile Ereignis-ID bereitstellt, verwenden Sie sie im richtigen Integrationskontext als Deduplizierungsschlüssel. Falls sie nicht existiert, erstellen Sie einen Fingerabdruck aus stabilen Attributen des Callbacks, bewahren Sie die verwendeten Komponenten auf und behalten Sie die ursprüngliche Payload. Stützen Sie den Fingerabdruck nicht auf Felder, die sich durch lokale Transformation ändern können, oder auf mehrdeutige Attribute, ohne das Risiko zu dokumentieren.
- 1. Empfangen Sie den Callback und persistieren Sie den Empfang, bevor Geschäftseffekte ausgeführt werden.
- 2. Validieren und extrahieren Sie verfügbare Felder, ohne die ursprüngliche Payload zu verwerfen.
- 3. Stellen Sie fest, ob eine stabile Ereignis-ID existiert; falls nicht, berechnen Sie einen dokumentierten Fingerabdruck für das logische Ereignis.
- 4. Fügen Sie das Ereignis atomar in das Register logischer Ereignisse ein oder erkennen Sie es dort.
- 5. Korrelieren Sie über die externe ID und wenden Sie Übergangsregeln nur einmal je logischem Ereignis an.
- 6. Geben Sie nach dem Persistieren des nötigen Ergebnisses eine konsistente HTTP-Antwort zurück, damit ein Retry sicher ist.
Zustandsautomat: erlaubte Übergänge explizit machen
Ein Zustandsautomat verhindert, dass die Logik von der zufälligen Reihenfolge des Eintreffens abhängt. Der SMPP-Formatleitfaden klassifiziert ENROUTE als Zwischenstatus sowie DELIVERED, EXPIRED, DELETED und UNDELIVERABLE als endgültige Status. Er weist außerdem darauf hin, dass eine Nachricht bei Wiederholungsversuchen ENROUTE bleiben und später in EXPIRED oder DELIVERED enden kann.
Stellen Sie empfangene Statuswerte dar, ohne sie umzuschreiben, und definieren Sie eine Ebene für den berechneten operativen Status. Im beschriebenen SMPP-Modell gehen endgültige Status nicht in andere Status über. Ein späteres Ereignis, das einem bereits berechneten Endstatus zu widersprechen scheint, darf ihn daher nicht stillschweigend ersetzen: Es muss erhalten bleiben und eine Ausnahme zur Abstimmung oder Untersuchung auslösen.
Verallgemeinern Sie Fehlercodes nicht von einer Plattform auf eine andere. Netz- oder SMSC-Codes können gateway- oder plattformspezifisch sein. Speichern Sie sie als ursprüngliche Belege und erstellen Sie interne Klassifizierungen nur dann, wenn Ihre Regeln für die konkrete Integration dokumentiert sind.
- Rohstatus: der empfangene Wert ohne destruktive Neuinterpretation.
- Normalisierter Status: eine dokumentierte interne Kategorie, sofern die Integration eine zuverlässige Zuordnung erlaubt.
- Berechneter Status: Ergebnis der Anwendung von Vorrang- und Übergangsregeln auf korrelierte Ereignisse.
- Ausnahme: Konflikt zwischen Ereignissen, widersprüchliches Endereignis, fehlende Korrelation oder unbekanntes Format.
- Konservative Regel: Ein bereits materialisierter Endstatus darf nicht allein deshalb in einen anderen Endstatus übergehen, weil ein späterer Callback eintrifft.
Verspätete Ereignisse und falsche Reihenfolge: Belege bewahren und vorsichtig berechnen
Speichern Sie mindestens zwei unterschiedliche Zeitangaben: wann Ihr System den Callback empfangen hat und welche Zeit der Callback meldet, sofern er eine meldet. Möglicherweise müssen auch die in Quittungsformaten enthaltenen Einreichungs- und Abschlusszeiten erhalten bleiben. Diese Zeitstempel sind nicht austauschbar: Der eine beschreibt die lokale Beobachtung, der andere die von der Messaging-Plattform übermittelte Angabe.
Um den berechneten Status zu bestimmen, ordnen Sie nicht blind nach dem Eingangszeitpunkt. Wenden Sie eine dokumentierte Richtlinie an, die Statustyp, Zwischen- oder Endcharakter und Qualität der Korrelation berücksichtigt. Wenn es keine verlässliche Grundlage gibt, zwei Ereignisse zu ordnen, erfinden Sie keine Reihenfolge: Bewahren Sie beide auf und markieren Sie den Konflikt.
Die operative Ausgabe muss zwischen dem vollständigen Verlauf und der aktuellen Zusammenfassung unterscheiden. Ein Dashboard kann einen endgültigen berechneten Status anzeigen und zugleich darauf hinweisen, dass wiederholte, verspätete oder widersprüchliche Ereignisse aufgetreten sind. Dieser Ansatz verringert die Versuchung, Signale zu verbergen, die später für Support, Abstimmung oder Qualitätsanalysen entscheidend werden.
- Bewahren Sie die lokale Empfangsreihenfolge, gemeldete Zeiten und die ursprüngliche Payload auf.
- Löschen Sie kein Duplikat: Kennzeichnen Sie es gegebenenfalls als Wiederholung desselben logischen Ereignisses.
- Ersetzen Sie einen Endstatus nicht durch einen anderen inkompatiblen Endstatus, wenn es dafür keine vertragliche oder technisch überprüfbare Regel für diese Integration gibt.
- Verwenden Sie eine Untersuchungswarteschlange für Konflikte und nicht korrelierte Nachrichten.
- Legen Sie im Audit offen, welches Ereignis den berechneten Status stützt und welche Ereignisse nicht angewendet werden konnten.
Checkliste für die Produktion
Bevor Sie DLR-Callbacks mit Kennzahlen, Abrechnung, Warnungen oder Kampagnenentscheidungen verbinden, testen Sie die Integration als Ereignissystem und nicht nur als erfolgreichen HTTP-Aufruf. Entscheidend ist, dass ein Retry, eine unerwartete Payload oder eine Quittung ohne Korrelation nicht zu einer falschen Zustellungsbehauptung wird.
Bei jeder Verbindung sollten Sie die konkrete Semantik von Feldern, Formaten und Quittungsregeln der Gegenpartei bestätigen, bevor Sie sie in kritische Automatisierungen übernehmen.
- Testen Sie denselben Callback wiederholt und bestätigen Sie, dass sich berechneter Status und Zähler durch die Wiederholung nicht ändern.
- Testen Sie ein Zwischenereignis, das nach einem Endstatus eintrifft, und bestätigen Sie, dass es das Endergebnis nicht verschlechtert oder überschreibt.
- Testen Sie zwei inkompatible Endstatus und stellen Sie sicher, dass der zweite erhalten bleibt und zur Untersuchung markiert wird.
- Testen Sie Callbacks ohne Ereignis-ID, mit nicht gefundener externer ID sowie mit nicht erkannten Datumsformaten oder Payloads.
- Stellen Sie sicher, dass nicht korrelierte Nachrichten nicht automatisch über Ziel oder Inhalt zugeordnet werden.
- Prüfen Sie, dass Berichte zwischen Annahme, gemeldetem DLR-Status und einer möglichen unabhängigen Prüfung außerhalb des DLR unterscheiden.
Häufige Fragen
Bedeutet ein doppelter DLR-Callback, dass die SMS zweimal zugestellt wurde?
Nein. Es kann sich um die Wiederholung einer Benachrichtigung handeln. Sie sollte als beobachteter Empfang erhalten bleiben, aber der Effekt auf den berechneten Status und die Zähler darf nur einmal pro logischem Ereignis angewendet werden.
Kann ich einen DLR nur anhand der Zielnummer korrelieren?
Das ist nicht empfehlenswert. Das Ziel kann bei mehreren Nachrichten identisch sein. Die wichtigste Grundlage der Korrelation sollte die der Nachricht zugewiesene externe ID sein, etwa die SMPP-message_id in Verbindung mit receipted_message_id. Das Ziel dient als zusätzliche Validierung.
Bestätigt DELIVERED, dass der Empfänger die Nachricht gelesen hat?
Nein. DELIVERED ist ein von der Messaging-Kette gemeldeter Zustellstatus zum Ziel. Er stellt keine unabhängige Bestätigung menschlichen Lesens oder der Anzeige des Inhalts auf dem Endgerät dar.
Was mache ich, wenn ein Endstatus nach einem anderen, abweichenden Endstatus eintrifft?
Bewahren Sie beide Ereignisse auf und markieren Sie den Konflikt zur Untersuchung. Ersetzen Sie einen Endstatus nicht stillschweigend durch einen anderen inkompatiblen Endstatus, nur aufgrund der Empfangsreihenfolge des Callbacks.
Muss die ursprüngliche DLR-Payload gespeichert werden?
Ja. Formate und Codes können je nach Plattform variieren. Die ursprüngliche Payload ermöglicht die Prüfung des Parsers, die Analyse nicht normalisierter Felder und die Untersuchung von Abweichungen, ohne empfangene Belege zu verlieren.
Verwendete Quellen
- SMPP Protocol Specification v3.4, Issue 1.2SMPP Developers Forum
- SMPP Delivery Receipt FormatSMPP Developers Forum
- RFC 9110: HTTP SemanticsIETF / RFC Editor
- Recommendation ITU-T E.164: The international public telecommunication numbering planInternational Telecommunication Union