Back to blog SMS Operations

Transactional SMS Retries: When to Retry, Stop, or Review a Send

A transactional SMS retry policy must make decisions based on technical evidence, the usefulness window, and duplicate risk. This framework separates transport retries from business resends and defines when to stop.

Operational decision diagram for transactional SMS retries

The problem: a technical failure does not always justify another SMS

A transactional SMS retry policy establishes what to do when a send result is inconclusive or indicates a problem. Its goal is not to maximize the number of attempts, but to maximize the likelihood that a still-useful message arrives without creating duplicates, recipient confusion, or unnecessary traffic.

The starting point is to distinguish the available technical states. Acceptance of a request by a platform, subsequent acceptance by a carrier, and a reported delivery are different events. For example, a status equivalent to “sent” may mean that an upstream carrier accepted the message, not that it reached the handset.

Therefore, an integration timeout, a delayed response, or an incomplete status update should not automatically become a new SMS. Before retrying, the system must determine whether the first message may have been accepted or may still be in progress.

  • Do not use the immediate absence of a DLR as proof of a definitive failure.
  • Do not equate provider or carrier acceptance with confirmed receipt on the phone.
  • Do not treat every error state as a transient cause.
  • Do not prioritize retry volume over message usefulness and recipient experience.
The problem: a technical failure does not always justify another SMS

Separate three decisions: transport, business, and closure

A robust design separates the logical message from the technical attempt. The logical message is the business intent, such as confirming an operation, notifying a change, or delivering a one-time code. A technical attempt is a specific execution to transport that intent through an available connection, provider, or route.

A transport retry means attempting the technical execution of the same logical message again under constrained rules. It may be appropriate when there is a documented, potentially transient cause, the message remains useful, and the risk that an active send already exists is controlled.

A business resend is different: it creates a new communication for the recipient. It should be governed by product and experience rules, not by an isolated network error. For example, requesting a new OTP may invalidate the previous one, change the expiry, and require suppression of repeated requests.

Definitive closure marks that no further attempts will be made for that logical unit. It may result from expiry, evidence of definitive rejection, exhaustion of the attempt limit, high duplicate risk, or the need for operational review.

  • Logical message: the notification the business intends to communicate.
  • Technical attempt: an individual execution to deliver that logical message.
  • Transport retry: a new technical execution under the same intent.
  • Business resend: a new notification, potentially with new content or validity.
  • Closure: an explicit decision not to continue sending.
Separate three decisions: transport, business, and closure

Define the usefulness window first

The first condition of any policy should be the usefulness window: the period during which receiving the SMS still has value for the recipient and the process. An event alert, an operation confirmation, and an OTP may have very different windows. There is no universal duration that works for every use case.

The technical expiry configured in a messaging platform may limit how long a message remains queued before it is no longer sent. However, that setting does not replace the business decision. The sending system must enforce an expiry date or time consistent with the message’s purpose.

When the window has ended, the prudent action is to stop retries. Delivering an alert late may be useless; delivering an OTP late may cause confusion or lead the user to enter a code that is no longer valid.

  • Define an expiry for each message type before configuring waits and attempt counts.
  • Assess usefulness from the recipient’s perspective, not only from route availability.
  • Prevent an attempt from starting if there is no longer enough time for the message to serve its purpose.
  • Record expiry as a closure reason, not as a generic technical failure.

Classify the result before making a decision

An operational policy needs its own stable, auditable classification. It should not depend solely on the status labels of a specific integration. The goal is to translate the available outcome into a decision: stop, wait, retry in a controlled way, or review.

Definitive rejections are outcomes for which the available evidence indicates that retrying immediately will not resolve the issue. A potentially transient failure is one where the documented cause allows consideration of another attempt within the usefulness window. Acceptance without a final result requires waiting and reconciliation before sending another copy. An uncertain state requires maximum caution because the first message may have progressed even though the application did not receive conclusive confirmation.

A status equivalent to “undelivered” provides evidence that the message was not delivered, but it does not determine a single cause. There may be multiple reasons, including carrier content filtering or handset availability. Therefore, it does not automatically make retrying the correct action either.

  • Definitive rejection: stop and classify for review or correction.
  • Potentially transient failure: evaluate a limited retry.
  • Acceptance without a final result: wait through a reconciliation window.
  • Uncertain state: do not duplicate without checking references, late events, and expiry.
  • Reported delivery: close the technical flow without assuming more evidence than is available.

Do not confuse DLRs, acceptance, and receipt on the handset

Delivery receipts and status callbacks are valuable operational elements, but they must be interpreted according to what they actually prove. A platform may report that it accepted the request; a sending status may indicate acceptance by an upstream carrier; and a DLR may communicate a later outcome. These are different operational signals.

Independent receipt on the handset should not be inferred merely because a provider accepted a request or because there is a sending status toward the network. Even when there is a reported delivery status, the policy should describe it accurately as evidence reported by the available messaging chain, not as absolute proof of user reading or action.

