DLR-Statuscodes: SMPP-Message-States und was sie wirklich aussagen

Zustellberichte sind das Nächstbeste zur belastbaren Wahrheit, das ein SMS-Stack liefert, und dennoch sind sie keine absolute Wahrheit. Dieser Artikel ordnet SMPP-v3.4-message_state-Werte dem zu, was jeder aussagt und nicht aussagt, welche States sich noch ändern können, wie Receipt-Text und Netzwerkfehler-Familien dazu passen und wie Sie sie in Webhooks verarbeiten, ohne einem einzelnen Stat-Feld zu sehr zu vertrauen.

ACCEPTEDENROUTEDELIVEREDfinalEXPIREDfinalUNDELIVERABLEfinalREJECTEDfinalDELETEDfinalZwischenzustände (kleine Punkte) können sich noch ändern; Endzustände (große Punkte) nicht

SMPP-v3.4-message_state-Werte: was jeder aussagt

SMPP v3.4 definiert eine kleine Menge von message_state-Werten in deliver_sm-Zustellberichten und query_sm-Antworten. Behandeln Sie sie als netzseitig gemeldete Klassifikationen, nicht als forensischen Nachweis von Handset-Verhalten. Dieselbe Bezeichnung kann von unterschiedlichen Hops mit unterschiedlicher Konfidenz kommen. Koppeln Sie den State stets mit dem Receipt-Text, einem etwaigen Netzwerkfehlercode und Ihren eigenen Submit-/Done-Zeitstempeln.

ENROUTE sagt aus, dass die Nachricht in den Zustellpfad aufgenommen wurde und beim meldenden Knoten noch kein terminales Ergebnis vorliegt. Es sagt nicht aus, dass das Handset geklingelt hat, der HLR-Lookup erfolgreich war oder die Nachricht am Ende zugestellt wird. DELIVRD oder DELIVERED sagt aus, dass ein Downstream-Knoten erfolgreiche Zustellung an das Handset oder an einen akzeptierten Store-and-Forward-Endpunkt gemeldet hat, den das Netz als zugestellt behandelt. Es sagt nicht Lesebestätigung, App-Install oder korrektes Rendering Ihres Inhalts aus. EXPIRED sagt aus, dass die Gültigkeitsdauer ohne erfolgreichen, netzseitig finalen Zustellbericht abgelaufen ist. Es sagt nicht aus, dass das Handset die ganze Zeit aus war - nur dass die Zeit nach den Regeln des Pfads abgelaufen ist.

DELETED sagt aus, dass die Nachricht vor finaler Zustellung aus einem Message Center oder einer Queue entfernt wurde, typischerweise durch administrative oder netzseitige Purge-Aktion. Es sagt nicht, wer das Löschen ausgelöst hat oder ob ein Handset die SMS je gesehen hat. UNDELIVERABLE sagt aus, dass das Netz unter aktuellen Bedingungen die Zustellung als nicht abschließbar bewertet. Es stempelt die MSISDN nicht dauerhaft für jeden künftigen Versuch als ungültig; Bedingungen ändern sich. ACCEPTED sagt aus, dass die Nachricht von einer Downstream-Entität angenommen wurde, die nicht zwingend eine klassische Handset-Zustellung zurückmeldet - üblich bei bestimmten Application-Endpoints oder intermediären Acceptance-Semantiken. Es ist kein Synonym für DELIVERED.

UNKNOWN sagt aus, dass der meldende Knoten das Ergebnis keinem spezifischeren State zuordnen kann. Es bedeutet nicht, dass die Nachricht ohne Logs auf Ihrer Seite verschwunden ist; es bedeutet, dass der erhaltene Receipt uninformativ ist. REJECTED sagt aus, dass die Nachricht durch eine Netz- oder Plattformrichtlinie vor oder anstelle des normalen Abschlusses des Zustellversuchs abgelehnt wurde. Es bedeutet nicht immer, dass die Nummer ungültig ist - Inhalt, Originator, Throughput oder Barring-Regeln können je nach Pfad denselben State erzeugen.

