SMS DeliverabilityJune 3, 202610 min read

Twilio Error 30003, 30005, and 30006: Prevent SMS Delivery Failures with Phone Validation

Delivery errors are not only provider logs. They are paid evidence that your list contains unreachable, inactive, or non-SMS-capable numbers. A validation gate catches many of those failures before the message is sent, so SMS spend stays focused on valid mobile contacts.

Phone validation workflow preventing SMS delivery errors 30003 30005 and 30006 with carrier lookup and line type detection
Preventable SMS failures usually come from list quality: invalid numbers, landlines, unsupported line types, and stale carrier data.

Quick answer: what should SMS teams do first?

The fastest fix for recurring 30003, 30005, and 30006 delivery errors is to validate every number before it enters the send queue. Normalize the number, verify it is valid, detect carrier and line type, remove landlines and disconnected numbers, and export a clean mobile-only file for SMS.

12% to 1.8%

Potential failure-rate improvement after validation cleanup.

40%

Typical wasted SMS volume removed from dirty lists.

50ms

Average real-time validation response for form gates.

232

Countries covered for global phone validation workflows.

What 30003, 30005, and 30006 usually mean

Provider error codes are useful because they point back to a list-quality decision. Twilio documents 30003 as an unreachable handset, 30005 as an unknown destination, and 30006 as a landline or unreachable carrier issue. The prevention work happens upstream.

CodeMeaningLikely data issuePrevention rule
30003Unreachable destination handsetThe handset is unavailable, unsupported for SMS, roaming, or attached to an unreachable carrier.Validate before send, flag disconnected records, and route uncertain numbers to a smaller retry queue.
30005Unknown destination handsetThe number may no longer exist, may be inactive, or may be formatted with the wrong country code.Normalize to E.164, run a phone number validity check, and remove invalid or inactive records from the audience.
30006Landline or unreachable carrierThe number cannot receive SMS because it is a landline, an unsupported line type, or on a carrier path that cannot be reached.Detect mobile, landline, fixed VoIP, non-fixed VoIP, and toll-free line types before the message leaves your system.

Why retries are a weak default

Retry logic helps when the handset is temporarily offline. It fails when the destination is a landline, a void number, a recycled contact, or a non-fixed VoIP number created to abuse an OTP form. Retrying those records adds cost without adding reach.

SMS marketers feel the problem in two places. First, failed sends inflate cost per reached contact. Second, undelivered traffic pollutes performance reporting. A campaign may look like a copy, offer, or sender issue when the real problem is that 10,000 rows should never have been eligible for SMS.

Phone-Check.app gives teams a cleaner workflow: validate, detect line type, check carrier, identify timezone, filter out invalid or non-mobile rows, then export the clean segment. For forms, the same decision happens in under 50ms before the record is saved.

Build an SMS eligibility rule before the send

Send now

Signal: Valid mobile, active carrier, local send window

Action: Send SMS or MMS through the approved campaign

Result: Higher delivery rate and cleaner campaign reporting

Voice or email fallback

Signal: Landline, toll-free, or fixed business VoIP

Action: Remove from SMS and keep the record for another channel

Result: No paid SMS attempt against a number that cannot receive it

Manual review

Signal: Recently ported, ambiguous line type, or high-value account

Action: Hold the send, enrich the record, or ask sales to confirm

Result: Less false suppression on valuable accounts

Suppression

Signal: Invalid, disconnected, disposable, non-fixed VoIP, or repeated failures

Action: Remove from campaign exports and future automated sends

Result: Lower failure rate and less spend on unreachable contacts

API example: classify before sending SMS

Put validation between the form, CRM, or campaign export and your SMS provider. The example below returns a simple send decision your application can store next to the contact record.

type PhoneCheckResult = {
  carrier?: string;
  line_type?: 'mobile' | 'landline' | 'fixed_voip' | 'non_fixed_voip' | 'toll_free';
  normalized_phone?: string;
  risk_score?: number;
  timezone?: string;
  valid: boolean;
};

type SmsDecision = {
  allowSms: boolean;
  reason: string;
  normalizedPhone?: string;
};

export async function classifyBeforeSms(phoneNumber: string): Promise<SmsDecision> {
  const url = new URL('https://api.phone-check.app/v1-get-phone-details');
  url.searchParams.set('phone', phoneNumber);

  const response = await fetch(url, {
    headers: {
      accept: 'application/json',
      'x-api-key': process.env.PHONE_CHECK_API_KEY ?? '',
    },
  });

  if (!response.ok) {
    return { allowSms: false, reason: 'validation_unavailable' };
  }

  const result = (await response.json()) as PhoneCheckResult;

  if (!result.valid) {
    return { allowSms: false, reason: 'invalid_or_inactive_number' };
  }

  if (result.line_type === 'landline' || result.line_type === 'toll_free') {
    return { allowSms: false, reason: 'not_sms_capable' };
  }

  if (result.line_type === 'non_fixed_voip' || (result.risk_score ?? 0) >= 70) {
    return { allowSms: false, reason: 'high_risk_or_disposable_number' };
  }

  return {
    allowSms: true,
    normalizedPhone: result.normalized_phone,
    reason: 'valid_mobile_or_reviewed_fixed_voip',
  };
}

The exact endpoint shape depends on your account configuration, but the rule should stay stable: no valid mobile signal, no automatic SMS. High-value exceptions can move to review instead of suppression.

Bulk CSV cleanup for campaign teams

Real-time validation protects forms and checkout flows. Bulk validation protects campaigns. Upload multiple CSV files, map the phone column, validate each row, and download a clean file without landlines, invalid numbers, and high-risk VoIP records.

Open bulk checker
Example export fields
phone,valid,line_type,carrier,timezone,sms_eligible,action
+14155550140,true,mobile,Verizon,America/Los_Angeles,true,send
+14155550141,true,landline,AT&T,America/Los_Angeles,false,voice_fallback
+14155550142,false,unknown,,America/New_York,false,suppress
+14155550143,true,non_fixed_voip,Virtual Provider,America/Chicago,false,review_or_suppress

Carrier and timezone data make the fix stick

Carrier lookup does more than label the network. It helps messaging teams understand whether failures are concentrated around a specific carrier, country, acquisition source, or send window. That is valuable when A2P 10DLC registration, sender reputation, or carrier filtering also needs review.

Timezone data prevents another quiet source of waste: valid messages sent when the recipient is asleep, commuting, or outside local business hours. Once the list is valid and mobile-ready, schedule by local time so better data turns into better engagement.

FAQ

Can phone validation prevent every SMS delivery error?

No. Carrier outages, handset power, roaming, content filtering, and sender registration can still affect delivery. Phone validation prevents the avoidable part: invalid numbers, landlines, disconnected records, non-mobile line types, and stale campaign files.

Should I retry messages after a 30003, 30005, or 30006 error?

Retry only after classification. A transient 30003 may deserve a limited retry, but 30005 and repeated 30006 failures usually point to invalid, inactive, or non-SMS-capable destinations. Those records should be cleaned before future sends.

How often should SMS campaign lists be validated?

Validate new leads in real time and run bulk validation before every major campaign. Phone data changes through disconnects, carrier changes, porting, and recycled numbers, so a list cleaned last quarter can still contain expensive failure risk.

What fields should I export after bulk phone validation?

Export the normalized number, validity, line type, carrier, country, timezone, risk reason, SMS eligibility, and suppression reason. Marketing can use the clean file while RevOps keeps the rejected rows for repair or fallback channels.

Related reading