Volver al blog Calidad y confianza

Aceptado no significa entregado: cómo reconciliar estados de envío y DLR en A2P SMS

Un marco operativo para separar acuses de API y SMPP, aceptación de proveedores, estados de red y DLR finales sin convertir evidencia de transporte en una afirmación de recepción en el terminal.

Diagrama operativo de estados de envío y DLR para un mensaje A2P SMS

La pregunta operativa: ¿qué evidencia existe realmente después de enviar un SMS?

En A2P SMS, la palabra “enviado” puede describir hechos muy distintos. Puede significar que una aplicación creó una solicitud HTTP, que un ESME recibió submit_sm_resp con éxito, que un proveedor aceptó el tráfico, que un carrier upstream aceptó el mensaje o que se recibió un recibo de entrega. Estas señales no tienen el mismo alcance probatorio.

La regla práctica es sencilla: cada estado debe expresar la evidencia disponible, no la conclusión más favorable. Una respuesta satisfactoria de una API o un command_status correcto en submit_sm_resp confirma el resultado de esa interacción técnica. No confirma, por sí sola, que el mensaje haya alcanzado la red de destino ni que el abonado lo haya recibido en su terminal.

Esta distinción es especialmente importante en flujos OTP y transaccionales. Un sistema puede decidir reintentos, mostrar una pantalla al usuario o abrir una investigación operativa basándose en el estado equivocado si transforma “aceptado” en “entregado”. En marketing legítimo, el mismo error puede distorsionar métricas y decisiones de calidad de ruta.

Un DLR tampoco debe presentarse automáticamente como una verificación independiente de recepción física en el terminal. Es evidencia de estado comunicada a través de la cadena de mensajería. Su significado concreto depende del evento recibido, de los campos disponibles y de las garantías que ofrezca cada participante de la ruta.

  • Acuse de solicitud: evidencia de que una entidad procesó una solicitud técnica.
  • Aceptación de proveedor o carrier: evidencia de admisión para procesamiento posterior.
  • Estado intermedio: evidencia de cola, envío o tránsito, pero no necesariamente de resultado final.
  • DLR final: evidencia reportada de entrega o no entrega; debe conservarse junto con su fuente y carga original.
  • Silencio: ausencia de un evento observado, no prueba de entrega ni de fallo.
La pregunta operativa: ¿qué evidencia existe realmente después de enviar un SMS?

Las cuatro capas que no conviene mezclar

Una arquitectura de reconciliación robusta separa al menos cuatro capas. La primera es la aceptación local: la aplicación ha validado y enviado una solicitud, o la ha puesto en su propia cola. Es un hecho interno y no informa del resultado remoto.

La segunda es la aceptación remota. En SMPP, cada operación, salvo alert_notification, tiene una solicitud y una respuesta asociada. Si el originador no recibe la respuesta, debe asumir que el PDU no fue recibido por la entidad remota. Cuando recibe submit_sm_resp, command_status comunica el éxito o fallo de la solicitud submit_sm. Este acuse de transporte no es un DLR.

La tercera capa es el procesamiento de proveedor o red. En APIs HTTP, algunos proveedores exponen estados como accepted, queued, sending o sent. Estos pueden ser valiosos para localizar una cola, una fase de despacho o la aceptación por un carrier upstream, pero siguen siendo distintos de una confirmación de entrega.

La cuarta capa es el resultado comunicado. SMPP define estados como ENROUTE, DELIVERED, EXPIRED, UNDELIVERABLE, UNKNOWN, ACCEPTED y REJECTED. Esta variedad demuestra por qué un único campo booleano de éxito suele perder información crítica para operaciones, atención al cliente y análisis de calidad.

  • Capa 1: solicitud creada o aceptada por el sistema propio.
  • Capa 2: solicitud aceptada o rechazada por API, SMSC o proveedor.
  • Capa 3: procesamiento, cola, despacho o tránsito comunicado por la cadena de entrega.
  • Capa 4: resultado final o estado aún no resuelto comunicado mediante DLR, consulta o reconciliación.
Las cuatro capas que no conviene mezclar

Por qué un message_id no es una prueba de entrega

