Anatomie d'un accusé de réception SMPP
Quand vous envoyez un SMS avec registered_delivery à 1, le SMSC renvoie plus tard un PDU deliver_sm sur un bind récepteur ou émetteur-récepteur. Le bit 0x04 de son esm_class indique qu'il s'agit d'un accusé et non d'un message entrant, et son short_message contient un accusé texte. L'annexe B de la spécification SMPP v3.4 donne ce format en exemple, et presque tous les SMSC le suivent : id:IIIIIIIIII sub:SSS dlvrd:DDD submit date:YYMMDDhhmm done date:YYMMDDhhmm stat:DDDDDDD err:E text:….
L'annexe B étant un exemple et non une règle stricte, les accusés réels varient : clés en minuscules, espaces en trop, submit_date avec un tiret bas, dates à 12 chiffres avec secondes ou champ text absent. Ce décodeur accepte toutes ces variantes et signale les champs manquants.
- id : l'identifiant renvoyé par le SMSC dans submit_sm_resp. Il permet de rattacher l'accusé à votre message. L'exemple de la spécification montre 10 caractères, mais beaucoup de SMSC utilisent des identifiants plus longs, parfois en hexadécimal.
- sub et dlvrd : le nombre de messages soumis et délivrés, sur 3 chiffres. Ils servent surtout pour les listes de diffusion ; pour un SMS unique, on voit généralement 001 et 001 (ou 000).
- submit date et done date : la date de soumission et celle de l'état final, selon l'horloge du SMSC.
- stat : l'état final ou intermédiaire, sous forme de code de 7 lettres comme DELIVRD.
- err : un code d'erreur de 3 caractères, propre au réseau ou au SMSC ; 000 signifie aucune erreur.
- text : les 20 premiers caractères du message d'origine, souvent tronqués ou vides.
- Des TLV optionnels peuvent reprendre ces données sous une forme plus propre : receipted_message_id (0x001E), message_state (0x0427) et network_error_code (0x0423).
Les codes stat des DLR et leur signification
SMPP v3.4 définit huit états de message. ENROUTE et ACCEPTD sont intermédiaires, les autres sont finaux. Notre API normalise tous les canaux en six statuts webhook (SUBMITTED, SENT, DELIVERED, READ, FAILED, REJECTED), et le décodeur affiche la correspondance la plus proche pour chaque valeur stat. Cette correspondance est indicative : la règle exacte de votre compte est confirmée lors de la mise en service.
- DELIVRD (message_state 2) : délivré sur le téléphone. Statut webhook le plus proche : DELIVERED.
- ACCEPTD (6) : formellement « lu manuellement par le service client pour le compte de l'abonné », mais la plupart des SMSC l'envoient comme accusé intermédiaire « accepté par le réseau ». Le plus proche : SENT.
- ENROUTE (1) : toujours en transit, par exemple en attente d'une nouvelle tentative. Le plus proche : SENT.
- UNDELIV (5) : non distribuable, par exemple un numéro invalide ou inactif. Le plus proche : FAILED.
- EXPIRED (3) : la période de validité a expiré avant que le téléphone soit joignable, souvent éteint ou hors couverture. Le plus proche : FAILED.
- DELETED (4) : supprimé avant la livraison, par exemple via cancel_sm. Le plus proche : FAILED.
- REJECTD (8) : refusé par le réseau ou un pare-feu SMS, par exemple un identifiant d'expéditeur (Sender ID) non enregistré ou un contenu bloqué. Le plus proche : REJECTED.
- UNKNOWN (7) : le SMSC n'a pas d'état final. Considérez-le comme non confirmé, pas comme un échec avéré.
Codes err : pourquoi il n'existe pas de liste universelle
Le champ err fait trois caractères et la spécification SMPP n'en définit pas les valeurs. 000 signifie toujours aucune erreur, mais les autres valeurs viennent de l'éditeur du SMSC, de l'opérateur ou d'un agrégateur intermédiaire. Certains SMSC transmettent les causes d'erreur GSM MAP (par exemple, l'erreur MAP 1 correspond à un abonné inconnu et la 27 à un abonné absent), d'autres utilisent leur propre table.
Si l'accusé contient le TLV network_error_code (0x0423), il est plus fiable : son premier octet indique le type de réseau (3 pour GSM) et les deux suivants le code d'erreur. Un accusé DELIVRD avec un err non nul est incohérent et mérite d'être signalé à votre fournisseur ; le décodeur le met en évidence.
Erreurs command_status et accusés de réception
SMPP signale les problèmes à deux moments. Le command_status de submit_sm_resp arrive en quelques millisecondes et indique si le SMSC a accepté votre requête ; 0x00000000 (ESME_ROK) signifie accepté, pas délivré. L'accusé de réception arrive de quelques secondes à quelques jours plus tard et donne le résultat final.
Les valeurs command_status sont définies à la section 5.1.3 de SMPP v3.4. Les plus fréquentes en production sont 0x00000058 ESME_RTHROTTLED (vous dépassez le débit convenu : ralentissez et réessayez avec un backoff exponentiel), 0x00000014 ESME_RMSGQFUL (file pleine : temporisez), 0x0000000A et 0x0000000B (adresse source ou destination invalide) et 0x0000000D ou 0x0000000E (échec du bind ou mot de passe erroné). Les valeurs 0x00000400 à 0x000004FF sont réservées aux erreurs propres à l'éditeur du SMSC : interrogez votre fournisseur.
Dates, fuseaux horaires et délai de livraison
Les dates des accusés suivent le format AAMMJJhhmm, et beaucoup de SMSC ajoutent les secondes (AAMMJJhhmmss). Aucun fuseau horaire n'est indiqué : l'heure est celle de l'horloge du SMSC, généralement UTC. Le décodeur affiche les dates telles quelles et calcule le délai comme done date moins submit date, ce qui reste juste tant que les deux proviennent de la même horloge.
Le délai est un bon indicateur de qualité. Un OTP vers un téléphone joignable aboutit généralement en quelques secondes. De longs délais suivis d'EXPIRED signalent des téléphones éteints ou en itinérance, et une done date antérieure à la submit date indique des horloges désaccordées. Des dates à la minute ne mesurent pas un délai inférieur à la minute : privilégiez les SMSC qui envoient les secondes.
Traiter les accusés de façon fiable en production
Répondez à chaque deliver_sm par un deliver_sm_resp, même si votre traitement échoue, sinon le SMSC le renvoie et peut brider le bind. Stockez l'accusé brut, puis traitez-le de façon asynchrone et idempotente par identifiant de message, car les accusés peuvent arriver en double ou dans le désordre : un ENROUTE tardif ne doit jamais écraser un DELIVRD.
Si vous préférez ne pas analyser d'accusés, notre API SMS REST fournit les mêmes informations sous forme de statuts webhook normalisés, et les accusés manqués peuvent être renvoyés avec POST /sms/resendDlr. Des binds SMPP sur TLS sont disponibles pour les gros volumes et les revendeurs.