SMSRoute-Konten enthalten kostenlose Testguthaben, mit denen Sie die Zustellung vor der Zahlung prüfen, und Tools zum Delivery-Testing sind im SMSRoute-Dashboard verfügbar.

message_stateSagt ausSagt nicht aus
ENROUTEUnterwegs auf einem meldenden PfadHandset erreicht oder späterer Erfolg
DELIVEREDDownstream-Erfolgsmeldung empfangenLesebestätigung, UX-Erfolg oder unveränderliche Wahrheit
EXPIREDGültigkeitsfenster ohne Erfolg beendetDauerhafter Handset- oder Nummernfehler
DELETEDVor finaler Zustellung aus MC/Queue entferntAkteursidentität oder Handset-Sichtbarkeit
UNDELIVERABLEPfad bewertet Zustellung derzeit als nicht abschließbarLebenslange dauerhafte Ungültigkeit
ACCEPTEDAngenommen von einem Endpoint mit nicht-klassischer DLR-SemantikHandset-Zustellung gleichwertig zu DELIVERED
UNKNOWNKeine bessere Klassifikation verfügbarFehlen jeglicher System-Logs
REJECTEDUnter Policy- oder Routing-Regeln abgelehntImmer eine ungültige MSISDN

Finale versus intermediate Zustände

Intermediate Zustände können sich noch ändern. ENROUTE ist der klare intermediate Zustand: danach können DELIVERED, EXPIRED, UNDELIVERABLE, REJECTED, DELETED oder sogar ACCEPTED folgen. UNKNOWN sollte operativ als nicht-final behandelt werden, sofern Ihr Upstream-Vertrag nichts anderes sagt; viele Integrationen sehen UNKNOWN ersetzt, sobald ein klarerer Receipt eintrifft, und manche erhalten nie ein Update.

Finale Zustände sind jene, für die Ihr Handler normalerweise Submit-Retries stoppen sollte: DELIVERED, EXPIRED, DELETED, UNDELIVERABLE, REJECTED und typischerweise ACCEPTED, wenn der Pfad ACCEPTED als terminales Application-Acceptance nutzt. Final heißt final für diese Message-Identity auf diesem Pfad – nicht final für das Business-Outcome. Ein DELIVERED DLR kann trotzdem falsch sein; auf ein EXPIRED kann nur in defekten oder Multi-Path-Setups eine für den Nutzer sichtbare späte SMS folgen, was Sie als Defect-Signal und nicht als erwartetes SMPP-Verhalten werten sollten.

State Machines um Message-ID-Korrelation herum bauen, nicht um Hoffnung. Bei ENROUTE die Zeile offen halten. Bei finalem Zustand Outbound-Retries für diese ID schließen, State- und err-Felder speichern und nur bei expliziter Duplicate-ID-Conflict-Policy unter Ihrer Kontrolle wieder öffnen. DELIVERED nicht zurück auf ENROUTE kippen, weil ein zweiter Receipt freundlicher wirkt – stattdessen die Anomalie loggen.

Receipt-Textkonvention und Netzwerk-Error-Code-Familien

Viele SMSC-deliver_sm-Receipts betten einen kurzen Textbody nach langlebiger ESM-Konvention ein. Felder erscheinen üblich als gelabelte Tokens: id (Message-Identifier wie die MC sie kennt), sub (Submit-Count), dlvrd (Delivered-Count), submit date, done date, stat (textueller State wie DELIVRD, EXPIRED, UNDELIV, ACCEPTD, REJECTD) und err (Netzwerk- oder MC-Error-Code). Parsing muss defensiv sein: Spacing, Zero-Padding bei Dates und stat-Schreibweisen variieren je Pfad. Structured message_state TLV bevorzugen, wenn vorhanden, und stat als Korroboration nutzen, nicht als einziges Signal.