En SMPP, message_id es una referencia única asignada por el SMSC. La especificación lo describe como un valor opaco y dependiente de la implementación. Puede utilizarse como manejador en operaciones posteriores, por ejemplo query_sm, cancel_sm o replace_sm. Su existencia permite correlacionar operaciones; no acredita que el destinatario haya recibido el SMS.

Una integración no debería depender de un solo identificador. El proveedor puede generar su propio identificador, un SMSC puede devolver otro, y un DLR puede incluir receipted_message_id. Además, un mensaje de negocio puede requerir su propio identificador estable para relacionar el intento de envío con una transacción, una sesión OTP o un aviso transaccional legítimo.

La práctica recomendable es crear un identificador interno inmutable antes de enviar. Ese identificador debe enlazarse con cada intento técnico, sus referencias externas, los eventos recibidos y el estado derivado. Si se realizan reintentos, cada intento debe tener una identidad propia y conservar una relación explícita con el mensaje lógico original.

No use el número de destino, el texto completo del mensaje ni una marca temporal aproximada como clave principal de correlación. Son campos que pueden repetirse, cambiar por segmentación o presentar problemas de privacidad. Conserve únicamente los datos necesarios para la operación y aplique los controles de protección de datos que correspondan.

  • message_logical_id: identifica el mensaje o acción de negocio.
  • attempt_id: identifica cada intento técnico de envío.
  • provider_message_id: identificador devuelto por la API o proveedor.
  • smpp_message_id: identificador devuelto por submit_sm_resp cuando aplique.
  • receipted_message_id: referencia incluida en un DLR SMPP cuando aplique.
  • event_id o huella de evento: permite detectar duplicados sin borrar evidencia.
  • correlation_version: documenta reglas de correlación si cambian con el tiempo.

Modelo de máquina de estados para un SMS A2P

La máquina de estados debe distinguir eventos observados de conclusiones derivadas. Un evento es inmutable: por ejemplo, una respuesta HTTP aceptada, un submit_sm_resp exitoso, un deliver_sm con message_state o una consulta posterior. El estado actual es una proyección calculada a partir de todos los eventos correlacionados y de reglas explícitas.

Un modelo mínimo puede mantener estados internos de creación, envío local y espera de respuesta; estados de aceptación remota; estados transitorios de procesamiento; estados finales reportados; y un estado de reconciliación que indique si el caso está cerrado, pendiente de observación o requiere revisión. No es necesario obligar a todos los proveedores a encajar en una taxonomía más precisa que la evidencia disponible.

Para SMPP, trate el éxito de submit_sm_resp como “aceptado por la entidad SMPP”, no como “entregado”. Cuando lleguen recibos mediante deliver_sm, registre los valores disponibles, incluidos receipted_message_id, message_state y, si existe, network_error_code. Las notificaciones intermedias y los DLR pueden compartir este mecanismo de transporte.

Una proyección prudente puede mostrar “entregado reportado” cuando la evidencia normalizada sea DELIVERED o equivalente comunicado por el proveedor. Puede mostrar “no entregado reportado” para estados finales negativos como UNDELIVERABLE, EXPIRED o REJECTED, sin borrar el código original. Cuando solo existe un estado de tránsito, el resultado debe seguir siendo pendiente o en curso.

  • CREATED: se creó la intención de enviar, sin evidencia remota.
  • SUBMITTED_LOCAL: el sistema intentó transmitir la solicitud.
  • REMOTE_ACCEPTED: API, SMSC o proveedor aceptó la solicitud técnica.
  • IN_PROGRESS: existe evidencia de cola, despacho, tránsito o ENROUTE.
  • DELIVERED_REPORTED: se recibió un estado final positivo comunicado por la cadena de mensajería.
  • FAILED_REPORTED: se recibió un estado final negativo comunicado por la cadena de mensajería.
  • UNKNOWN_OR_UNRESOLVED: no existe evidencia final suficiente o se recibió UNKNOWN.
  • RECONCILIATION_PENDING: ha vencido una ventana operativa y el caso requiere consulta o clasificación de cierre.

Cómo normalizar HTTP, SMPP y DLR heterogéneos sin perder el dato original

La normalización sirve para operar de forma consistente, no para sustituir la semántica de origen. Guarde siempre el evento original junto con una representación normalizada. La carga original es necesaria para auditoría técnica, depuración de mapeos y adaptación cuando un proveedor añada o modifique campos en callbacks.

