Torna al blog Qualità e fiducia

Accettato non significa consegnato: come riconciliare stati di invio e DLR negli SMS A2P

Un framework operativo per separare conferme API e SMPP, accettazione del provider, stati di rete e DLR finali, senza trasformare l’evidenza di trasporto in un’affermazione di ricezione sul terminale.

Diagramma operativo degli stati di invio e DLR per un messaggio SMS A2P

La domanda operativa: quale evidenza esiste davvero dopo l’invio di un SMS?

Negli SMS A2P, la parola “inviato” può descrivere fatti molto diversi. Può significare che un’applicazione ha creato una richiesta HTTP, che un ESME ha ricevuto con successo un submit_sm_resp, che un provider ha accettato il traffico, che un carrier upstream ha accettato il messaggio oppure che è stata ricevuta una ricevuta di consegna. Questi segnali non hanno lo stesso valore probatorio.

La regola pratica è semplice: ogni stato deve esprimere l’evidenza disponibile, non la conclusione più favorevole. Una risposta positiva di un’API o un command_status corretto in submit_sm_resp conferma l’esito di quella specifica interazione tecnica. Non conferma, da sola, che il messaggio abbia raggiunto la rete di destinazione né che l’abbonato lo abbia ricevuto sul proprio terminale.

Questa distinzione è particolarmente importante nei flussi OTP e transazionali. Un sistema può decidere di effettuare nuovi tentativi, mostrare una schermata all’utente o avviare un’indagine operativa sulla base dello stato errato se trasforma “accettato” in “consegnato”. Nel marketing legittimo, lo stesso errore può distorcere metriche e decisioni sulla qualità della rotta.

Neppure un DLR deve essere presentato automaticamente come una verifica indipendente della ricezione fisica sul terminale. È evidenza di stato comunicata attraverso la catena di messaggistica. Il suo significato concreto dipende dall’evento ricevuto, dai campi disponibili e dalle garanzie offerte da ogni partecipante della rotta.

  • Conferma della richiesta: evidenza che un’entità ha elaborato una richiesta tecnica.
  • Accettazione da parte di provider o carrier: evidenza di ammissione per l’elaborazione successiva.
  • Stato intermedio: evidenza di accodamento, invio o transito, ma non necessariamente di un esito finale.
  • DLR finale: evidenza riportata di consegna o mancata consegna; deve essere conservata insieme alla fonte e al payload originale.
  • Silenzio: assenza di un evento osservato, non prova di consegna né di errore.
La domanda operativa: quale evidenza esiste davvero dopo l’invio di un SMS?

I quattro livelli da non confondere

Un’architettura di riconciliazione robusta separa almeno quattro livelli. Il primo è l’accettazione locale: l’applicazione ha convalidato e inviato una richiesta, oppure l’ha inserita nella propria coda. È un fatto interno e non informa sull’esito remoto.

Il secondo è l’accettazione remota. In SMPP, ogni operazione, salvo alert_notification, ha una richiesta e una risposta associate. Se l’originatore non riceve la risposta, deve presumere che il PDU non sia stato ricevuto dall’entità remota. Quando riceve submit_sm_resp, command_status comunica il successo o il fallimento della richiesta submit_sm. Questa conferma di trasporto non è un DLR.

Il terzo livello è l’elaborazione da parte del provider o della rete. Nelle API HTTP, alcuni provider espongono stati come accepted, queued, sending o sent. Possono essere utili per individuare una coda, una fase di dispatch o l’accettazione da parte di un carrier upstream, ma restano diversi da una conferma di consegna.

Il quarto livello è l’esito comunicato. SMPP definisce stati quali ENROUTE, DELIVERED, EXPIRED, UNDELIVERABLE, UNKNOWN, ACCEPTED e REJECTED. Questa varietà dimostra perché un unico campo booleano di successo spesso perde informazioni critiche per le operazioni, il supporto clienti e l’analisi della qualità.

  • Livello 1: richiesta creata o accettata dal sistema interno.
  • Livello 2: richiesta accettata o rifiutata da API, SMSC o provider.
  • Livello 3: elaborazione, accodamento, dispatch o transito comunicati dalla catena di consegna.
  • Livello 4: esito finale o stato ancora irrisolto comunicato tramite DLR, interrogazione o riconciliazione.
I quattro livelli da non confondere

Perché un message_id non è una prova di consegna

In SMPP, message_id è un riferimento univoco assegnato dall’SMSC. La specifica lo descrive come un valore opaco e dipendente dall’implementazione. Può essere usato come handle nelle operazioni successive, ad esempio query_sm, cancel_sm o replace_sm. La sua esistenza consente di correlare operazioni; non dimostra che il destinatario abbia ricevuto l’SMS.

