Protocollo SMPP
Cos'è SMPP
SMPP (Short Message Peer-to-Peer) è un protocollo binario per connessioni affidabili e persistenti, progettato per l'invio di SMS su larga scala con tracciamento della consegna. Scegli SMPP quando hai bisogno di:
- Connessioni persistenti per messaggistica ad alto volume
- Notifiche di consegna in tempo reale tramite ricevute di consegna
- Integrazione con infrastrutture di telecomunicazione esistenti
Modalità di connessione
SMPP supporta tre modalità di bind. L'allocazione predefinita è di 4 connessioni, che possono essere combinate tra le diverse modalità.
| Modalità | Direzione | Descrizione |
|---|---|---|
| TX (Transmitter) | Solo invio | Utilizzata esclusivamente per l'invio di messaggi. Non può ricevere ricevute di consegna. |
| RX (Receiver) | Solo ricezione | Utilizzata esclusivamente per ricevere ricevute di consegna e messaggi MO (Mobile Originated). |
| TRX (Transceiver) | Invio e ricezione | Bidirezionale: può sia inviare messaggi che ricevere ricevute di consegna sulla stessa connessione. Consigliata per la maggior parte delle integrazioni. |
:::tip Configurazione consigliata Utilizza la modalità TRX per semplicità. Una singola connessione transceiver gestisce sia l'invio che la ricezione, riducendo la complessità e il sovraccarico delle connessioni. :::
Dettagli di connessione
| Parametro | Valore |
|---|---|
| HOST | smpp.agiletelecom.com |
| PORT | 2776 (TLS) |
| SYSTEM ID | Username dell'account |
| PASSWORD | Password dell'account |
| MODE | TX, RX o TRX |
| Login-AddrRange | Vuoto |
| Login-SystemType | Vuoto |
| Login-TON | 1 |
| Login-NPI | 1 |
| Login-DCS | 0 |
:::warning Keep-Alive obbligatorio
Invia un pacchetto ENQUIRE_LINK almeno ogni 30 secondi. Se non viene ricevuta alcuna risposta entro 5 minuti, la connessione verrà chiusa.
:::
Esempi di codice
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
Codici di errore
Errori di bind e autenticazione
| Codice | Nome | Descrizione |
|---|---|---|
| 1 | ESME_RINVMSGLEN | Lunghezza del messaggio non valida |
| 4 | ESME_RINVNUMRANGE | Intervallo numerico non valido |
| 5 | ESME_RALYBND | Già connesso (bound) |
| 8 | ESME_RSYSERR | Errore di sistema |
| 10 | ESME_RINVSRCADR | Indirizzo sorgente non valido |
| 11 | ESME_RINVDSTADR | Indirizzo destinazione non valido |
| 13 | ESME_RINVBNDSTS | Stato di bind non valido |
| 21 | ESME_RINVSCHED | Orario di consegna programmata non valido |
| 69 | ESME_RPROHIBITED | ESME non autorizzato a utilizzare la funzionalità specificata |
| 88 | ESME_RTHROTTLED | Errore di throttling: troppe richieste |
| 97 | ESME_RINVDCS | Schema di codifica dati non valido |
| 98 | ESME_RINVSRCADDRSUBUNIT | Sottounità indirizzo sorgente non valida |
| 259 | VENDOR_SPECIFIC_259 | Errore di autenticazione specifico del vendor |
| 1026 | VENDOR_SPECIFIC_1026 | Errore di bind specifico del vendor |
Errori di stato della consegna
Errori HLR
| Codice | Descrizione |
|---|---|
| 201 | Abbonato sconosciuto |
| 202 | Teleservizio non provisionato |
| 203 | Chiamata bloccata |
| 204 | Abbonato assente (HLR) |
| 205 | Abbonato assente (MSC) |
| 206 | Abbonato non identificato |
| 207 | Roaming non consentito |
| 208 | Abbonato illegale |
| 209 | Servizio bearer non provisionato |
| 210 | Non consentito per l'abbonato |
| 211 | Apparecchiatura illegale (IMEI in blacklist) |
| 212 | Violazione di inoltro |
| 213 | Rifiuto CUG |
| 214 | Operazione SS illegale |
| 215 | SS non disponibile |
| 350 | Errore di sistema HLR |
Errori MSC
| Codice | Descrizione |
|---|---|
| 401 | Consegna SM fallita |
| 402 | Lista di attesa messaggi piena |
| 403 | Errore di sistema (MSC) |
| 404 | Dati mancanti |
| 405 | Valore dati imprevisto |
| 406 | Utente occupato |
| 407 | Abbonato assente |
| 408 | Timeout di consegna |
| 409 | Congestione SC |
| 410 | Funzionalità non supportata |
| 411 | Nessuna consegna SME |
| 412 | Messaggio annullato |
| 413 | Indirizzo SC non valido |
| 414 | Messaggio illegale |
| 415 | Non abbonato SC |
| 416 | USSD occupato |
| 417 | Errore di codifica dati |
| 418 | Classe messaggio non supportata |
| 419 | Messaggio duplicato |
| 550 | Errore di sistema MSC |
Errori SMSC
| Codice | Descrizione |
|---|---|
| 615 | Scaduto (TTL del messaggio superato) |
| 616 | Eliminato dall'operatore |
| 617 | In coda (ancora in attesa) |
| 618 | Non recapitabile |
Altri errori
| Codice | Descrizione |
|---|---|
| 806 | Errore di portabilità del numero |
| 901 | Rifiutato dal filtro |
| 902 | Destinazione in blacklist |
| 903 | Contenuto filtrato |
| 904 | Loop rilevato |
Sender ID
| Tipo | Lunghezza massima | Esempio | Caso d'uso |
|---|---|---|---|
| Numerico | 16 caratteri | +393401234567 | Messaggistica bidirezionale, risposte attese |
| Alfanumerico | 11 caratteri | MyBrand | Marketing, notifiche, messaggistica unidirezionale |
:::caution Regolamento AGCOM In Italia, i sender ID alfanumerici sono soggetti al regolamento AGCOM 42/13/CIR. Il tuo sender ID deve essere pre-registrato e approvato prima dell'utilizzo. Contatta il supporto per la registrazione. :::
Tracciamento dei messaggi
Ogni messaggio inviato riceve un message ID univoco in formato UUID:
AGILE-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
I timestamp delle ricevute di consegna seguono il formato:
yyMMddHHmmss
Esempio: 240315143022 = 15 marzo 2024 alle 14:30:22
Sicurezza: IP Binding
:::warning Whitelist IP Tutte le connessioni SMPP richiedono la whitelist degli IP. I tuoi indirizzi IP sorgente devono essere registrati presso Agile Telecom prima di poter stabilire una connessione. Contatta il supporto per aggiungere o aggiornare i tuoi IP autorizzati.
Le connessioni da IP non autorizzati verranno silenziosamente rifiutate. :::
FAQ
TX vs RX vs TRX: quale scegliere?
Utilizza TRX (Transceiver) a meno che tu non abbia un motivo specifico per separare i percorsi di invio e ricezione. TRX semplifica la tua integrazione gestendo entrambe le direzioni su una singola connessione.
Come ricevo i report di consegna?
Effettua il bind in modalità RX o TRX. I report di consegna arrivano come PDU DELIVER_SM con il campo esm_class impostato per indicare una ricevuta di consegna. Analizza il campo short_message per estrarre lo stato, il message ID e i timestamp.
Qual è il limite di throughput?
Il throughput predefinito è di 100 messaggi/secondo per account. Se hai bisogno di un throughput più elevato, contatta il tuo account manager per discutere gli aggiornamenti di capacità.