Skip to main content

SMPP Protocol

What is SMPP

SMPP (Short Message Peer-to-Peer) is a binary protocol for reliable, persistent connections to send SMS at scale with delivery tracking. Choose SMPP when you need:

  • Persistent connections for high-volume messaging
  • Real-time delivery notifications via delivery receipts
  • Integration with existing telecom infrastructure

Connection Modes

SMPP supports three bind modes. The default allocation is 4 connections, which can be combined across modes.

ModeDirectionDescription
TX (Transmitter)Send onlyUsed exclusively for submitting messages. Cannot receive delivery receipts.
RX (Receiver)Receive onlyUsed exclusively for receiving delivery receipts and MO (Mobile Originated) messages.
TRX (Transceiver)Send & ReceiveBidirectional — can both submit messages and receive delivery receipts on the same connection. Recommended for most integrations.

:::tip Recommended Setup Use TRX mode for simplicity. A single transceiver connection handles both sending and receiving, reducing complexity and connection overhead. :::


Connection Details

ParameterValue
HOSTsmpp.agiletelecom.com
PORT2776 (TLS)
SYSTEM IDAccount username
PASSWORDAccount password
MODETX, RX, or TRX
Login-AddrRangeEmpty
Login-SystemTypeEmpty
Login-TON1
Login-NPI1
Login-DCS0

:::warning Keep-Alive Required Send an ENQUIRE_LINK packet at least every 30 seconds. If no response is received within 5 minutes, the connection will be closed. :::


Code Examples

Python (smpplib)

pip install smpplib
import smpplib.client
import smpplib.consts
import smpplib.gsm

client = smpplib.client.Client("smpp.agiletelecom.com", 2776, allow_unknown_opt_params=True)
client.connect()
client.bind_transceiver(system_id="YOUR_SYSTEM_ID", password="YOUR_PASSWORD")

# Register delivery receipt handler
client.set_message_received_handler(lambda pdu: print(f"DLR received: {pdu.short_message}"))

parts, encoding_flag, msg_type_flag = smpplib.gsm.make_parts("Hello from SMPP!")
for part in parts:
client.send_message(
source_addr_ton=smpplib.consts.SMPP_TON_ALNUM,
source_addr="MySender",
dest_addr_ton=smpplib.consts.SMPP_TON_INTL,
destination_addr="393401234567",
short_message=part,
data_coding=encoding_flag,
registered_delivery=True,
)
client.listen() # blocks, waiting for DLRs

Node.js (smpp)

npm install smpp
const smpp = require("smpp");

const session = smpp.connect(
{ url: "smpp://smpp.agiletelecom.com:2776", auto_enquire_link_period: 30000 },
() => {
session.bind_transceiver({ system_id: "YOUR_SYSTEM_ID", password: "YOUR_PASSWORD" }, (pdu) => {
if (pdu.command_status === 0) {
session.submit_sm({
source_addr: "MySender",
destination_addr: "393401234567",
short_message: "Hello from SMPP!",
registered_delivery: 1,
}, (submitPdu) => {
console.log("Message ID:", submitPdu.message_id);
});
}
});
}
);

session.on("deliver_sm", (pdu) => {
console.log("DLR:", pdu.short_message.message);
session.deliver_sm_resp({ sequence_number: pdu.sequence_number });
});

Java (CloudHopper)

<!-- pom.xml -->
<dependency>
<groupId>com.cloudhopper</groupId>
<artifactId>ch-smpp</artifactId>
<version>5.1.0</version>
</dependency>
import com.cloudhopper.smpp.*;
import com.cloudhopper.smpp.impl.DefaultSmppClient;
import com.cloudhopper.smpp.type.*;

DefaultSmppClient client = new DefaultSmppClient();
SmppSessionConfiguration config = new SmppSessionConfiguration();
config.setHost("smpp.agiletelecom.com");
config.setPort(2776);
config.setSystemId("YOUR_SYSTEM_ID");
config.setPassword("YOUR_PASSWORD");
config.setType(SmppBindType.TRANSCEIVER);

SmppSession session = client.bind(config, new DefaultSmppSessionHandler() {
@Override
public PduResponse firePduRequestReceived(PduRequest req) {
if (req instanceof DeliverSm) {
System.out.println("DLR: " + new String(((DeliverSm) req).getShortMessage()));
}
return req.createResponse();
}
});

SubmitSm submit = new SubmitSm();
submit.setSourceAddress(new Address((byte) 0x05, (byte) 0x00, "MySender"));
submit.setDestAddress(new Address((byte) 0x01, (byte) 0x01, "393401234567"));
submit.setShortMessage("Hello from SMPP!".getBytes());
submit.setRegisteredDelivery((byte) 1);
session.submit(submit, 10000);

PHP (php-smpp)

composer require alexandr-mironov/php-smpp
<?php
require 'vendor/autoload.php';

use smpp\{Client, SMPP, transport\Socket};

$transport = new Socket(["smpp.agiletelecom.com"], 2776);
$transport->setRecvTimeout(30000);
$smpp = new Client($transport);

$transport->open();
$smpp->bindTransceiver("YOUR_SYSTEM_ID", "YOUR_PASSWORD");

$message = "Hello from SMPP!";
$from = new \smpp\Address("MySender", SMPP::TON_ALPHANUMERIC);
$to = new \smpp\Address("393401234567", SMPP::TON_INTERNATIONAL, SMPP::NPI_E164);

$messageId = $smpp->sendSMS($from, $to, $message);
echo "Message ID: {$messageId}\n";

$smpp->close();

Go (go-smpp)

go get github.com/fiorix/go-smpp
package main

import (
"fmt"
"github.com/fiorix/go-smpp/smpp"
"github.com/fiorix/go-smpp/smpp/pdu/pdufield"
)