Un’integrazione non dovrebbe dipendere da un solo identificatore. Il provider può generare un proprio identificatore, un SMSC può restituirne un altro e un DLR può includere receipted_message_id. Inoltre, un messaggio di business può richiedere un proprio identificatore stabile per collegare il tentativo di invio a una transazione, una sessione OTP o un avviso transazionale legittimo.

La pratica consigliata è creare un identificatore interno immutabile prima dell’invio. Tale identificatore deve collegarsi a ogni tentativo tecnico, ai relativi riferimenti esterni, agli eventi ricevuti e allo stato derivato. Se vengono effettuati nuovi tentativi, ciascun tentativo deve avere una propria identità e mantenere una relazione esplicita con il messaggio logico originale.

Non usare il numero di destinazione, il testo completo del messaggio o un timestamp approssimativo come chiave primaria di correlazione. Sono campi che possono ripetersi, cambiare a causa della segmentazione o presentare problemi di privacy. Conservare soltanto i dati necessari per l’operatività e applicare i controlli di protezione dei dati pertinenti.

  • message_logical_id: identifica il messaggio o l’azione di business.
  • attempt_id: identifica ogni tentativo tecnico di invio.
  • provider_message_id: identificatore restituito dall’API o dal provider.
  • smpp_message_id: identificatore restituito da submit_sm_resp, quando applicabile.
  • receipted_message_id: riferimento incluso in un DLR SMPP, quando applicabile.
  • event_id o impronta dell’evento: consente di rilevare duplicati senza eliminare l’evidenza.
  • correlation_version: documenta le regole di correlazione se cambiano nel tempo.

Modello di macchina a stati per un SMS A2P

La macchina a stati deve distinguere gli eventi osservati dalle conclusioni derivate. Un evento è immutabile: ad esempio, una risposta HTTP di accettazione, un submit_sm_resp riuscito, un deliver_sm con message_state o un’interrogazione successiva. Lo stato corrente è una proiezione calcolata a partire da tutti gli eventi correlati e da regole esplicite.

Un modello minimo può mantenere stati interni di creazione, invio locale e attesa di risposta; stati di accettazione remota; stati transitori di elaborazione; stati finali riportati; e uno stato di riconciliazione che indichi se il caso è chiuso, in attesa di osservazione o richiede revisione. Non è necessario forzare tutti i provider in una tassonomia più precisa dell’evidenza disponibile.

Per SMPP, trattare il successo di submit_sm_resp come “accettato dall’entità SMPP”, non come “consegnato”. Quando arrivano ricevute tramite deliver_sm, registrare i valori disponibili, inclusi receipted_message_id, message_state e, se presente, network_error_code. Le notifiche intermedie e i DLR possono condividere questo meccanismo di trasporto.

Una proiezione prudente può mostrare “consegnato riportato” quando l’evidenza normalizzata è DELIVERED o un equivalente comunicato dal provider. Può mostrare “mancata consegna riportata” per stati finali negativi come UNDELIVERABLE, EXPIRED o REJECTED, senza eliminare il codice originale. Quando esiste soltanto uno stato di transito, l’esito deve rimanere in attesa o in corso.

  • CREATED: l’intenzione di inviare è stata creata, senza evidenza remota.
  • SUBMITTED_LOCAL: il sistema ha tentato di trasmettere la richiesta.
  • REMOTE_ACCEPTED: API, SMSC o provider ha accettato la richiesta tecnica.
  • IN_PROGRESS: esiste evidenza di accodamento, dispatch, transito o ENROUTE.
  • DELIVERED_REPORTED: è stato ricevuto uno stato finale positivo comunicato dalla catena di messaggistica.
  • FAILED_REPORTED: è stato ricevuto uno stato finale negativo comunicato dalla catena di messaggistica.
  • UNKNOWN_OR_UNRESOLVED: non esiste evidenza finale sufficiente oppure è stato ricevuto UNKNOWN.
  • RECONCILIATION_PENDING: è scaduta una finestra operativa e il caso richiede un’interrogazione o una classificazione di chiusura.

Come normalizzare HTTP, SMPP e DLR eterogenei senza perdere il dato originale

La normalizzazione serve a operare in modo coerente, non a sostituire la semantica di origine. Conservare sempre l’evento originale insieme a una rappresentazione normalizzata. Il payload originale è necessario per l’audit tecnico, il debug delle mappature e l’adattamento quando un provider aggiunge o modifica campi nei callback.

