---
title: "SMS delivery report (DLR) decoder"
description: "Decode SMPP delivery receipts: stat codes such as DELIVRD and UNDELIV, err, submit and done dates, latency and command_status errors. Free, in your browser."
canonical: "https://omnichannels.ai/tools/sms-delivery-report-decoder/"
language: "en"
updated: "2026-10-10"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
---

# SMS delivery report (DLR) decoder

Canonical: https://omnichannels.ai/tools/sms-delivery-report-decoder/
Language: en
Publisher: OmniChannels.ai by BroadNet Technologies

An SMPP delivery report (DLR) is the receipt an SMSC returns in a deliver_sm PDU after you submit an SMS. Its text follows the pattern id, sub, dlvrd, submit date, done date, stat, err and text. The stat field holds the outcome: DELIVRD means delivered to the handset; UNDELIV, EXPIRED, DELETED and REJECTD are final failures; ENROUTE and ACCEPTD are intermediate. Dates use YYMMDDhhmm, sometimes with seconds.

## How to decode an SMS delivery receipt
1. **Copy the receipt text:** Take the short_message of the deliver_sm PDU from your SMPP client or SMSC log, for example id:… sub:001 dlvrd:001 … stat:DELIVRD err:000. Log prefixes are ignored.
2. **Paste one per line:** Paste a single receipt or hundreds of them. You can also paste a command_status value such as 0x00000058 or ESME_RTHROTTLED on its own line.
3. **Read the decoded fields:** Each receipt shows the status meaning, whether it is final, the closest webhook status, readable dates, delivery latency and warnings for missing or inconsistent fields.
4. **Check the batch summary:** See counts by stat and by webhook status, the delivery rate and the median latency, then copy everything as JSON for a ticket or a test fixture.

## Anatomy of an SMPP delivery receipt

When you submit an SMS with registered_delivery set to 1, the SMSC later sends a deliver_sm PDU back on a receiver or transceiver bind. Bit 0x04 in its esm_class marks it as a delivery receipt rather than an inbound message, and its short_message carries a text receipt. Appendix B of the SMPP v3.4 specification gives this format as an example, and nearly every SMSC follows it: id:IIIIIIIIII sub:SSS dlvrd:DDD submit date:YYMMDDhhmm done date:YYMMDDhhmm stat:DDDDDDD err:E text:….
Because Appendix B is an example rather than a strict rule, real receipts vary: lowercase keys, extra spaces, submit_date with an underscore, 12-digit dates with seconds, or missing text. This decoder accepts all of those and tells you which fields are missing.
- id: the message ID the SMSC returned in submit_sm_resp. Use it to match the receipt to your message. The spec example shows 10 characters, but many SMSCs use longer IDs, sometimes in hex.
- sub and dlvrd: the number of messages originally submitted and delivered, as 3 digits. They matter mainly for distribution lists; for a single SMS they are typically 001 and 001 (or 000).
- submit date and done date: when the message was submitted and when it reached its final state, in the SMSC's clock.
- stat: the final or intermediate state, as a 7-letter code such as DELIVRD.
- err: a 3-character error code, network or SMSC specific; 000 means no error.
- text: the first 20 characters of the original message, often truncated or blank.
- Optional TLVs can repeat this data in a cleaner form: receipted_message_id (0x001E), message_state (0x0427) and network_error_code (0x0423).

## DLR stat codes and what they mean

SMPP v3.4 defines eight message states. ENROUTE and ACCEPTD are intermediate; the others are final. Our API normalises every channel to six webhook statuses (SUBMITTED, SENT, DELIVERED, READ, FAILED, REJECTED), and the decoder shows the closest match for each stat value. Treat that mapping as indicative: the exact rule for your account is confirmed during onboarding.
- DELIVRD (message_state 2): delivered to the handset. Closest webhook status: DELIVERED.
- ACCEPTD (6): formally 'read manually on behalf of the subscriber by customer service', but most SMSCs send it as an intermediate 'accepted by the network' receipt. Closest: SENT.
- ENROUTE (1): still in transit, for example queued for a retry. Closest: SENT.
- UNDELIV (5): undeliverable, for example an invalid or inactive number. Closest: FAILED.
- EXPIRED (3): the validity period ended before the handset could be reached, often because it was off or out of coverage. Closest: FAILED.
- DELETED (4): deleted before delivery, for example by cancel_sm. Closest: FAILED.
- REJECTD (8): refused by the network or a firewall, for example an unregistered sender ID or blocked content. Closest: REJECTED.
- UNKNOWN (7): the SMSC has no final state. Treat it as unconfirmed, not as a proven failure.

## err codes: why there is no universal list

