BroadNet
Protocols Intermediate

SMPP Fundamentals

The binary protocol behind high-volume SMS: bind types, submit_sm, PDUs, the transmit window, delivery receipts, and keepalives.

5 lessons3 min readStandards-based · self-paced
DiagramAn SMPP session between your platform and BroadNet
Your platform (ESME)
BroadNet SMSC
One persistent TCP/TLS connection
  1. bind_transceiverOpen and authenticate the session
  2. bind_transceiver_respSession accepted
  3. submit_smSend a message
  4. submit_sm_respAccepted, message ID returned
  5. deliver_smDelivery receipt or inbound message
  6. deliver_sm_respAcknowledged
  7. enquire_linkKeepalive while idle
Lesson 01

What SMPP is

SMPP — Short Message Peer-to-Peer — is the binary, session-based protocol that aggregators and operators expose for high-throughput A2P messaging. Where a REST API is convenient and stateless, SMPP is a persistent TCP connection built for volume and low latency.

An ESME (External Short Messaging Entity — your side) opens a session to the SMSC and exchanges PDUs (Protocol Data Units). The protocol is compact and efficient, which is why it remains the backbone for large senders even as REST covers everyday use.

The most widely deployed version is SMPP v3.4; v5.0 adds congestion-state signalling and enhanced parameters but is backward compatible. You should never assume a v5.0 feature is available until the bind response confirms the negotiated version.

Lesson 02

Bind types and sessions

Before sending anything, an ESME must bind — authenticate and declare a role. A transmitter bind sends messages only; a receiver bind receives mobile-originated messages and delivery receipts only; a transceiver bind does both over one connection.

Transceiver is usually preferred because it halves the number of connections and simplifies correlation of DLRs to submissions. The number of concurrent binds and the per-bind messages-per-second (TPS) are provisioned by the provider and must be honoured.

The bind carries a system_id, password, system_type, and address_range. A mismatched address_range silently breaks MO and DLR routing on receiver binds — a classic integration bug that produces no errors, only missing traffic.

Lesson 03

PDUs and the submit_sm

Every SMPP interaction is a PDU with a command header (length, command id, status, sequence number) and a body. The workhorse is submit_sm, which carries a single outbound message.

Two field pairs decide addressing: source_addr with its TON/NPI (type-of-number / numbering-plan-indicator) and dest_addr with its own. An alphanumeric sender ID uses TON 5; an international MSISDN uses TON 1, NPI 1. Get these wrong and the sender ID renders incorrectly or the message is rejected.

The data_coding field sets the encoding — GSM 7-bit (0), 8-bit (4), or UCS-2 (8) for Unicode. Long messages are concatenated either with UDH bytes in the body or with the SAR optional parameters (sar_msg_ref_num, sar_total_segments, sar_segment_seqnum); pick one method and stay consistent, because routes differ on which they accept.

Lesson 04

The window, throttling, and keepalives

SMPP uses a transmit window: a cap on the number of submit_sm PDUs sent before their responses come back. Exceeding the window, or the provisioned TPS, triggers ESME_RTHROTTLED (0x58). The correct response is to back off with jitter, not to hot-loop retries.

To detect a half-open TCP connection, each side sends enquire_link on an idle timer (commonly every 30–60 seconds) and expects an enquire_link_resp. A missed response means the session is dead and should be re-bound with exponential backoff.

Graceful shutdown uses unbind / unbind_resp. Unexpected disconnects should trigger a reconnect with backoff and idempotent retries, so a dropped window doesn't cause double submissions and double billing.

Lesson 05

Delivery receipts over SMPP

Delivery receipts arrive as deliver_sm PDUs. The receipt text in the short_message field carries id, sub, dlvrd, submit date, done date, the terminal stat (DELIVRD, UNDELIV, EXPIRED, REJECTD), and an err code.

Correlate the DLR to your original submission using the provider's message_id, not the receipt text alone — message_id may be returned in hex on submit_resp but decimal in the DLR, so normalise both formats.

Always answer with a deliver_sm_resp. An unacknowledged DLR is re-sent by the SMSC and can stall the receive window, so acknowledge promptly even if your downstream processing is asynchronous.

Key takeaways
  • SMPP is a persistent binary session for high-volume A2P; v3.4 is the common baseline, v5.0 is backward compatible.
  • Bind as transmitter, receiver, or transceiver; transceiver halves connections and eases DLR correlation.
  • TON/NPI decide sender-ID rendering and data_coding decides encoding — both are easy to get wrong.
  • Respect the window and TPS, back off on ESME_RTHROTTLED, and keep the session alive with enquire_link.
Put it into practice

Build with what you just learned.

Talk to a real engineer about your use case, or open the developer docs and send a message across the routes this course describes.

Why learn from BroadNet
  • Since2003
  • Countries200+
  • Operator links1,000+