Para cada evento, registre como mínimo la fuente, el tipo de interfaz, el momento de recepción por su plataforma, el identificador externo disponible, el estado original, el estado normalizado, los códigos de error y la carga original protegida. Si el proveedor comunica una fecha originada en la red, almacénela separada de la hora de recepción: no representan necesariamente el mismo instante.

En SMPP, un deliver_sm puede transportar recibos de entrega. Para esos eventos, receipted_message_id y message_state son parámetros relevantes; network_error_code puede estar presente. No descarte un recibo porque falte un campo no garantizado por su integración: clasifíquelo con la evidencia disponible y márquelo para revisión si no puede correlacionarse con seguridad.

En HTTP, no suponga que todos los callbacks contienen los mismos campos ni que todos los estados existen para todos los canales o configuraciones. Mantenga una tabla de mapeo versionada por proveedor e interfaz. El mapeo debe transformar estados externos en categorías operativas amplias, preservando el valor externo literal.

  • No reemplace el estado original por el normalizado; conserve ambos.
  • Diferencie event_received_at de event_reported_at cuando el origen aporte fecha propia.
  • Registre códigos y textos de error sin convertirlos en diagnósticos no confirmados.
  • Versione las reglas de mapeo y precedencia.
  • Mantenga eventos no correlacionados en una cola de investigación en lugar de asociarlos por similitud débil.

Estados transitorios, finales y desconocidos: reglas explícitas

Clasifique los estados por su función operativa. Los transitorios indican que puede llegar información adicional; los finales comunican un resultado y, según sus reglas, cierran el intento; los desconocidos expresan falta de resolución y no deben convertirse en éxito o fracaso por conveniencia analítica.

SMPP enumera ENROUTE como estado de tránsito y DELIVERED, EXPIRED, DELETED, UNDELIVERABLE y REJECTED entre los estados que pueden tener carácter final según el contexto de la integración. UNKNOWN exige especial cautela: informa de que el estado no puede determinarse, no de que el mensaje haya fallado ni de que haya sido entregado.

Defina por adelantado qué estados cierran un intento y qué estados permiten más eventos. La regla no debe residir únicamente en código implícito. Debe estar documentada, ser comprobable y poder modificarse de forma controlada si cambia una interfaz o una relación operativa.

No convierta el paso del tiempo en una prueba de entrega. El tiempo solo puede activar una acción de reconciliación o un cierre administrativo con incertidumbre declarada. Si no hay DLR, el resultado correcto puede ser “sin estado final observado dentro de la ventana”, no “entregado”.

  • Transitorios: queued, sending, sent, ENROUTE o equivalentes comunicados por el origen.
  • Finales positivos reportados: DELIVERED o equivalente explícito del proveedor.
  • Finales negativos reportados: EXPIRED, UNDELIVERABLE, REJECTED o equivalentes explícitos.
  • Indeterminados: UNKNOWN, errores de correlación, ausencia de DLR y eventos incompletos.
  • Administrativos: cerrado por política operativa, siempre separado del resultado de entrega reportado.

DLR duplicados, fuera de orden o contradictorios

Los sistemas de mensajería deben diseñarse para eventos repetidos y orden imperfecto. SMPP indica que un SMSC debería responder en el mismo orden en que recibe solicitudes, pero no está obligado a hacerlo, y el ESME debe poder manejar respuestas fuera de secuencia. Esta precaución debe extenderse a callbacks HTTP, colas internas y procesos de reintento.

La respuesta no es sobrescribir el último dato recibido. Almacene cada evento como un hecho inmutable y derive el estado actual con una política de precedencia. La política debe considerar al menos la correlación, la categoría del estado, la hora informada por el origen cuando sea fiable, la hora de recepción, la fuente y la versión de la regla aplicada.

Un duplicado puede detectarse con un identificador de evento cuando exista, o mediante una huella calculada sobre campos estables del evento. Marcarlo como duplicado no implica eliminarlo: conserva valor para diagnóstico y demuestra que el sistema recibió más de una notificación.

