149 countries · crypto-native · no KYC

SMPP Delivery Receipt Format: Parsing DLRs Without Guessing

SMPP delivers the same status two ways at once — a text blob in the message body and structured TLV fields. Parse the wrong one and your delivery tracking breaks silently. Here's how to read both.

$0.035/msg from sub-100ms median 98.6% delivered
SMPP Delivery Receipt Format: Parsing DLRs Without Guessing — smsroute
$0.004
per SMS from
149
countries
60s
to first message
6
crypto rails
An SMPP delivery receipt (DLR) is how your application learns whether a message actually reached a handset. It is the level-three confirmation that the three levels of error handling all build toward. But two things trip up teams parsing them. First, you only get a DLR if you *asked* for one, via the registered_delivery field on the original submit_sm. Second, the SMPP delivery receipt format delivers the outcome in two places at once: a text blob and structured fields. Which one to trust depends on your SMPP version and provider. Read the wrong one and your delivery tracking quietly reports garbage.

Requesting a receipt, then reading it

An SMPP delivery receipt (DLR) is how your application learns whether a message actually reached a handset. It is the level-three confirmation that the three levels of error handling all build toward. First, you only get a DLR if you *asked* for one, via the registered_delivery field on the original submit_sm. Second, the SMPP delivery receipt format delivers the outcome in two places at once: a text blob and structured fields. Which one to trust depends on your SMPP version and provider.

registered_delivery: no request, no receipt

Why is registered_delivery required for SMPP delivery receipts?

Without setting registered_delivery in your SMPP submit_sm, the SMSC treats your message as fire-and-forget and never generates a delivery receipt. SMSRoute's API automatically handles this flag for you, ensuring every message gets a DLR without manual configuration.

The dual format: text blob and TLVs — comparison diagram

Whether you get a delivery receipt depends entirely on the registered_delivery field you set when submitting the message. It is not automatic. A submit_sm without it asks for no confirmation, and you will never learn the outcome no matter how correctly your bind is set up. This is the second-most-common reason for 'my messages send but I get no DLRs' (after a transmitter-only bind).

The dual format: text blob and TLVs

How do SMPP delivery receipts come in dual format?

SMPP DLRs arrive as both a human-readable text blob (e.g., 'id:1234 sub:001 dlvrd:001') and structured TLVs (tag-length-value fields) for machine parsing. SMSRoute's API delivers both formats in every DLR webhook, so you can parse whichever suits your system best.

Here is the part that surprises people. To be compatible with both SMPP v3.4 and v5.0, the delivery status arrives *two ways in the same receipt*. The classic way is a text string in the short_message field with parseable stat and err components. The modern way is structured TLV (Tag-Length-Value) parameters: receipted_message_id, message_state, and network_error_code. The SMPP v3.4 specification defines the text format, while v5.0 introduced the TLV approach (SMPP v5.0 specification, 2026).

Format Where Contains Best for
Text (short_message) The message body of the DLR stat (status), err (error), id, timestamps v3.4 compatibility; human-readable
TLV parameters Optional TLV fields message_state, network_error_code, receipted_message_id v5.0; structured, less error-prone to parse

The practical rule: prefer the TLVs (message_state, network_error_code) when your provider sends them. They are structured and unambiguous. Fall back to parsing the short_message te

Parsing it reliably

How can I parse SMPP delivery receipts reliably?

Parse the text blob using regex for fields like id, sub, dlvrd, and stat, or extract TLVs directly for precision. SMSRoute provides ready-to-use parsing examples in Python, PHP, Go, and Node on GitHub, eliminating guesswork and ensuring your integration works first time.

  1. Match the receipt to the original messageUse receipted_message_id (TLV) or the id in the text blob to correlate the DLR back to the message you sent. Store your submit_sm message ids so you can reconcile. This is the same discipline as REST-level DLR handling.
  2. Read message_state / stat for the outcomemessage_state (TLV) or stat (text) tells you DELIVERED, UNDELIVERABLE, EXPIRED, etc. This is the answer you requested the DLR for.
  3. Read network_error_code / err for the whyWhen a message failed, the error field explains it. This is a foundation for deciding whether to retry, revalidate the number, or try another channel.
  4. Handle both formats defensivelyTLVs first, text-blob fallback. Do not assume one. A provider or version change that drops you to the other format should not break your parser silently.

SMSRoute is a no-KYC SMS API with crypto billing (BTC, ETH, USDT, XMR, LTC, and SOL) and supports SMPP with delivery receipts alongside its REST API (where DLRs arrive as clean webhook callbacks instead of this dual binary format). If yo

FAQ

What is the SMPP delivery receipt format?
An SMPP DLR carries the delivery outcome in two ways for cross-version compatibility: a text string in the short_message field (with stat and err components, used in v3.4) and structured TLV parameters (message_state, network_error_code, receipted_message_id, used in v5.0). Robust parsers read the TLVs when present and fall back to the text blob when not.
Why am I not receiving SMPP delivery receipts?
Two common causes: a transmitter-only bind (which can't receive DLRs — you need a receiver or transceiver bind), or not setting the registered_delivery field on your submit_sm. Delivery receipts aren't automatic; you must request them per message via registered_delivery, and your bind must be able to receive.
What is the registered_delivery field in SMPP?
A field on the submit_sm operation that tells the SMSC whether and when to send you a delivery receipt. Set to 0 you get no receipt; set to 1 you get one on final delivery or failure. Other values request receipts for intermediate states or failures only. You control it per message, so you can request DLRs selectively.
Should I parse the text blob or the TLVs in an SMPP DLR?
Prefer the TLVs (message_state, network_error_code, receipted_message_id) when your provider sends them — they're structured and unambiguous. Fall back to parsing the short_message text (stat/err fields) when TLVs aren't present, which is common with SMPP v3.4. Handle both defensively, since you'll encounter both across providers and versions.

Send your first SMS in 5 minutes

How quickly can I send my first SMS with SMSRoute?

Sign up with just an email (no KYC), fund with crypto (BTC, ETH, USDT, XMR, LTC, SOL), get your API key, and send your first message—all in under 5 minutes. Free test credits are included to verify routes before you commit any real balance.

No KYC. Pay with BTC, ETH, USDT, XMR, LTC, and SOL. Live routes to 149 countries.

Get an API key →