Agent Wranglers

Text messages Required

Store phone numbers in E.164

Parse every phone number with a phone number library, and store it in E.164 format with its country.

How to do it

E.164 is a plus sign, the country code and the number, with no spaces, such as +46701234567. Parse with a port of Google's libphonenumber, such as libphonenumber-js or phonenumbers for Python, using the visitor's country as the default. Reject numbers that are not valid. Check the line type before sending codes, because landlines cannot receive texts. Use type="tel" and autocomplete="tel" in the form.

Example

-- Must return 0 rows
SELECT id FROM users WHERE phone IS NOT NULL AND phone !~ '^\+[1-9][0-9]{6,14}$';
import { parsePhoneNumberWithError } from 'libphonenumber-js';

export function toE164(input, defaultCountry) {
  const number = parsePhoneNumberWithError(input, defaultCountry);
  if (!number.isValid()) throw new Error('Invalid phone number');
  return { e164: number.number, country: number.country };
}
import phonenumbers

def to_e164(raw: str, default_country: str) -> dict:
    number = phonenumbers.parse(raw, default_country)
    if not phonenumbers.is_valid_number(number):
        raise ValueError("Invalid phone number")
    return {"e164": phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164),
            "country": phonenumbers.region_code_for_number(number)}

How to check

A database query finds no phone number that fails the pattern ^\+[1-9][0-9]{6,14}$. A unit test turns "070-123 45 67" with country SE into +46701234567.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers notifications playbook: https://agentwranglers.se/playbook/notifications/text-messages/e164-phone-numbers.