Diagnosing Twilio SMS Delivery Failures: When Messages Stay in 'Sent'
Diagnose Twilio SMS messages that stay in "sent" or fail with error codes 30007 and 30003. Check carrier logs, StatusCallback webhooks, and A2P 10DLC compliance to pinpoint and resolve delivery issues.
17 Jan 2026, 23:31 UTC

The Condition: Messages Stop at \"Sent\"
You call the Twilio Programmable SMS API, receive a 201 Created response with a message SID, and the initial status reads queued or sent. Minutes later, the Message Logs still show sent, or the status flips to failed with an error code. The recipient reports nothing arrived. This guide helps you determine whether the failure happened at the carrier, in content filtering, or in your own webhook pipeline.
Key takeaway: In Twilio, sent means the upstream carrier accepted the message for delivery. It is not a handset receipt. The only reliable signal that a message reached the device is a delivered status delivered asynchronously through a StatusCallback webhook, which is the URL Twilio calls when a message status changes.
Common Causes and Diagnostic Signals
| Observed Symptom | Likely Cause | Where to Look |
|---|---|---|
Status remains sent indefinitely | Carrier accepted the message but did not return a delivery receipt | Message Logs; absence of StatusCallback event |
Status failed, ErrorCode 30007 | Destination unreachable or carrier content filter blocked the message | Message resource error_code field |
Status failed, ErrorCode 30003 | Number is not a valid SMS-capable mobile line (e.g., landline or inactive) | Message resource error_code field |
| No error, but US messages silently vanish | A2P 10DLC brand or campaign not verified; carrier silently drops unregistered traffic | Console > Messaging > Regulatory Compliance; Debugger |
| International messages fail while domestic succeed | Alphanumeric Sender ID used in a market that restricts it (e.g., US, Canada) | Messaging Service sender pool and geographic permissions |
Ordered Diagnostic Checks
1. Confirm the API response and Message SID
Run this from your application server or a secure terminal with your Twilio credentials. Replace ACxxxxxxxx with your Account SID and SMxxxxxxxx with the Message SID returned by the create-message call.
curl -X GET \"https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxx/Messages/SMxxxxxxxx.json\" \\
-u \"ACxxxxxxxx:your_auth_token\"
Expected check: The response should contain a status field. If it reads undelivered or failed, inspect error_code and error_message. If it reads sent, the carrier has the message and the problem is downstream.
Risk: Your Auth Token grants full account access. Use it only in secure environments and never commit it to source control.
2. Inspect Message Logs for carrier error codes
In the Twilio Console, go to Monitor > Logs > Messaging (or Messaging > Logs depending on Console layout). Filter by the recipient number and time window. Look for the Error Code column.
Expected check: Error 30007 points to carrier filtering or an unreachable handset. Error 30003 points to an invalid SMS destination. No error code with a stuck sent status suggests the carrier is not returning a delivery receipt.
3. Audit StatusCallback webhook health
StatusCallback is the URL Twilio calls when a message status changes. If your endpoint returns a non-2xx response or times out, you will not see delivered or failed events even though Twilio recorded them.
Open the Twilio Debugger (Console > Monitor > Debugger) and filter for Errors. Look for HTTP connection failures or invalid response errors related to StatusCallback requests.
Expected check: Your webhook should respond with 200 OK within 15 seconds. A 500 or timeout means your application, not the carrier, is hiding the final status.
4. Isolate the carrier with a controlled test
Send a single message with unique, plain-language text to a known-good device on a different mobile carrier. Avoid repeating identical content to the same number, which can trigger spam filters.
Expected check: If the message delivers on Carrier B but not Carrier A, the issue is carrier-specific filtering. If it fails everywhere, suspect your sender configuration or content.
5. Review Messaging Service sender and geographic rules
If you use a Messaging Service, open Messaging > Services and inspect the sender pool. Alphanumeric Sender IDs (e.g., "MyBrand") are not supported for delivery to US or Canadian numbers. If your pool contains only an alphanumeric sender and you are messaging a US number, the carrier will reject or silently drop the traffic.
Expected check: For US destinations, the sender pool should include a 10DLC long code or short code. For international destinations, verify that the selected sender type is permitted in that market.
Fixes Tied to Findings
Finding: Error 30007 (carrier filter or unreachable)
- Remove or rewrite link shorteners, prohibited keywords, and all-caps text.
- Reduce burst volume and vary message content across recipients.
- If the number was recently ported or inactive, wait and retry after confirming it is reachable.
Finding: Error 30003 (invalid destination)
- Format numbers in E.164, the international phone number format (e.g.,
+15558675309). - Use the Twilio Lookup API to confirm the line type is
mobilebefore sending.
Finding: Silent US drops
- Complete A2P 10DLC brand and campaign registration in the Console. A2P 10DLC is the US carrier registration framework for application-to-person business messaging.
- Until registration is approved, use a verified short code or an already-registered 10DLC campaign.
Finding: StatusCallback errors in Debugger
- Fix your endpoint to return HTTP
200immediately. Process the payload asynchronously if needed. - Ensure your firewall allows Twilio's IP ranges and that TLS certificates are valid.
Finding: Alphanumeric sender rejected internationally
- In the Messaging Service, add a numeric long code or short code for the affected country.
- Use geographic permissions or a Sticky Sender to route traffic to the correct sender type.
Concrete Example: Reading the Final Status
Assume your application created a message and stored the SID SM1234567890abcdef. To see the final carrier disposition, query the Message resource from your server or a secure terminal:
curl -X GET \"https://api.twilio.com/2010-04-01/Accounts/AC1234567890abcdef/Messages/SM1234567890abcdef.json\" \\
-u \"AC1234567890abcdef:your_auth_token\"
An illustrative response structure for a filtered message looks like this:
{\n \"status\": \"failed\",\n \"error_code\": 30007,\n \"error_message\": \"Message filtered by carrier\",\n \"date_updated\": \"Wed, 16 Oct 2026 08:15:00 +0000\"\n}
A delivered response will show \"status\": \"delivered\" and no error code. If the status remains \"sent\" with no error code after several minutes, the carrier likely did not return a delivery receipt.
Escalation Criteria
Contact Twilio Support with the Message SID, timestamps, and Debugger logs when:
- The Debugger shows Twilio-side 5xx errors during StatusCallback processing.
- A2P 10DLC registration is fully approved, yet US messages still fail with no error code.
- Multiple carriers in the same country reject identical content while a known-good control message succeeds.
- You observe
30007on a number that has successfully received messages from the same sender previously.
Limitations and Verification
Limitations: Twilio cannot force a carrier to deliver a message once it has been accepted. Some carriers do not return delivery receipts at all, so a permanent sent status may be the final available state. A2P 10DLC rules and carrier filtering behavior change over time; confirm current requirements in the Twilio Console and carrier documentation.
Practical verification: After applying a fix, send one unique test message to a personal device on a different carrier. Wait five minutes. In the Message Logs, confirm the status reaches delivered or a terminal failed state with an explanatory error code. If the status still reads sent with no error, re-check your StatusCallback endpoint in the Debugger before escalating.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.