Back to blog SMS Operations

Managing A2P SMS Outbound Queues: Admission, Draining, and Recovery

An operational guide to deciding which messages a queue accepts, how to classify failures, when messages expire, and how to recover traffic without confusing downstream acceptance with delivery to the recipient.

Operational diagram of an A2P SMS outbound queue showing admission, failure classification, draining, and monitoring

A queue begins wherever a system holds a message

An A2P messaging chain can contain several queues: in the sending application, on the messaging platform, at a connection or intermediary, and in downstream systems. For clear operations, identify which queue you are measuring and who is responsible for each transition.

A message that is “queued” is not necessarily accepted by the next system, and acceptance by that system does not prove that the message reached the phone. Explicitly define the boundary of responsibility: for example, when the platform receives a message, when an attempt is made, the next system’s acceptance response, and any subsequent delivery result, if available.

  • Assign each message an identifier that can be correlated across the systems you control.
  • Record when the message enters the queue, when processing is attempted, and what result the next system returns.
  • Keep internal statuses separate from statuses reported through external interfaces or reports.
A queue begins wherever a system holds a message

Define statuses that explain what happened

A useful internal model distinguishes work that is pending from work being processed and work that has received a response from the next system. It should also represent messages that are deferred, expired, or held for review. These are operational categories: do not present them as a normative list of SMPP statuses or automatically equate them with interface codes.

Document the permitted transitions, the event that triggers each one, and the system that provides the evidence. For example, a downstream acceptance response may end the local queue’s responsibility, but it should not be labeled final delivery to the recipient unless appropriate evidence supports that claim.

  • Pending: accepted by the platform, with no active processing attempt yet.
  • Processing: a worker is handling the send.
  • Accepted downstream: the next system confirmed that it accepts the message; this does not imply receipt by the handset.
  • Deferred: processing is postponed according to a defined policy.
  • Expired: the message’s time-sensitive value has ended, so it should not be sent as if it were still valid.
  • Under review: an operational decision is needed before the message can resume or be closed.
Define statuses that explain what happened

Admit traffic in a way that protects capacity

A queue should not grow without an operational limit. Set admission and capacity limits based on the resources you actually control: storage, available workers, connections, and configured capacity for destinations or traffic classes. There is no universal threshold that can be set without knowing the architecture, agreements, and observed behavior.

Segmentation by destination or class can help prevent a troubled traffic flow from consuming resources needed by other flows. Segmentation also adds complexity: define what happens when a limit is reached, how the result is communicated to the sender, and who can adjust the policy. Do not accept a message if the system cannot reliably retain it until processing or clearly reject it.

  • Set limits per queue and for any segments with different behavior or requirements.
  • Define an explicit action for when capacity is reached: reject, defer, or apply another documented policy.
  • Ensure the sending application can distinguish acceptance from rejection and manage its own retries without duplicating sends.
  • Review limits using actual data on incoming and outgoing traffic, message age, and resources—not generic figures.

Classify failures before retrying

Not every failure warrants the same treatment. Temporary saturation, an outage, a potentially transient rejection, and an error that requires correcting the message or configuration have different implications. Use the specific response from the interface or connected system and the applicable documentation to classify it; do not invent equivalences between codes.

For each failure class, document whether the message should be retried, deferred, rejected, or sent for review. Retries must be limited and coordinated between the sender and platform: if both repeat the send without coordination, they can increase load and create duplicates. Preserve the original result to support diagnosis.

  • Saturation: protect resources and apply the defined admission or deferral policy.
  • Unavailability: determine whether to wait and retry, with limits and a record of the reason.
  • Potentially recoverable rejection: confirm what condition must change before retrying.
  • Permanent or not automatically correctable error: avoid retry loops and route the case to closure or review.
  • In every case, record the observed response and the action taken.

Set order and priority without starvation

FIFO—first in, first out—is a straightforward option when messages in a queue have similar urgency requirements and there is no operational reason to change their order. If classes differ in validity period or priority, an explicit policy may be more appropriate, but it should preserve traceability and prevent lower-priority traffic from being blocked indefinitely.

