Skip to content

Concept map· 6 connected terms

Short Message Peer-to-Peer Protocol(SMPP)

Also called: SMPP v3.4 · Short Message Peer-to-Peer · SMPP bind

In one line
The binary protocol that applications use to send and receive high volumes of SMS through an operator's message centre over a persistent connection.

Reviewed

What is SMPP?

The Short Message Peer-to-Peer protocol (SMPP) is the open, binary protocol that SMS applications and gateways — called ESMEs, External Short Messaging Entities — use to exchange messages with an operator's or aggregator's Short Message Service Centre (SMSC). Version 3.4, published in 1999, is still the version almost everyone runs; v5.0 exists but is rarely required. Unlike an HTTP API, SMPP keeps one long-lived TCP session open — on port 2775 by convention, often inside TLS or a VPN — and streams PDUs over it in both directions.

Every PDU starts with a 16-byte header — command_length, command_id, command_status and sequence_number — followed by the body. An ESME first binds as transmitter, receiver or transceiver (bind_transceiver) with its system_id and password. It sends messages with submit_sm and gets a submit_sm_resp carrying the SMSC's message_id; inbound messages and delivery reports arrive as deliver_sm, which it must acknowledge with deliver_sm_resp. enquire_link keeps the session alive, and unbind closes it cleanly.

SMPP's speed comes from windowing: an ESME may have several requests in flight — commonly ten or more — before waiting for responses, matching each response to its request by sequence number. Operators cap throughput per bind and answer ESME_RTHROTTLED (0x00000058) when you exceed it. Most businesses never touch SMPP directly: they call an SMS gateway's HTTP API and the gateway speaks SMPP to operators. In India, binds also carry DLT details — the principal entity ID and the DLT content template ID — in operator-defined optional TLV parameters, so the operator can scrub each message before delivery.

Key takeaways

  • SMPP is the binary protocol between an SMS application (an ESME) and an operator's SMSC, running over one long-lived TCP session.
  • Version 3.4 from 1999 is still the version almost everyone uses; port 2775 is the convention.
  • Messages go out as submit_sm; the SMSC's submit_sm_resp means accepted, not delivered.
  • Inbound messages and delivery reports arrive as deliver_sm and must be acknowledged with deliver_sm_resp straight away.
  • Throughput comes from windowing several requests in flight; exceeding the operator's rate returns ESME_RTHROTTLED (0x58).

Follow one OTP through an SMPP session

9 / 9
  • Your app (ESME)SMPP client
  • Operator SMSCstore and forward
  • Handsetcustomer's phone

Step 9 of 9Response

Operator SMSCYour app (ESME)

enquire_link_resp

A slow answer here is the first sign of trouble.

  • Request — solid arrow — a call that expects an answer
  • Response — dashed arrow — the answer coming back
  • Event — dotted arrow — something happened and is pushed out
  • Async — double head — fire-and-forget, nobody waits
Bind, submit, get a message_id, then watch the delivery report come back as deliver_sm. Step through each PDU and the field that matters in it.

Step 9 of 9: Operator SMSC to Your app (ESME) — enquire_link_resp. A slow answer here is the first sign of trouble.

Why does SMPP matter?

SMPP is the wire underneath most A2P SMS. If you run an SMS gateway, connect directly to an operator for OTP volume, or chase delivery reports that never reach your database, you are dealing with binds, windows, throttling and deliver_sm handling. Those details — sequence numbers, response timeouts, registered_delivery, data_coding — decide your real throughput, whether Hindi text arrives readable, whether long messages reassemble and whether every SMS delivery report gets matched to the message it describes.

SMPP in code

import smpp from "smpp";
const session = smpp.connect({ url: "smpp://smsc.example.net:2775", auto_enquire_link_period: 30000 });
session.bind_transceiver({ system_id: process.env.SMPP_SYSTEM_ID, password: process.env.SMPP_PASSWORD }, (bind) => {
if (bind.command_status !== 0) return console.error("bind failed", bind.command_status);
session.submit_sm({
source_addr: "ACMEBK", // DLT-registered header in India
source_addr_ton: 5,
source_addr_npi: 0,
destination_addr: "919812345678",
dest_addr_ton: 1,
dest_addr_npi: 1,
data_coding: 0, // 0 = SMSC default (GSM-7), 8 = UCS-2
registered_delivery: 1, // request a final delivery report
short_message: "482913 is your OTP for ACME Bank. Valid for 5 minutes. Do not share it. -ACME",
// India: add the DLT entity ID and content template ID as the
// optional TLVs your operator specifies; tag numbers differ by operator.
}, (resp) => {
if (resp.command_status === 0) saveMessageId(resp.message_id); // accepted, not delivered
else if (resp.command_status === 0x58) retryLater(); // ESME_RTHROTTLED
});
});
session.on("deliver_sm", (pdu) => {
session.send(pdu.response()); // acknowledge first, process later
const text = pdu.short_message.message;
if (pdu.esm_class & 0x04) queueReceipt(text); // "id:... stat:DELIVRD err:000 ..."
else queueInbound(pdu.source_addr, text); // a mobile-originated message
});