Per ogni evento, registrare almeno la fonte, il tipo di interfaccia, il momento di ricezione da parte della piattaforma, l’identificatore esterno disponibile, lo stato originale, lo stato normalizzato, i codici di errore e il payload originale protetto. Se il provider comunica una data originata nella rete, memorizzarla separatamente dall’orario di ricezione: non rappresentano necessariamente lo stesso istante.

In SMPP, un deliver_sm può trasportare ricevute di consegna. Per tali eventi, receipted_message_id e message_state sono parametri rilevanti; network_error_code può essere presente. Non scartare una ricevuta perché manca un campo non garantito dalla propria integrazione: classificarla in base all’evidenza disponibile e contrassegnarla per revisione se non può essere correlata con certezza.

In HTTP, non presumere che tutti i callback contengano gli stessi campi né che tutti gli stati esistano per tutti i canali o le configurazioni. Mantenere una tabella di mappatura versionata per provider e interfaccia. La mappatura deve trasformare gli stati esterni in categorie operative ampie, preservando il valore esterno letterale.

  • Non sostituire lo stato originale con quello normalizzato; conservarli entrambi.
  • Distinguere event_received_at da event_reported_at quando la fonte fornisce la propria data.
  • Registrare codici e testi di errore senza trasformarli in diagnosi non confermate.
  • Versionare le regole di mappatura e precedenza.
  • Mantenere gli eventi non correlati in una coda di indagine invece di associarli per somiglianza debole.

Stati transitori, finali e sconosciuti: regole esplicite

Classificare gli stati in base alla loro funzione operativa. Gli stati transitori indicano che possono arrivare ulteriori informazioni; gli stati finali comunicano un esito e, secondo le proprie regole, chiudono il tentativo; gli stati sconosciuti esprimono una mancanza di risoluzione e non devono essere trasformati in successo o fallimento per convenienza analitica.

SMPP elenca ENROUTE come stato di transito e DELIVERED, EXPIRED, DELETED, UNDELIVERABLE e REJECTED tra gli stati che possono avere carattere finale, a seconda del contesto dell’integrazione. UNKNOWN richiede particolare cautela: indica che lo stato non può essere determinato, non che il messaggio sia fallito o sia stato consegnato.

Definire in anticipo quali stati chiudono un tentativo e quali consentono ulteriori eventi. La regola non deve risiedere soltanto nel codice implicito. Deve essere documentata, verificabile e modificabile in modo controllato se cambia un’interfaccia o una relazione operativa.

Non trasformare il trascorrere del tempo in una prova di consegna. Il tempo può soltanto attivare un’azione di riconciliazione o una chiusura amministrativa con incertezza dichiarata. Se non esiste un DLR, l’esito corretto può essere “nessuno stato finale osservato entro la finestra”, non “consegnato”.

  • Transitori: queued, sending, sent, ENROUTE o equivalenti comunicati dalla fonte.
  • Finali positivi riportati: DELIVERED o equivalente esplicito del provider.
  • Finali negativi riportati: EXPIRED, UNDELIVERABLE, REJECTED o equivalenti espliciti.
  • Indeterminati: UNKNOWN, errori di correlazione, assenza di DLR ed eventi incompleti.
  • Amministrativi: chiuso in base alla politica operativa, sempre separato dall’esito di consegna riportato.

DLR duplicati, fuori ordine o contraddittori

I sistemi di messaggistica devono essere progettati per eventi ripetuti e un ordine imperfetto. SMPP indica che un SMSC dovrebbe rispondere nello stesso ordine in cui riceve le richieste, ma non è obbligato a farlo, e l’ESME deve poter gestire risposte fuori sequenza. Questa precauzione deve estendersi ai callback HTTP, alle code interne e ai processi di nuovo tentativo.

La risposta non è sovrascrivere l’ultimo dato ricevuto. Memorizzare ogni evento come fatto immutabile e derivare lo stato corrente con una politica di precedenza. La politica deve considerare almeno la correlazione, la categoria dello stato, l’orario riportato dalla fonte quando affidabile, l’orario di ricezione, la fonte e la versione della regola applicata.

Un duplicato può essere rilevato tramite un identificatore di evento, quando disponibile, oppure mediante un’impronta calcolata sui campi stabili dell’evento. Contrassegnarlo come duplicato non implica eliminarlo: conserva valore per la diagnosi e dimostra che il sistema ha ricevuto più di una notifica.