Ante contradicciones, no invente una resolución. Por ejemplo, si aparece una señal final positiva y después un evento negativo que no puede explicarse por un intento distinto, preserve ambos, señale el caso como contradictorio y aplique una regla de presentación prudente. La vista operativa puede requerir revisión, mientras que la auditoría debe mostrar la secuencia completa.

  • No use “el último evento gana” como única regla.
  • Deduzca el estado por intento, no solo por mensaje lógico.
  • Aplique deduplicación idempotente antes de actualizar proyecciones.
  • Separe eventos tardíos de eventos inválidos: un evento tardío puede ser legítimo.
  • Escalone las contradicciones no resolubles a revisión operativa.
  • Registre la razón de cada cambio de estado derivado.

Qué hacer cuando no llega DLR

La ausencia de DLR no demuestra que el mensaje no haya sido procesado ni que no haya sido entregado. Puede indicar que no se recibió un callback, que la integración no lo solicitó o no lo soporta para ese caso, que el evento no pudo correlacionarse o que la cadena todavía no produjo un resultado observable.

Establezca ventanas de espera por caso de uso, proveedor e interfaz solo cuando disponga de una política operativa justificada. Evite convertir una recomendación de un proveedor en una regla universal. Como ejemplo de práctica documentada, Twilio recomienda consultar el recurso si no se ha recibido delivered o undelivered en 12 horas y reconciliar estados al menos diariamente; esa pauta debe adaptarse y validarse para cada integración, no asumirse como comportamiento de toda la industria.

Para OTP legítimos, el objetivo de producto suele requerir una decisión rápida, pero el estado de entrega no debe sustituirse por una suposición. Diseñe alternativas de autenticación apropiadas, controle reintentos para evitar duplicación y registre que el resultado quedó pendiente si no llega evidencia final. Para mensajes transaccionales, una ventana más amplia puede ser adecuada según la criticidad y las expectativas del proceso. Para marketing consentido, separe la medición de entrega reportada de métricas de interacción y no infiera lectura a partir del DLR.

El cierre operativo debe distinguir entre “resultado final reportado”, “resultado consultado”, “sin DLR observado” y “no correlacionable”. Esta precisión reduce disputas entre sistemas y evita que informes de calidad conviertan incertidumbre en una tasa de entrega artificial.

  • Verifique que la petición de DLR o callback esté configurada cuando la interfaz lo permita.
  • Compruebe la disponibilidad del endpoint receptor, autenticación y registro de errores de callback.
  • Programe consultas de reconciliación cuando el proveedor ofrezca una fuente de estado consultable.
  • Cierre con una etiqueta de incertidumbre si no existe evidencia final.
  • No atribuya silencio a un fallo de red, un fallo de proveedor o una entrega sin datos que lo sustenten.
  • Mida por separado DLR solicitados, DLR recibidos, DLR correlacionados y casos sin resolución final.
FAQ

Preguntas frecuentes

¿Un submit_sm_resp con command_status correcto confirma la entrega del SMS?

No. Confirma el resultado de la solicitud submit_sm ante la entidad SMPP remota. Es una aceptación técnica de la solicitud, no una confirmación de entrega al abonado.

¿Qué demuestra un message_id de SMPP?

Demuestra que el SMSC asignó una referencia para operaciones posteriores, como consulta, cancelación o reemplazo. Es útil para correlación, pero no es una prueba de entrega.

¿Qué estado debe mostrarse si no llega ningún DLR?

Un estado de incertidumbre, como “sin estado final observado” o “pendiente de reconciliación”, según su política. La ausencia de DLR no debe etiquetarse como entrega ni como fallo sin evidencia adicional.

¿Cómo se deben tratar DLR duplicados?

Registre cada evento de forma inmutable, detecte duplicados mediante un identificador o huella estable y haga idempotente la actualización del estado derivado. No elimine la evidencia original.

¿Puede llegar un DLR fuera de orden?

Sí. SMPP exige que una implementación pueda manejar respuestas fuera de secuencia. Por ello, el orden de llegada no debe ser la única base para decidir el estado final.

¿Un DLR delivered prueba de forma independiente que el usuario vio o leyó el mensaje?

No. Un DLR delivered es evidencia de entrega comunicada por la cadena de mensajería. No demuestra por sí mismo lectura, atención del usuario ni consentimiento.

Fuentes consultadas

  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