func main() {
tx := &smpp.Transceiver{
Addr: "smpp.agiletelecom.com:2776",
User: "YOUR_SYSTEM_ID",
Passwd: "YOUR_PASSWORD",
Handler: smpp.HandlerFunc(func(p smpp.Pdu) {
fmt.Println("DLR received:", p.FieldList())
}),
}
conn := tx.Bind()
defer tx.Close()

<-conn // wait for connection

sm, err := tx.Submit(&smpp.ShortMessage{
Src: "MySender",
Dst: "393401234567",
Text: pdufield.Raw("Hello from SMPP!"),
Register: pdufield.DeliverySetting(1),
})
if err != nil {
panic(err)
}
fmt.Println("Message ID:", sm.RespID())
}

C# (.NET)

dotnet add package JamaaTech.SMPP.Net.Lib
using JamaaTech.Smpp.Net.Client;
using JamaaTech.Smpp.Net.Lib;

var client = new SmppClient();
client.Properties.Host = "smpp.agiletelecom.com";
client.Properties.Port = 2776;
client.Properties.SystemID = "YOUR_SYSTEM_ID";
client.Properties.Password = "YOUR_PASSWORD";
client.Properties.DefaultEncoding = DataCoding.UCS2;

client.MessageDelivered += (sender, args) =>
Console.WriteLine($"DLR: {args.ShortMessage.MessageId}");

client.Start();

var message = new TextMessage
{
SourceAddress = "MySender",
DestinationAddress = "393401234567",
Text = "Hello from SMPP!",
RegisterDeliveryNotification = true
};
client.SendMessage(message);

Ruby (ruby-smpp)

gem install ruby-smpp
require 'smpp'

config = {
host: "smpp.agiletelecom.com",
port: 2776,
system_id: "YOUR_SYSTEM_ID",
password: "YOUR_PASSWORD",
system_type: "",
source_ton: 5,
source_npi: 0,
}

EventMachine.run do
trx = Smpp::Transceiver.new(config, self)

trx.send_mt("MySender", "393401234567", "Hello from SMPP!")

trx.on_delivery_report do |dr|
puts "DLR received: #{dr}"
end
end

Error Codes

Bind & Authentication Errors

CodeNameDescription
1ESME_RINVMSGLENInvalid message length
4ESME_RINVNUMRANGEInvalid number range
5ESME_RALYBNDAlready bound
8ESME_RSYSERRSystem error
10ESME_RINVSRCADRInvalid source address
11ESME_RINVDSTADRInvalid destination address
13ESME_RINVBNDSTSInvalid bind status
21ESME_RINVSCHEDInvalid scheduled delivery time
69ESME_RPROHIBITEDESME prohibited from using specified feature
88ESME_RTHROTTLEDThrottling error — too many requests
97ESME_RINVDCSInvalid data coding scheme
98ESME_RINVSRCADDRSUBUNITInvalid source address subunit
259VENDOR_SPECIFIC_259Vendor-specific authentication failure
1026VENDOR_SPECIFIC_1026Vendor-specific bind error

Delivery Status Errors

HLR Errors

CodeDescription
201Unknown subscriber
202Teleservice not provisioned
203Call barred
204Absent subscriber (HLR)
205Absent subscriber (MSC)
206Unidentified subscriber
207Roaming not allowed
208Illegal subscriber
209Bearer service not provisioned
210Not allowed for the subscriber
211Illegal equipment (IMEI blacklisted)
212Forwarding violation
213CUG reject
214Illegal SS operation
215SS not available
350HLR system failure

MSC Errors

CodeDescription
401SM delivery failure
402Message waiting list full
403System failure (MSC)
404Data missing
405Unexpected data value
406User busy
407Subscriber absent
408Delivery timeout
409SC congestion
410Facility not supported
411No SME delivery
412Message cancelled
413SC address invalid
414Illegal message
415Not SC subscriber
416Ussd busy
417Data coding error
418Message class not supported
419Duplicate message
550MSC system failure

SMSC Errors

CodeDescription
615Expired (message TTL exceeded)
616Deleted by operator
617Enqueued (still pending)
618Undeliverable

Other Errors

CodeDescription
806Number portability error
901Rejected by filter
902Blacklisted destination
903Content filtered
904Loop detected

Sender ID

TypeMax LengthExampleUse Case
Numeric16 characters+393401234567Two-way messaging, responses expected
Alphanumeric11 charactersMyBrandMarketing, notifications, one-way messaging

:::caution AGCOM Regulation In Italy, alphanumeric sender IDs are subject to AGCOM regulation 42/13/CIR. Your sender ID must be pre-registered and approved before use. Contact support for registration. :::


Message Tracking

Each submitted message receives a unique message ID in UUID format:

AGILE-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Delivery receipt timestamps follow the format:

yyMMddHHmmss

Example: 240315143022 = March 15, 2024 at 14:30:22


Security: IP Binding

:::warning IP Whitelisting All SMPP connections require IP whitelisting. Your source IP addresses must be registered with Agile Telecom before you can establish a connection. Contact support to add or update your whitelisted IPs.

Connections from non-whitelisted IPs will be silently dropped. :::


FAQ

TX vs RX vs TRX: which should I choose?

Use TRX (Transceiver) unless you have a specific reason to separate send and receive paths. TRX simplifies your integration by handling both directions on a single connection.

How do I receive delivery reports?

Bind in RX or TRX mode. Delivery reports arrive as DELIVER_SM PDUs with the esm_class field set to indicate a delivery receipt. Parse the short_message field to extract status, message ID, and timestamps.

What is the throughput limit?

The default throughput is 100 messages/second per account. If you need higher throughput, contact your account manager to discuss capacity upgrades.