In presenza di contraddizioni, non inventare una risoluzione. Ad esempio, se compare un segnale finale positivo e successivamente un evento negativo che non può essere spiegato da un tentativo diverso, conservare entrambi, segnalare il caso come contraddittorio e applicare una regola di visualizzazione prudente. La vista operativa può richiedere revisione, mentre l’audit deve mostrare la sequenza completa.

  • Non usare “vince l’ultimo evento” come unica regola.
  • Derivare lo stato per tentativo, non solo per messaggio logico.
  • Applicare la deduplicazione idempotente prima di aggiornare le proiezioni.
  • Separare gli eventi tardivi da quelli non validi: un evento tardivo può essere legittimo.
  • Escalare le contraddizioni non risolvibili a revisione operativa.
  • Registrare il motivo di ogni modifica dello stato derivato.

Cosa fare quando non arriva un DLR

L’assenza di un DLR non dimostra che il messaggio non sia stato elaborato né che non sia stato consegnato. Può indicare che non è stato ricevuto un callback, che l’integrazione non lo ha richiesto o non lo supporta per quel caso, che l’evento non ha potuto essere correlato oppure che la catena non ha ancora prodotto un esito osservabile.

Stabilire finestre di attesa per caso d’uso, provider e interfaccia soltanto quando si dispone di una politica operativa giustificata. Evitare di trasformare una raccomandazione di un provider in una regola universale. Come esempio di pratica documentata, Twilio raccomanda di interrogare la risorsa se non sono stati ricevuti delivered o undelivered entro 12 ore e di riconciliare gli stati almeno ogni giorno; tale indicazione deve essere adattata e convalidata per ogni integrazione, non assunta come comportamento dell’intero settore.

Per OTP legittimi, l’obiettivo di prodotto richiede spesso una decisione rapida, ma lo stato di consegna non deve essere sostituito da una supposizione. Progettare alternative di autenticazione appropriate, controllare i nuovi tentativi per evitare duplicazioni e registrare che l’esito è rimasto in sospeso se non arriva evidenza finale. Per i messaggi transazionali, può essere adatta una finestra più ampia a seconda della criticità e delle aspettative del processo. Per il marketing basato sul consenso, separare la misurazione della consegna riportata dalle metriche di interazione e non inferire la lettura dal DLR.

La chiusura operativa deve distinguere tra “esito finale riportato”, “esito interrogato”, “nessun DLR osservato” e “non correlabile”. Questa precisione riduce le controversie tra sistemi e impedisce ai report di qualità di trasformare l’incertezza in un tasso di consegna artificiale.

  • Verificare che la richiesta di DLR o callback sia configurata quando l’interfaccia lo consente.
  • Controllare la disponibilità dell’endpoint ricevente, l’autenticazione e la registrazione degli errori di callback.
  • Programmare interrogazioni di riconciliazione quando il provider offre una fonte di stato interrogabile.
  • Chiudere con un’etichetta di incertezza se non esiste evidenza finale.
  • Non attribuire il silenzio a un errore di rete, a un errore del provider o a una consegna senza dati che lo confermino.
  • Misurare separatamente DLR richiesti, DLR ricevuti, DLR correlati e casi senza esito finale.
FAQ

Domande frequenti

Un submit_sm_resp con command_status corretto conferma la consegna dell’SMS?

No. Conferma l’esito della richiesta submit_sm presso l’entità SMPP remota. È un’accettazione tecnica della richiesta, non una conferma della consegna all’abbonato.

Cosa dimostra un message_id SMPP?

Dimostra che l’SMSC ha assegnato un riferimento per operazioni successive, come interrogazione, annullamento o sostituzione. È utile per la correlazione, ma non è una prova di consegna.

Quale stato dovrebbe essere mostrato se non arriva alcun DLR?

Uno stato di incertezza, come “nessuno stato finale osservato” o “in attesa di riconciliazione”, secondo la propria politica. L’assenza di DLR non deve essere etichettata come consegna o errore senza ulteriore evidenza.

Come devono essere gestiti i DLR duplicati?

Registrare ogni evento in modo immutabile, rilevare i duplicati tramite un identificatore o un’impronta stabile e rendere idempotente l’aggiornamento dello stato derivato. Non eliminare l’evidenza originale.

Un DLR può arrivare fuori ordine?

Sì. SMPP richiede che un’implementazione possa gestire risposte fuori sequenza. Per questo, l’ordine di arrivo non deve essere l’unica base per decidere lo stato finale.

Un DLR delivered prova in modo indipendente che l’utente ha visto o letto il messaggio?

No. Un DLR delivered è evidenza di consegna comunicata dalla catena di messaggistica. Non dimostra da solo lettura, attenzione dell’utente né consenso.

Fonti consultate

  1. SMPP Protocol Specification v3.4, Issue 1.2SMPP Developers Forum
  2. Outbound Message Status in Status CallbacksTwilio Documentation
  3. Messages resourceTwilio Documentation
  4. Best Practices for Messaging Delivery Status LoggingTwilio Documentation