Das err-Feld ist kein universelles Wörterbuch. Carrier und Hubs komprimieren unterschiedliche Failures in überlappende Codes. In qualitativen Familien arbeiten statt per-Carrier-Tabellen zu erfinden. Absent-Subscriber-Familie: das Netz konnte den Subscriber nicht erreichen – aus, außer Coverage oder temporär detached, je nach Hop. Handset-Memory-Familie: Gerät- oder SIM-Speicherpfad hat Intake abgelehnt oder deferred. Barring-Familie: Originator-, Destination-, Content-Class- oder Subscriber-Barring verhinderte Completion. Routing-Failure-Familie: keine viable Route, Destination-Netz von diesem Interconnect unerreichbar oder Address-Formatting vor Deep Delivery abgelehnt. Diese Familien steuern Retries und User-Messaging; sie rechtfertigen keine hardcodierten Mythen, dass ein einzelner numerischer Code immer eine Root Cause meint.

Familien mit Zurückhaltung auf Produktverhalten mappen. Absent-Subscriber- und Handset-Memory-Outcomes rechtfertigen oft begrenzte, validity-bewusste Retries oder langsameres Follow-up. Barring und viele Routing Failures sollten in der Regel nicht mit schnellen Resubmits derselben Payload gehämmert werden. Fehlt err oder ist null, während stat Failure anzeigt: der Failure-Klasse glauben und den Raw Receipt für Support-Eskalation behalten.

SMSRoute's Error-Code-Lookup-Tool deckt dieselben States interaktiv ab.

EXPIRED versus REJECTED in der Praxis

EXPIRED und REJECTED sind beide typischerweise final, beantworten aber unterschiedliche Fragen. EXPIRED heißt: die Message durfte innerhalb einer Validity Period versuchen, und dieses Fenster endete ohne vom meldenden Knoten akzeptierten Erfolg. Ursachen clustern um Handset-Unavailability, deferred Delivery die nie freigab, oder Path-Latenz jenseits der von Ihnen oder der MC gesetzten TTL. REJECTED heißt Refusal – Policy, Screening, ungültige oder non-routable Address-Behandlung am rejecting Hop, kommerzieller Block oder ähnliche sofortige bzw. nahezu sofortige Ablehnung – und kein sauberes Auslaufen der Zeit.

In Handlern lädt EXPIRED zur Prüfung von Validity-Period-Konfiguration, Submit-Time versus Done-Time und ob ENROUTE bis Timeout anhielt. REJECTED lädt zur Prüfung von Destination-Format (E.164 bis 15 Stellen), Originator-Permissions, Content-Rules und ob der Reject unmittelbar nach Submit kam. Ein sofortiges REJECTED mit near-zero Latency ist eine andere operative Story als langes ENROUTE, das am Validity-Rand zu EXPIRED wird. Keiner der beiden States ist ein höfliches Synonym des anderen; sie in einen einzigen Fehler-Boolean zu kollabieren wirft Retry- und Compliance-Signal weg.

Fake-DLR-Warnsignale

Weil DLRs für die Reputation wertvoll sind, unplausible Zustellbestätigungen als Vorfälle erster Klasse behandeln. Red Flags sind u. a. einheitliches DELIVERED über große gemischte Zielmengen ohne Varianz in den Ergebnis-Familien, die in Real Traffic erscheinen müssten, und implausible Latency – Done-Dates am oder jenseits des Messrauschens von Submit bei perfektem Erfolg, oder fixe Latenzen, die sich nicht mit der Destination-Region änderner Tageszeit bewegen. Weiteres Flag: stat-Text der nie mit einem immer-null err auf failure-prone Routes divergiert, oder Message IDs die nicht mit Ihren Submit-Responses korrelieren.

