SMS Delivery Failures Playbook¶
Symptom: SMS not delivered to recipient.
Hypotheses¶
| Hypothesis | Likely Cause | Evidence Tag |
|---|---|---|
| Wrong phone format | Number not in E.164 format (e.g., missing +1) | [Observed] |
| Recipient opt-out | Recipient is on a STOP list or has previously opted out | [Inferred] |
| Carrier blocking | Content triggered spam filters or suspicious pattern detection | [Correlated] |
| Rate limiting | Exceeding the messages per second (MPS) limit for the number | [Measured] |
| Invalid number | Destination number is disconnected or does not exist | [Observed] |
flowchart TD
S["SMS not delivered"] --> H1{"Number in E.164 format?"}
H1 -- no --> R1["Correct phone format"]
H1 -- yes --> H2{"Recipient opted out?"}
H2 -- yes --> R2["Respect opt-out and re-consent flow"]
H2 -- no --> H3{"Throttled at MPS limit?"}
H3 -- yes --> R3["Throttle sends within MPS"]
H3 -- no --> H4{"Carrier blocking or invalid number?"}
H4 -- yes --> R4["Adjust content or drop invalid number"]
H4 -- no --> EV["Collect evidence: delivery reports, SMS metrics, CLI send"]
EV --> M["Apply mitigation and confirm delivery report"] Evidence Collection¶
1. Delivery Reports¶
Query the ACSSMSIncomingOperations table in Log Analytics, filtering for OperationName == "SMSDeliveryReportsReceived" and inspecting ResultType, ResultSignature, and ResultDescription per row.
2. Monitor Metrics¶
Review the SMS API Requests metric in Azure Monitor and split by the Operation dimension (SMSMessageSent vs SMSDeliveryReportsReceived) to compare send volume against delivery report volume. Filter by the Status Code dimension (for example 200, 400, 429) or StatusSubClass (2xx, 4xx, 5xx) to separate successful from failed API calls.
3. CLI Check¶
Delivery status is not read from the CLI. Request a delivery report when sending the message, then consume the result through Event Grid (SMS Delivery Report event).
az communication sms send --sender "<from>" --recipient "<to>" --message "test" --deliveryReport --connection-string "<cs>"
| Command | Purpose |
|---|---|
az communication sms send | Sends an SMS, optionally requesting a delivery report. |
--sender "<from>" | Sets the provisioned ACS phone number the SMS is sent from. |
--recipient "<to>" | Sets the destination phone number. |
--message "test" | Sets the SMS body text. |
--deliveryReport | Enables delivery reporting; the report is delivered via Event Grid, not the CLI. |
--connection-string "<cs>" | Authenticates the request using the ACS connection string. |
Validation¶
[Observed] Validate Phone Format¶
Ensure the number starts with + followed by the country code. If not, the SDK or service will reject the request with a 400 Bad Request.
[Inferred] Check Opt-out Status¶
Review recipient communication history. If they sent a STOP keyword, the carrier will block future messages.
[Measured] Review MPS Throttling¶
Check for 429 Too Many Requests in your app logs. Azure Monitor will show spikes in throttled requests.
Mitigation¶
- Fix Format: Normalize all phone numbers to E.164 before sending.
- Handle Opt-outs: Respect STOP keywords and implement a local suppression list.
- Optimize Content: Avoid short-links and suspicious keywords. Use a consistent sender name.
- Scale Throughput: If hitting rate limits, request a higher MPS limit or use a toll-free number.
See Also¶
Sources¶
- Azure SMS Delivery Report Status Codes
- CTIA Messaging Principles and Best Practices