A transceiver bind that submits an OTP and handles both inbound messages and delivery reports on the same session.

How does SMPP work?

  1. Connect and bind

    Open TCP to the SMSC's host and port and send bind_transceiver (or separate transmitter and receiver binds) with the system_id and password the operator issued. A bind_transceiver_resp with command_status 0 (ESME_ROK) means you are bound.

  2. Submit with submit_sm

    Set source_addr (your sender), destination_addr, data_coding (0 for the SMSC default alphabet, usually GSM-7; 8 for UCS-2) and registered_delivery 1 to request a final receipt. short_message holds up to 254 octets; longer texts go as concatenated segments with a UDH (esm_class 0x40) or in the message_payload TLV.

  3. Window and match responses

    Keep a fixed number of requests in flight, match each submit_sm_resp by sequence_number, and store the returned message_id next to your own reference so the receipt can be matched later.

  4. Receive deliver_sm

    Mobile-originated messages and delivery reports both arrive as deliver_sm; receipts have esm_class 0x04 and a text body with id:, stat: and err: fields. Acknowledge each with deliver_sm_resp before doing anything slow.

  5. Keep alive and recover

    Send enquire_link every 30–60 seconds. On a timeout or dropped socket, rebind with backoff and resubmit only the messages that never got a submit_sm_resp, keyed by your own ID so customers do not get duplicates.

Key facts at a glance

SMPP: key facts and limits

Version in use
SMPP v3.4 (1999); v5.0 rarely required
Transport
Persistent TCP, port 2775 by convention
PDU header
16 bytes: length, command_id, status, sequence
Bind modes
Transmitter, receiver, transceiver
Message field
short_message up to 254 octets
Delivery reports
deliver_sm with esm_class 0x04
Throttling error
ESME_RTHROTTLED (0x00000058)
Keep-alive
enquire_link, typically every 30–60 s

Example: A direct bind for an OTP platform in Noida

An OTP platform in Noida runs two transceiver binds to each operator, one reserved for OTPs and one for bulk alerts, so a campaign never queues in front of a login code. Each bind keeps a window of ten requests and paces itself under the operator's per-bind cap; the rare ESME_RTHROTTLED goes back into a delay queue instead of failing the message. Every submit_sm carries the client's DLT entity and template IDs in the operator's TLVs. During launch the team found that 3% of receipts would not match: one operator returned message_id in hex in submit_sm_resp but in decimal inside the receipt text. Normalising both to one form fixed the gap, and the OTP-to-receipt match rate went to 100%.

Common wrong turns

Common mistakes with SMPP

  • Slow deliver_sm acknowledgements

    If you process a receipt before acknowledging it, the SMSC waits, retries or throttles the whole session. Send deliver_sm_resp immediately and do the database work from a queue.

  • Reading submit_sm_resp as delivered

    A successful submit_sm_resp only means the SMSC accepted the message. Delivery is known only when the receipt arrives with stat:DELIVRD — or never, if the phone stays off.

  • Ignoring the window

    Sending one PDU and waiting for its response caps you at a few messages per second; firing hundreds at once gets you throttled. Tune the window and pace to the operator's agreed rate per bind.

  • Wrong data_coding for Indian scripts

    Hindi or Tamil sent as data_coding 0 arrives as question marks. Use 8 (UCS-2) with UTF-16 big-endian text, and remember that drops one SMS to 70 characters.

  • No reconnect or duplicate protection

    Sessions drop. Rebind automatically with backoff, and resubmit only messages without a response, keyed by your own ID, so a reconnect never sends a customer the same OTP twice.

Good practice

Best practices for SMPP

  • Keep OTPs on their own bind so bulk traffic can never delay them.
  • Store your own ID beside the SMSC's message_id, and normalise hex and decimal forms before matching receipts.
  • Alert when enquire_link responses slow down — it is the earliest sign of a struggling SMSC.
  • Log command_status values by name (ESME_RINVDSTADR, ESME_RTHROTTLED) rather than raw numbers.

SMPP FAQs

What is the difference between SMPP and an HTTP SMS API?+
SMPP is a binary protocol over one persistent connection, built for high, steady volume; an HTTP API sends each message as a separate web request. Most businesses use HTTP and let their SMS gateway speak SMPP to operators.
Which SMPP version should I use?+
SMPP v3.4. It is the version operators and gateways almost universally support; v5.0 adds features, but few connections require it.
How fast can SMPP send messages?+
As fast as the operator allows per bind. Windowing lets you keep many requests in flight, but the agreed rate is the ceiling, and exceeding it returns ESME_RTHROTTLED until you slow down.
How do delivery reports arrive over SMPP?+
As deliver_sm PDUs with esm_class 0x04, sent only if you set registered_delivery when submitting. The body carries the message ID, a final state such as DELIVRD or UNDELIV and an operator error code.
Do I need SMPP to send SMS in India?+
No. Most businesses send through an SMS gateway's HTTP API; SMPP is for gateways and very high-volume senders connecting directly. Either way, every commercial message needs its DLT entity ID, header and content template ID.

See InfiQ pricing

Try it on the official WhatsApp Business API

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.