Bei Red Flags automatisierte Annahmen einfrieren, die DELIVERED mit User-Reachability gleichsetzen, Raw PDUs oder Webhook-Payloads behalten und mit kontrollierten Sendern verifizieren, die Sie betreiben. SMSRoute-Accounts enthalten kostenlose Test-Credits, die Delivery beweisen bevor Sie zahlen, und Delivery-Testing-Tools sind im SMSRoute-Dashboard verfügbar. Damit eine Baseline realistischer State-Mix und Timing etablieren, bevor Sie einer neuen Route in Production-Logic vertrauen.

Der SMSRoute DLR Guide erklärt die Webhook-Mechanik, über die diese States eintreffen.

Einsatz in Webhook-Handlern

Den Webhook als Korrelator strukturieren, nicht als Single-Field-Switch. Auf die Provider-Message-ID keyen, die beim Submit zurückkam; Submit-Timestamps selbst speichern; message_state oder stat, err und Done Date ingestieren; dann den internen Record mit expliziter State Machine transitionieren. HTTP 200 erst nach durable Persistence des Receipts akzeptieren, damit Provider-Retries Side Effects nicht verdoppeln; HTTP 429 oder HTTP 500 nur antworten, wenn Sie wirklich einen Retry brauchen, und diese Pfade idempotent halten.

Inbound States in ein eigenes Enum normalisieren, das SMPP-Unterscheidungen erhält – mindestens delivered, expired, rejected, undeliverable, accepted, deleted, enroute und unknown trennen. Error-Family-Tags qualitativ anhängen, ohne carrier-offizielle Dictionaries zu behaupten, die Sie nicht pflegen. Für ENROUTE und ungelöstes UNKNOWN Observation schedulen, keinen user-facing Success. Für DELIVERED Transport-Success markieren und business-kritische Actions weiterhin an eigene Application Acknowledgements koppeln, wo die Domain es verlangt.

Schließlich p50 und p95 der Submit-to-Done-Latency pro Route-Class loggen, damit fake oder degradierte DLR-Patterns als Distributions-Shifts statt als Anekdoten auffallen. Payload-Size-Disziplin beim Send im Blick behalten – 160/153 GSM-7- und 70/67 UCS-2-Segmenting-Regeln prägen weiterhin, wie Splits und Partial Failures downstream erscheinen – aber keine Delivery-Percentages erfinden. Unsicherheit gehört zur Protocol Surface; präzise Handler protokollieren, was asserted wurde, was nicht, und was als Nächstes passiert.

Häufig gefragt

Was sind die SMPP v3.4 message_state-Werte und welche sind final?
Das v3.4-Set umfasst ENROUTE, DELIVERED, EXPIRED, DELETED, UNDELIVERABLE, ACCEPTED, UNKNOWN und REJECTED. ENROUTE ist intermediate und kann sich noch ändern; UNKNOWN ist operativ nicht-final, sofern Ihr Upstream-Vertrag nichts anderes sagt. DELIVERED, EXPIRED, DELETED, UNDELIVERABLE, REJECTED und typischerweise ACCEPTED gelten als final für diese Message ID auf diesem Pfad.
Worin unterscheidet sich EXPIRED von REJECTED bei einem SMS DLR?
EXPIRED heißt: die Validity Period ist ohne vom reporting Node akzeptierten Success abgelaufen, nachdem die Message Delivery versuchen durfte. REJECTED heißt: die Message wurde unter Policy-, Routing- oder Screening-Regeln verweigert statt auszutimen. Immediate Rejects und lange enroute-then-expired Pfade sollten nicht in einen failed-Bucket kollabiert werden, wenn Ihnen Retries und Config-Fixes wichtig sind.
Welche Felder erscheinen im klassischen SMPP Delivery-Receipt-Textbody?
Übliche gelabelte Tokens sind id, sub, dlvrd, submit date, done date, stat und err. Structured message_state nutzen wenn verfügbar und stat/err als Korroboration behandeln; err-Codes in qualitative Familien wie Absent Subscriber, Handset Memory, Barring und Routing Failures gruppieren statt als universelle per-Carrier-Tabelle zu vertrauen.

Verwandt