Before introducing priorities, define which messages can belong to each class, who determines the classification, and how you will verify that the policy works. Do not base priority on sensitive content or use it to bypass consent or compliance controls.

  • Use FIFO when order is a requirement and the class is homogeneous.
  • Separate classes only when there is a justified and verifiable operational need.
  • Measure wait times by class and check whether a priority policy starves other classes.
  • Document how messages with equal priority are handled and how class changes are managed.

Align message validity with its usefulness

Validity expresses how long it remains useful to send a message. A one-time passcode, a transactional notification, and an authorized campaign may have different time requirements; do not assume they share an appropriate time limit. The person responsible for the message should define its useful life, and the platform should apply a policy consistent with it.

When a message expires, do not silently send it as if it were still valid. Record the expiration and communicate the result so the sending system can decide what to do. If a new send is considered, treat it as a new business decision, not as an automatic replay of outdated content.

  • Define validity for each use case with the person responsible for the message.
  • When required by policy, check message age before each new attempt.
  • Distinguish expiration from rejection or failed delivery.
  • Do not automatically reactivate expired messages without an explicit decision.

Recover service with a controlled drain

After an interruption, recovery is not simply a matter of resuming every pending send. First confirm that the cause of the backlog has been resolved and that the next system can accept traffic. Then release work gradually based on available capacity, using concurrency limits defined by the applicable configuration and agreements.

During draining, monitor whether message age or queue depth starts increasing again, whether rejections rise, and whether expected results are maintained. A shrinking queue is not sufficient evidence of recovery if messages are expiring, being rejected, or sent for review without the team noticing.

  • Identify and resolve the cause of the interruption before increasing send rates.
  • Resume with controlled limits rather than releasing the entire backlog without restriction.
  • Verify downstream acceptance and subsequent results separately.
  • Maintain a procedure for pausing again if the backlog returns or results worsen.

Monitor queue health, not just its size

Queue depth shows how many messages are waiting, but on its own it does not explain whether the situation is improving. Also track the age of the oldest message, incoming and outgoing rates, and results grouped by destination and class. Interpret these metrics alongside admission, rejection, deferral, and expiration events.

Present acceptance by the next system as acceptance, not final delivery. If delivery reports are received, their meaning depends on their source and level of verification: a received DLR does not necessarily mean independently verified receipt by the handset. Document this uncertainty in dashboards and reports.

  • Queue depth and age of the oldest message.
  • Incoming and outgoing rates over intervals appropriate to the operation.
  • Acceptances, rejections, deferrals, expirations, and messages sent for review.
  • Results broken down by destination and class, using consistent definitions.
  • Alerts tied to your own operational thresholds, reviewed against real data.
FAQ

Frequently asked questions

Does downstream acceptance mean a message was delivered?

No. It means the next system accepted the message according to the observed response. By itself, it does not prove that the phone received it. Delivery reports should also be interpreted according to their source and level of verification.

What should the maximum size of an outbound queue be?

There is no universal value that applies to every platform. The limit depends on resources, destinations, traffic classes, agreements, and observed behavior. Set it using operational data and define an explicit action for when it is reached.

Should every rejected message be retried?

No. First determine whether the cause is temporary, correctable, or permanent, using the response and documentation for the connected interface. Limit retries, prevent the sender and platform from retrying without coordination, and do not automatically retry expired content.

Should FIFO always be used?

FIFO is reasonable when preserving order matters and messages have similar requirements. If priorities are needed, define explicit classes and rules, and monitor to ensure that one class does not leave another waiting indefinitely.

Sources consulted

  1. SMPP v3.4, Issue 1.2SMPP Developers Forum
  2. HTTP Semantics (RFC 9110)IETF
  3. 3GPP specifications by series3GPP
  4. ITU-T Recommendation E.164International Telecommunication Union
  5. GSMA networks resourcesGSMA