Two French phone formats broke our SMS verification

这篇内容暂时只有 English 版本,以下是原文。

We shipped SMS verification to French users in March. Same code path as everywhere else: E.164 in the database, a small normalization step on input. About 4,000 signups a week from France at that point, and roughly 6% of them failed at the verify step. Not a carrier problem — the numbers never left our app.

What we saw in the logs: users typing 06 12 34 56 78, +33 6 12 34 56 78, and 0033 6 12 34 56 78. Our normalizer took anything starting with 0 and prefixed +33, dropping the leading zero. That worked for the first form and produced garbage for the second and third: +3306... and +33003.... The verify SMS still sent (twilio tolerated it in some cases), but the callback number didn’t match anything, so it looked like a silent failure to the user.

The fix was a small explicit normalizer rather than one regex:

import re

def to_e164_fr(raw: str) -> str:
    s = re.sub(r"[\s.\-()]", "", raw.strip())
    if s.startswith("+33"):
        s = "0" + s[3:]
    elif s.startswith("0033"):
        s = "0" + s[4:]
    if not re.fullmatch(r"0[1-9]\d{8}", s):
        raise ValueError("not a french mobile/landline")
    return "+33" + s[1:]

Why this shape: strip separators first, then peel the country prefix in the order users actually type it, then validate against the French national format before converting. The validation step is the part that matters — it turns a silent mismatch into a 400 the user can act on. Cost: a bit more code than a one-liner regex, and we now reject some edge inputs (like numbers typed with a trailing extension) that used to be passed through. That was the right trade for us.

Where this breaks: it does not handle overseas French numbers (Guadeloupe, Réunion, etc. start with 0590, 0262, and need different prefixes), and it will reject any number a user types already in E.164 with a non-French country code. We saw that happen with French expats using a Belgian SIM — they got a hard error, which was confusing but at least visible.

The thing I’m still unsure about: is validating against the national format the right default, or should we accept anything the SMS provider will send to and only normalize for display? We chose strict because the silent-failure mode was worse, but I’d like to know what others landed on for FR numbers.

0
赞同度 100% · 0 条评论 · 4 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。