The err field is three characters wide and the SMPP specification does not define its values. 000 always means no error, but non-zero values come from the SMSC vendor, the operator or an aggregator in between. Some SMSCs pass through GSM MAP error causes (for example, MAP error 1 is unknown subscriber and 27 is absent subscriber), while others map everything to their own table.
If the receipt carries the network_error_code TLV (0x0423), it is more reliable: its first octet gives the network type (3 means GSM) and the next two the error code. A DELIVRD receipt with a non-zero err is inconsistent and worth raising with your provider; the decoder flags it.

## command_status errors versus delivery receipts

SMPP reports problems at two moments. The command_status in submit_sm_resp arrives within milliseconds and says whether the SMSC accepted your request; 0x00000000 (ESME_ROK) means accepted, not delivered. The delivery receipt arrives seconds to days later and carries the final outcome.
command_status values are defined in section 5.1.3 of SMPP v3.4. The most common in production are 0x00000058 ESME_RTHROTTLED (you exceeded your agreed messages per second: slow down and retry with exponential backoff), 0x00000014 ESME_RMSGQFUL (queue full: back off), 0x0000000A and 0x0000000B (invalid source or destination address) and 0x0000000D or 0x0000000E (bind failed or wrong password). Values 0x00000400 to 0x000004FF are reserved for SMSC vendor-specific errors, so ask your provider about those.

## Dates, time zones and delivery latency

Receipt dates use YYMMDDhhmm, and many SMSCs append seconds (YYMMDDhhmmss). The receipt carries no time zone: the time is whatever the SMSC clock uses, usually UTC. The decoder shows the dates exactly as written and computes latency as done date minus submit date, which is unaffected by the time zone as long as both come from the same clock.
Latency is a useful quality signal. Healthy OTP traffic to a reachable handset usually completes within seconds. Long latencies followed by EXPIRED point to handsets that are switched off or roaming, and a done date earlier than the submit date means the two clocks disagree. Minute-level dates cannot measure sub-minute latency, so prefer SMSCs that send seconds.

## Handling receipts reliably in production

Answer every deliver_sm with deliver_sm_resp, even if your processing fails, otherwise the SMSC resends it and may throttle the bind. Store the raw receipt, then process it asynchronously and idempotently by message ID, because receipts can arrive twice or out of order: a late ENROUTE must never overwrite DELIVRD.
If you would rather not parse receipts at all, our REST SMS API delivers the same information as normalised webhook statuses, and missed receipts can be re-pushed with POST /sms/resendDlr. SMPP binds over TLS are available for high-volume senders and resellers.

## Delivery report questions

### What does stat:DELIVRD mean in an SMS delivery report?

DELIVRD is the SMPP message state 'delivered': the SMSC has confirmation that the message reached the recipient's handset. It does not mean the message was opened or read; plain SMS has no read receipts. In our webhooks it corresponds to DELIVERED.

### What is the difference between UNDELIV, EXPIRED and REJECTD?

UNDELIV means the network could not deliver the message, for example because the number is invalid or inactive. EXPIRED means delivery attempts continued until the validity period ended, usually because the phone was off or out of coverage. REJECTD means the network or a firewall refused the message, for example an unregistered sender ID or blocked content.

### What does ACCEPTD mean in an SMPP DLR?

In the SMPP v3.4 specification ACCEPTD means the message was read manually on behalf of the subscriber by customer service. In practice most SMSCs and aggregators use it as an intermediate receipt meaning the network accepted the message, and a final DELIVRD or failure receipt follows.

### What is SMPP error 0x00000058?

0x00000058 is ESME_RTHROTTLED: you sent more messages per second than your bind allows. It is temporary. Reduce your sending rate, keep a sensible window of outstanding submit_sm PDUs and retry the rejected messages with exponential backoff rather than immediately.

### What does err:000 mean, and where can I find other err codes?

err:000 means no error. Non-zero err values are not defined by the SMPP specification; they come from the SMSC vendor, the operator or an aggregator, and some pass through GSM MAP error causes. Ask your provider for their error table, and check the network_error_code TLV if it is present.

### What date format does an SMPP delivery receipt use?

submit date and done date use YYMMDDhhmm, for example 2610101201 for 10 October 2026 at 12:01. Many SMSCs add seconds (YYMMDDhhmmss). No time zone is included; it is the SMSC's clock, usually UTC.

### Why did I not receive a delivery report?

Common causes are registered_delivery not set to 1 in submit_sm, using a transmitter-only bind without a receiver bind, a destination network that does not return receipts, or your client not acknowledging deliver_sm. Some routes only return intermediate receipts. For REST traffic, check your webhook endpoint and re-push receipts with /sms/resendDlr.

### Is my receipt text sent anywhere when I use this tool?

No. The decoder runs entirely in your browser. Nothing you paste, including message IDs or message text, is sent to our servers.