This distinction is essential to avoid two opposite errors: retrying a message that probably already progressed, or declaring business success when only a transport status is known.

  • Preserve the original meaning of every received status.
  • Model transport success, reported delivery, and business success separately.
  • Avoid using a DLR as proof of consent, identity, number ownership, or message reading.
  • Define which evidence is sufficient to close each type of flow.

Operational criteria for authorizing a retry

A retry should require cumulative conditions, not a single error signal. At a minimum, assess the documented cause, elapsed time, message criticality, duplication risk, and restrictions applicable to the destination or sender.

The cause must be interpretable. If there is no clear cause or a provider reference is still pending, treat the case as uncertain and prioritize reconciliation. Elapsed time must be compared with the usefulness window and a waiting period designed to allow late updates. Criticality may justify faster review, but it does not eliminate the risk of duplicating a notification.

It is also worth considering whether the content, sender identifier, or destination may be related to the outcome. A delivery error does not by itself prove which of these elements caused the problem. If there is a persistent pattern, the appropriate response is to review the configuration, content, events, and connectivity rather than retry indefinitely.

  • Is the available cause documented and consistent with transient behavior?
  • Is the message still within its usefulness window?
  • Is there a provider identifier or pending update that could confirm the status?
  • Could the recipient receive two copies if a retry is sent now?
  • Is the message critical enough to justify the residual risk?
  • Is there a recurring restriction related to the destination, sender, or content that requires review?

Design a retry ladder with explicit stop conditions

A retry ladder should be defined by message type, not as a global rule. It should specify the maximum number of technical attempts, the wait between them, the absolute expiry, eligible causes, and stop conditions. If any of these elements is undefined, behavior will be exposed to improvised decisions.

Waits should allow late events and callbacks to arrive before another copy is created. HTTP callbacks may arrive out of order and with latency variations; some transitions may occur very close together. For this reason, automation should not decide solely on the first observed event or the first local timeout.

The attempt limit should be low and reasoned for the use case. If degradation persists, more repetitions may increase duplicates, operational costs, and frustration without correcting the cause. The final outcome should lead to closure or review, not an indefinite cycle.

  • Set a maximum number of technical attempts per logical message.
  • Define a minimum reconciliation wait before every new attempt.
  • Apply an absolute expiry that takes precedence over any pending retry.
  • Allow retries only for pre-approved causes.
  • Stop the flow upon reported delivery, definitive rejection, expiry, high duplicate risk, or exhaustion of the limit.
  • Send repeated or inconclusive cases for operational review.

OTP: coordinate delivery, expiry, and security

OTPs and other authentication secrets require a stricter policy. An out-of-band secret is short-lived and delivered through an independent channel. If the code has already expired, a transport retry adds no value and may worsen the experience.

Code validity, the authentication attempt limit, and suppression of repeated requests must work together. When a new code is generated, the system must explicitly decide what happens to the previous one, which technical attempt remains associated with each code, and which messages are suppressed. Do not let the transport layer continue resending a code that the authentication backend already considers invalid.

PSTN/SMS flows also require authentication alternatives and risk controls appropriate to the context. Limited coverage, device or SIM changes, number portability, and anomalous behavior are examples of signals that may justify additional controls. Resending SMS must not become the automatic response to persistent degradation.

User-facing responses should be cautious, especially in authentication and account recovery. Avoid messages that unnecessarily reveal whether an account exists or what its status is.

  • Link every OTP to an unambiguous business expiry.
  • Do not retry sending an OTP after its expiry.
  • Control repeated requests to reduce fatigue and unnecessary traffic.
  • Apply rate limiting to authentication attempts where appropriate.
  • Define authentication alternatives for cases where SMS is not suitable or available.
  • Keep external responses generic when necessary to prevent account enumeration.
FAQ

Frequently asked questions

Does a sending status confirm that the SMS reached the phone?

Not necessarily. A sending status may indicate that an upstream carrier accepted the message. It must be distinguished from a reported delivery status and, in turn, from receipt or reading by the recipient.

When should a transactional SMS retry stop?

It should stop when the message is no longer useful, there is evidence of definitive rejection, there is a high risk of duplication, the defined attempt limit has been reached, or the cause requires review rather than another repetition.

Should an SMS be resent automatically after a timeout?

No. A timeout may leave an uncertain outcome: the first attempt may have been accepted or may still generate updates. Before resending, reconcile the available identifier, wait for late events, and check the usefulness window.

What minimum data should be recorded for each attempt?

Record an internal ID for the logical message, idempotency key, attempt number, creation and decision times, provider or connection used, provider identifier, status, error code where available, classified cause, expiry, and subsequent decision.

Should an OTP be resent while it remains valid?

Only if the policy allows it and duplicate risk is controlled. The decision must be coordinated with code expiry, suppression of repeated requests, and authentication limits. It is not advisable to send a code that has already expired or has been invalidated by a newer code.

Sources consulted

  1. NIST SP 800-63B-4: autenticadores fuera de banda y uso de PSTNNational Institute of Standards and Technology (NIST)
  2. Twilio Message Resource: estados, aceptación por carrier, intentos y período de validezTwilio
  3. Twilio: seguimiento de estados y callbacks de mensajes salientesTwilio
  4. OWASP Authentication Cheat SheetOWASP Foundation