SMS Delivery Receipts and Fake DLRs
A delivery receipt is a claim, not proof. How DLRs are generated, what the status fields mean, and the patterns that show a route is manufacturing them.
A delivery receipt is a message from the network saying what happened to a message you sent. It is the primary evidence most senders have about route quality, which is exactly why it is the thing least worth taking on trust.
How a DLR is supposed to work
You submit a message. The SMSC accepts it and returns a message ID. Later, the destination network reports the outcome back up the chain, and you receive a deliver_sm PDU carrying a receipt that references your original message ID.
The receipt body follows a broadly standard text format containing the message ID, submit and done counts, a status, an error code, and timestamps. The field that matters most is stat.
The status values
- DELIVRD, delivered to the handset.
- EXPIRED, validity period elapsed before delivery. Usually a handset that was off or out of coverage for the whole window.
- DELETED, removed from the queue before delivery.
- UNDELIV, undeliverable. Invalid number, barred subscriber, or rejected by the network.
- ACCEPTD, accepted by the network, outcome not yet known. An intermediate state, not a success.
- UNKNOWN, the network did not report an outcome.
- REJECTD, rejected, commonly by a filter.
Two of these are routinely misread. ACCEPTD is not delivery, if your reporting counts it as success your delivery rate is inflated. And a receipt with no final state ever arriving is itself a data point about the route.
Where receipts actually come from
This is the question that decides whether your delivery reporting means anything.
Relayed receipts originate at the destination network and are passed back through the chain. They describe what happened to the handset.
Generated receipts are produced by a platform in the path. Somewhere along the route, a system decides what the outcome probably was and manufactures a receipt saying so. The format is identical. Your system cannot tell the difference.
There are legitimate reasons a platform generates receipts, some routes genuinely return nothing, and a synthetic receipt keeps the interface consistent. The problem is when generation is used to make a route look better than it is, and when the buyer is not told which they are getting.
Ask the question directly, per route: are delivery receipts on this route relayed from the operator or generated by your platform? Note how it is answered as well as what the answer is.
How to tell you are being told a story
Five patterns, none of which requires special tooling to spot.
Receipts that arrive too fast. Real delivery to a handset involves network queuing and a handset that must be reachable. Receipts landing within a few hundred milliseconds of submission, consistently, are not describing a round trip to a phone.
Uniform timing. Real delivery latency has a distribution, a cluster around a typical value and a tail of slow ones. Receipts that all arrive at almost exactly the same interval after submission were produced by a timer.
A delivery rate that never moves. Genuine delivery varies by operator, by time of day, and by the quality of your recipient list. A number that sits at the same figure week after week regardless of what you send is a configuration, not a measurement.
Success for numbers that cannot receive. This is the decisive test. Submit to a handful of numbers you know are invalid, unallocated, or permanently switched off. A route reporting DELIVRD for those is manufacturing receipts, and every other number it has reported is now unreliable too.
Handset reality does not match. Send to phones you physically control and compare. The gap between reported and observed delivery is the most useful number you will get from a test.
Building reporting that survives this
Assume receipts may be imperfect and design around it:
- Count ACCEPTD separately from DELIVRD. Never merge them.
- Track the time between submit and final receipt, and keep the distribution, not just the average. Shape reveals more than mean.
- Report per operator, not per country. An aggregate hides a failing network.
- Keep a small set of controlled handsets per priority destination and check them periodically against what your reporting claims.
- Where the business consequence is real, one-time passwords especially, use a downstream signal such as code entry rate. That measures arrival regardless of what the receipt says.
The last one is worth the effort. A drop in OTP completion with no change in reported delivery is one of the clearest signals that a route has changed underneath you.
Related: improving delivery rates and testing a route properly.
Keep reading
Related insights
SMPP Error Codes Explained
What the common SMPP command_status values actually mean, which ones are your fault, which are the supplier's, and what to do about…
SMPP Throughput: Planning TPS and Binds
Why a bind rated at 100 TPS does not give you 100 messages per second, how the window size governs real throughput,…
SMPP vs HTTP API: Which Connection Should You Use for A2P SMS?
SMPP vs HTTP API: both reach the same routes. The choice is about session model, throughput and how your platform is built,…