What Actually Happens When You Send an SMS
Most developers who work with SMS APIs never need to understand what happens underneath. The API call goes in, a message ID comes out, a delivery report arrives eventually. Black box. Works.
But when delivery rates are lower than expected, or DLRs look suspicious, or latency is higher than it should be — understanding the infrastructure becomes essential for debugging.
This is the technical overview I wish existed when I first started working with carrier-grade SMS systems.
The Cast of Characters
SMSC (Short Message Service Centre): The server that stores, routes, and forwards SMS messages. Every mobile carrier has an SMSC. When you send an SMS, it goes through at least one SMSC before reaching the destination handset.
HLR (Home Location Register): A database maintained by each mobile carrier containing subscriber information — which network a number belongs to, whether it's active, what its current routing status is. HLR lookup is how a gateway knows which SMSC to route a message to.
SMS Gateway: The system that accepts message submissions (via SMPP or HTTP), routes them toward the correct destination SMSC, and processes delivery reports coming back.
MNO (Mobile Network Operator): The carrier — EE, O2, Vodafone, Three in the UK. They own the SMSCs and the subscriber databases.
Aggregator: A company (like BulkSMSRates) that has interconnects with multiple MNOs and provides a single API endpoint for customers, abstracting away the per-carrier complexity.
The Message Journey: Step by Step
Here's what happens from your API call to phone vibration.
Step 1: Your application submits the message
You POST to https://app.bulksmsrates.com/v2/messages with the recipient number, sender ID, and message body. Or you submit a submit_sm PDU over your SMPP connection.
The gateway acknowledges immediately with a message ID. This is NOT a delivery confirmation — it's a receipt that the message has been accepted for routing. The SMSC submit response is typically sent within 10–50ms.
Step 2: The gateway performs number lookup
Before routing, the gateway looks up the number in HLR to determine:
- •Which MNO the number belongs to (important for multi-network countries)
- •Whether the number is currently active
- •Whether the number has been ported (moved from original carrier to another)
For UK numbers, this means checking the number portability database to route to the current carrier, not the original allocation carrier.
If HLR returns "unknown subscriber" — the number doesn't exist or is inactive — the gateway immediately returns an UNDELIV DLR with the appropriate error code.
Step 3: Route selection
The gateway selects which interconnect to use based on:
- •Destination MNO (e.g., EE in the UK)
- •Sender type (alphanumeric sender ID, shortcode, virtual number)
- •Route quality settings (direct, tier-1, or fallback routes)
- •Message content (some routes have content restrictions)
This is where grey routes vs direct routes matter. A direct route means: your gateway → destination MNO's SMSC. The message goes directly to the carrier that serves the recipient. A grey route means: your gateway → some intermediate SMSC → eventually maybe the destination SMSC, via unofficial commercial agreements.
Step 4: SMPP submission to destination SMSC
The gateway connects to the destination SMSC (or an intermediate SMSC) over SMPP and submits a submit_sm PDU. This PDU contains:
- •Source address (sender ID)
- •Destination address (recipient number in E.164)
- •Message encoding (GSM-7 or UCS-2 Unicode)
- •Message body
- •Service type
- •Priority flag
- •Validity period (TTL for the SMSC to retry before giving up)
The SMSC acknowledges with a submit_sm_resp PDU containing a message ID internal to the SMSC. This is a different ID from the one your gateway gave you — the gateway maintains a mapping between its IDs and the SMSC's internal IDs.
Step 5: SMSC stores and routes to handset
The SMSC checks if the handset is reachable. If the handset is online and registered on the network, the SMSC forwards the message immediately via the signalling path to the base station to the handset. This takes milliseconds.
If the handset is offline (switched off, no coverage), the SMSC stores the message and marks it as "pending delivery." It will retry periodically (typically every few minutes) until either:
- •The handset comes back online and the message is delivered
- •The validity period expires (in which case the message is discarded)
Step 6: Delivery confirmation flows back
When the handset receives the message and the delivery report is enabled, the network sends a delivery confirmation back up the chain:
Handset → base station → destination SMSC → (via SMPP deliver_sm) → gateway → (via webhook or SMPP deliver_sm) → your application
The deliver_sm PDU contains the message ID (which the gateway maps back to your original message ID), the status (DELIVRD, UNDELIV, EXPIRED, REJECTD), an error code if applicable, and the timestamp.
This end-to-end DLR flow is what distinguishes a genuine delivery confirmation from a "soft" DLR. Some providers give you a DLR when their own SMSC accepts the message (Step 4), not when the destination SMSC confirms delivery (Step 6). These are useless for understanding actual delivery.
PDU Anatomy
For those working with SMPP directly, here's what a basic submit_sm PDU looks like in structured form:
submit_sm {
service_type: ""
source_addr_ton: 5 // Alphanumeric
source_addr_npi: 0
source_addr: "MYSHOP"
dest_addr_ton: 1 // International
dest_addr_npi: 1
destination_addr: "+447912345678"
esm_class: 0 // Default
protocol_id: 0
priority_flag: 0
schedule_delivery_time: ""
validity_period: "000000230000000R" // 23 hours relative
registered_delivery: 1 // Request DLR
replace_if_present_flag: 0
data_coding: 0 // GSM-7
sm_default_msg_id: 0
short_message: "Your order has shipped"
}
The data_coding field is important: 0 = GSM-7 (160 chars/segment), 8 = UCS-2 Unicode (70 chars/segment). Most SMS libraries handle this automatically, but mismatches between the declared encoding and actual content cause garbled messages.
Why Architecture Matters for Delivery Rate
Direct vs grey routes:
A direct route is a commercial agreement between your aggregator and the destination MNO. The aggregator connects directly to the MNO's SMSC. Grey routes use unofficial paths — an aggregator connects to a third-party SMSC that has somehow obtained access to the destination network's infrastructure, often in violation of the MNO's commercial terms.
Grey routes have lower cost (which is why they're used) but:
- •MNOs actively work to detect and block them
- •DLRs are unreliable (often generated by the grey SMSC, not the destination)
- •Delivery rates fluctuate as MNOs update their blocking lists
- •No SLA from the destination network
For high-stakes transactional SMS (OTPs, authentication codes, financial alerts), grey routes are unacceptable. For low-importance promotional sends where cost is paramount, they might be a tolerable trade-off. Most serious providers don't use them because the customer experience damage from unexplained delivery failures isn't worth the cost saving.
SMSC connection pooling:
High-volume senders need multiple SMPP connections (binds) to the same SMSC to increase throughput. A single SMPP connection has a window (the number of outstanding unacknowledged PDUs) that limits throughput. With a window of 10 and 5ms round-trip per PDU, you max out at 2,000 messages/second per connection.
The BulkSMSRates SMPP gateway supports multiple simultaneous binds, allowing throughput well beyond what a single connection can achieve.
Message validity and retry:
If a message arrives at the destination SMSC and the handset is offline, the SMSC queues it. The validity period tells the SMSC how long to keep trying. The default is often 48–72 hours.
For an OTP that expires in 5 minutes, a 48-hour validity period means the subscriber might receive it 2 days later — after the code has expired — which is confusing and creates support issues. Always set validity periods appropriate to your use case via the validity_period field.
What This Means for Your Implementation
If you're building a reliable SMS system:
- 1.Use genuine DLR data. Make sure your provider sends end-to-end confirmed delivery status, not intermediate acceptance ACKs.
- 2.Handle DLR states properly. DELIVRD, UNDELIV, EXPIRED, REJECTD, ENROUTE each mean different things. Build your DLR processing to handle each appropriately.
- 3.Set validity periods correctly. Different message types need different validity windows.
- 4.Monitor per-destination delivery rates. A single aggregate delivery rate hides per-network issues. If one carrier starts filtering your sender ID, you'll see it in per-network breakdowns before it shows up in aggregates.
- 5.Use direct routes for critical messages. The cost difference between grey and direct routes is typically 10–20%. For anything where delivery matters — OTPs, appointment reminders, payment alerts — direct routes are worth it.