Full SMPP 3.4 spec
Complete protocol implementation - all PDU types, optional TLVs, and the full command/response cycle.
TLS 1.3 transport, configurable throughput windows, and full operator DLR pass-through - on the same direct routes powering our REST API. One host, three bind modes, 50+ countries.
← TLS 1.3 handshake complete (AES-256-GCM-SHA384) → bind_transceiver system_id = "your_system_id" password = "••••••••" interface_version = 0x34 ← bind_transceiver_resp command_status = 0x00000000 ESME_ROK system_id = "ESMSAFRICA" → submit_sm source_addr = "eSMSCo" destination_addr = "+254712345678" data_coding = 0x00 GSM-7 registered_delivery = 0x01 request DLR short_message = "Your OTP is 482910. Valid 5 min." ← submit_sm_resp command_status = 0x00000000 ESME_ROK message_id = "8A2F91C4" ── 4.2 s later ───────────────────────────── ← deliver_sm DLR from operator SMSC short_message = "id:8A2F91C4 sub:001 dlvrd:001 submit date:2605030812 done date:2605030812 stat:DELIVRD err:000" → deliver_sm_resp command_status = 0x00000000 ESME_ROK → enquire_link keepalive every 30 s ← enquire_link_resp
Point your SMPP client at smpp.esmsafrica.io:2775. TLS 1.3 is enforced - connections without TLS are refused before the SMPP handshake.
Send and receive on a single bind. Handles both submit_sm and deliver_sm - the right choice for most integrations.
Submit messages only. Use when you want to isolate outbound sending from inbound DLR reception.
Receive inbound messages and DLRs only. Pair with a TX bind for split-architecture deployments.
Complete protocol implementation - all PDU types, optional TLVs, and the full command/response cycle.
All connections are encrypted. TLS 1.3 is enforced at the transport level - older versions are rejected at the handshake.
Throughput windows are configurable per system_id. High-volume aggregators can negotiate dedicated burst capacity.
Full UDH support for multi-part messages. UCS-2 for Unicode (data_coding=8). Binary payloads (data_coding=4) pass through unchanged.
Operator delivery receipts arrive verbatim via deliver_sm. Error codes and timestamps from the carrier SMSC are preserved.
Two endpoints across separate regions with automatic failover. Bind loss triggers reconnect; enquire_link keeps idle connections alive.
Every bind lands on our routing infrastructure, passes through our operator agreements, and delivers to the handset. No grey routes, no wholesale aggregators.
← DLR returns the same path: operator deliver_sm → eSMS routing layer → your bind → deliver_sm PDU
Any SMPP 3.4 library with TLS support works. These snippets use the most popular open-source clients - swap in your credentials.
# pip install smpplib import ssl, smpplib.client, smpplib.gsm, smpplib.consts # TLS 1.3 context (required) ctx = ssl.create_default_context() client = smpplib.client.Client( 'smpp.esmsafrica.io', 2775, allow_unknown_opt_params=True, timeout=30, ) client.connect(ssl=ctx) client.bind_transceiver( system_id='YOUR_SYSTEM_ID', password='YOUR_PASSWORD', ) # Register DLR handler (deliver_sm callbacks) def dlr_received(pdu): msg = pdu.short_message if isinstance(msg, bytes): msg = msg.decode('latin-1') print(f"DLR: {msg}") client.set_message_received_handler(dlr_received) # Send a message (GSM-7, with DLR) parts, enc, msg_type = smpplib.gsm.make_parts('Your OTP is 482910') for part in parts: resp = client.send_message( source_addr_ton=smpplib.consts.SMPP_TON_ALNUM, source_addr_npi=smpplib.consts.SMPP_NPI_UNK, source_addr='eSMSCo', dest_addr_ton=smpplib.consts.SMPP_TON_INTL, dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN, destination_addr='+254712345678', data_coding=enc, esm_class=msg_type, short_message=part, registered_delivery=1, ) print(f"Queued: {resp.message_id}") # Block and process inbound PDUs client.listen()
Node.js, Go, and Java examples in the SMPP quickstart guide →
We provision bind credentials and validate the connection on a test SMSC before you go live.