Anatomía de un informe de entrega SMPP
Cuando envía un SMS con registered_delivery en 1, el SMSC devuelve más tarde una PDU deliver_sm por un bind receptor o transceptor. El bit 0x04 de su esm_class indica que es un informe de entrega y no un mensaje entrante, y su short_message contiene la confirmación en texto. El anexo B de la especificación SMPP v3.4 presenta este formato como ejemplo, y casi todos los SMSC lo siguen: id:IIIIIIIIII sub:SSS dlvrd:DDD submit date:YYMMDDhhmm done date:YYMMDDhhmm stat:DDDDDDD err:E text:….
Como el anexo B es un ejemplo y no una regla estricta, las confirmaciones reales varían: claves en minúsculas, espacios de más, submit_date con guion bajo, fechas de 12 dígitos con segundos o sin campo text. Este decodificador acepta todas esas variantes e indica qué campos faltan.
- id: el identificador que el SMSC devolvió en submit_sm_resp. Sirve para asociar la confirmación con su mensaje. El ejemplo de la especificación muestra 10 caracteres, pero muchos SMSC usan identificadores más largos, a veces en hexadecimal.
- sub y dlvrd: el número de mensajes enviados y entregados, con 3 dígitos. Importan sobre todo en listas de distribución; para un SMS individual suelen ser 001 y 001 (o 000).
- submit date y done date: cuándo se envió el mensaje y cuándo alcanzó su estado final, según el reloj del SMSC.
- stat: el estado final o intermedio, como código de 7 letras, por ejemplo DELIVRD.
- err: un código de error de 3 caracteres, propio de la red o del SMSC; 000 significa sin error.
- text: los primeros 20 caracteres del mensaje original, a menudo truncados o vacíos.
- Algunos TLV opcionales repiten estos datos de forma más limpia: receipted_message_id (0x001E), message_state (0x0427) y network_error_code (0x0423).
Códigos stat de los DLR y su significado
SMPP v3.4 define ocho estados de mensaje. ENROUTE y ACCEPTD son intermedios; los demás son finales. Nuestra API normaliza todos los canales en seis estados de webhook (SUBMITTED, SENT, DELIVERED, READ, FAILED, REJECTED), y el decodificador muestra el equivalente más cercano para cada valor stat. Considere esa correspondencia orientativa: la regla exacta de su cuenta se confirma durante la incorporación.
- DELIVRD (message_state 2): entregado en el teléfono. Estado de webhook más cercano: DELIVERED.
- ACCEPTD (6): formalmente «leído manualmente por atención al cliente en nombre del abonado», pero la mayoría de los SMSC lo envían como confirmación intermedia de «aceptado por la red». Más cercano: SENT.
- ENROUTE (1): aún en tránsito, por ejemplo en cola para un reintento. Más cercano: SENT.
- UNDELIV (5): no entregable, por ejemplo un número inválido o inactivo. Más cercano: FAILED.
- EXPIRED (3): el periodo de validez terminó antes de alcanzar el teléfono, a menudo apagado o sin cobertura. Más cercano: FAILED.
- DELETED (4): eliminado antes de la entrega, por ejemplo con cancel_sm. Más cercano: FAILED.
- REJECTD (8): rechazado por la red o por un firewall de SMS, por ejemplo por un ID de remitente no registrado o contenido bloqueado. Más cercano: REJECTED.
- UNKNOWN (7): el SMSC no tiene un estado final. Trátelo como no confirmado, no como un fallo comprobado.
Códigos err: por qué no hay una lista universal
El campo err tiene tres caracteres y la especificación SMPP no define sus valores. 000 siempre significa sin error, pero los demás valores provienen del fabricante del SMSC, del operador o de un agregador intermedio. Algunos SMSC transmiten causas de error GSM MAP (por ejemplo, el error MAP 1 es abonado desconocido y el 27 es abonado ausente), mientras que otros usan su propia tabla.
Si la confirmación incluye el TLV network_error_code (0x0423), es más fiable: su primer octeto indica el tipo de red (3 significa GSM) y los dos siguientes, el código de error. Una confirmación DELIVRD con err distinto de cero es incoherente y conviene comentarla con su proveedor; el decodificador la señala.
Errores command_status frente a informes de entrega
SMPP informa de los problemas en dos momentos. El command_status de submit_sm_resp llega en milisegundos e indica si el SMSC aceptó su solicitud; 0x00000000 (ESME_ROK) significa aceptado, no entregado. El informe de entrega llega entre segundos y días después y trae el resultado final.
Los valores command_status se definen en la sección 5.1.3 de SMPP v3.4. Los más habituales en producción son 0x00000058 ESME_RTHROTTLED (superó los mensajes por segundo acordados: reduzca el ritmo y reintente con backoff exponencial), 0x00000014 ESME_RMSGQFUL (cola llena: espere), 0x0000000A y 0x0000000B (dirección de origen o de destino inválida) y 0x0000000D o 0x0000000E (fallo del bind o contraseña incorrecta). Los valores 0x00000400 a 0x000004FF están reservados para errores propios del fabricante del SMSC: consulte a su proveedor.
Fechas, zonas horarias y latencia de entrega
Las fechas de las confirmaciones usan AAMMDDhhmm, y muchos SMSC añaden los segundos (AAMMDDhhmmss). No se indica zona horaria: la hora es la del reloj del SMSC, normalmente UTC. El decodificador muestra las fechas tal como aparecen y calcula la latencia como done date menos submit date, lo que no depende de la zona horaria mientras ambas vengan del mismo reloj.
La latencia es una buena señal de calidad. Un OTP a un teléfono disponible suele completarse en segundos. Latencias largas seguidas de EXPIRED apuntan a teléfonos apagados o en itinerancia, y una done date anterior a la submit date indica relojes desajustados. Las fechas al minuto no permiten medir latencias inferiores a un minuto, así que son preferibles los SMSC que envían segundos.
Procesar confirmaciones de forma fiable en producción
Responda a cada deliver_sm con deliver_sm_resp, aunque su procesamiento falle; de lo contrario, el SMSC lo reenvía y puede limitar el bind. Guarde la confirmación en bruto y procésela de forma asíncrona e idempotente por identificador de mensaje, porque las confirmaciones pueden llegar duplicadas o desordenadas: un ENROUTE tardío nunca debe sobrescribir un DELIVRD.
Si prefiere no analizar confirmaciones, nuestra API REST de SMS entrega la misma información como estados de webhook normalizados, y las confirmaciones perdidas pueden reenviarse con POST /sms/resendDlr. Hay binds SMPP sobre TLS disponibles para grandes volúmenes y revendedores.
