Plongée technique : architecture et algorithmes de routage SMS par correspondance opérateur
Introduction : les coulisses du routage SMS par correspondance opérateur
La plupart des fournisseurs SMS décrivent le routage comme une boîte noire :
« Nous utiliserons la meilleure route en fonction de la qualité et du prix. »
Si vous êtes ingénieur ou architecte responsable de la disponibilité, ce n'est pas suffisant. Vous devez savoir :
- Quel chemin un message a suivi.
- Quel expéditeur a été utilisé.
- Pourquoi le système a choisi cette combinaison.
- Comment il se comportera en cas de pannes et de pics de trafic.
Le routage par correspondance opérateur est l'une des raisons principales pour lesquelles certaines passerelles atteignent durablement 99,4 % et plus de délivrabilité dans des verticales difficiles, tandis que d'autres stagnent entre 90 et 95 %. Dans cet article, nous allons explorer en détail l'architecture :
- La couche d'intelligence (détection de l'opérateur et du type de ligne).
- Le moteur de décision de routage.
- La sélection de pools/grilles et la logique de rotation.
- Les stratégies de repli.
- L'observabilité et le débogage.
Ceci n'est pas du marketing fournisseur. C'est l'architecture concrète que nous avons vue fonctionner sur des millions de messages par jour.
Section 1 : ce que signifie réellement la « correspondance opérateur »
À un niveau général, la correspondance opérateur consiste à :
Pour chaque numéro de destination, choisir un expéditeur et une route qui correspondent le mieux à l'opérateur et au contexte de la destination.
Plutôt que de :
- Tout envoyer via les routes génériques les moins chères.
- Mélanger tous les opérateurs et tous les cas d'usage sur les mêmes expéditeurs.
La correspondance opérateur vise à :
- Utiliser des expéditeurs validés Verizon pour les abonnés Verizon.
- Utiliser des expéditeurs validés AT&T pour les abonnés AT&T.
- Maintenir une réputation par opérateur isolée et prévisible.
Bénéfices observés en pratique :
- Un gain de délivrabilité de 3 à 12 points sur certains opérateurs par rapport au routage générique.
- Une variance réduite des performances dans le temps.
- Une analyse des causes profondes plus claire en cas de problème (un opérateur, une grille).
Section 2 : architecture de haut niveau
Une passerelle SMS à correspondance opérateur comporte généralement les composants suivants :
-
API d'entrée (ingress)
- Reçoit les requêtes de messages (
/messages). - Valide la charge utile, l'authentification et le schéma de base.
- Reçoit les requêtes de messages (
-
Normalisation et enrichissement
- Normalise les numéros de téléphone (E.164).
- Enrichit avec :
- Les informations sur l'opérateur.
- Le pays/la région.
- Le type de ligne (mobile, VoIP, fixe lorsque disponible).
- Les signaux de risque.
-
Moteur de décision de routage
- À partir du contexte enrichi et des métadonnées applicatives :
- Choisit un profil de route (par ex., OTP_US, Promo_EU).
- Sélectionne un pool/grille.
- Choisit un expéditeur au sein de cette grille.
- Applique des règles par opérateur et par grille.
- À partir du contexte enrichi et des métadonnées applicatives :
-
Mise en file d'attente et envoi
- Place les messages dans des files d'attente par route.
- Applique :
- Une limitation de débit.
- Un contrôle des pics.
- Des stratégies de réessai.
-
Accusés de réception et retour d'information
- Ingère les DLR (accusés de réception de livraison).
- Met à jour :
- La santé du pool/de la grille.
- Les métriques de réputation des expéditeurs.
- Alimente en retour les décisions de routage.
-
Plan d'observabilité
- Métriques, journaux, traces.
- Interrogeable par :
- Opérateur.
- Pool/grille.
- Expéditeur.
- Campagne.
Section 3 : la couche d'intelligence opérateur
Avant de pouvoir faire correspondre les opérateurs, il faut les connaître.
Entrées
- Numéro de téléphone au format E.164.
- Optionnellement :
- Le code pays issu du contexte applicatif.
- Des métadonnées utilisateur connues (par ex., opérateur déjà résolu précédemment).
Sources
- Fournisseurs de lookup HLR / opérateur.
- API de renseignement sur les numéros de téléphone.
- Caches internes (numéros récemment résolus).
Sorties
Pour une destination donnée :
carrier_id: par ex.,verizon_us,att_us,tmobile_us,o2_uk, etc.country_code:US,GB,DE, etc.line_type:mobile,fixed,voip(lorsque disponible).risk_flags: portabilité récente, plages suspectes, etc. (optionnel).
Stratégie de mise en cache
- Préchauffer les caches sur :
- Les destinations à fort trafic.
- Les expéditeurs fréquents connus (par ex., utilisateurs intensifs d'OTP).
- Respecter :
- Les limites de débit du fournisseur de lookup.
- Les contraintes de fraîcheur des données.
Exemple (pseudo-code) :
type CarrierInfo = {
carrierId: string;
country: string;
lineType?: string;
lastUpdated: number;
};
async function resolveCarrier(msisdn: string): Promise<CarrierInfo> {
const cached = await carrierCache.get(msisdn);
if (cached && Date.now() - cached.lastUpdated < CACHE_TTL_MS) {
return cached;
}
const lookup = await externalLookup(msisdn);
const info: CarrierInfo = {
carrierId: lookup.carrierId,
country: lookup.countryCode,
lineType: lookup.lineType,
lastUpdated: Date.now(),
};
carrierCache.set(msisdn, info);
return info;
}
Section 4 : conception du moteur de décision de routage
Étant donné :
- Le contexte de message enrichi (
CarrierInfo, pays, métadonnées applicatives). - Le type de message (OTP, transactionnel, marketing).
- La configuration du client/compte.
Le moteur de routage doit choisir :
-
Le profil de route
- Par ex.,
OTP_US,PROMO_US,ALERT_EU, etc. - Encapsule :
- Les opérateurs/routes préférés.
- Les plafonds de débit.
- Les types d'expéditeurs autorisés.
- Par ex.,
-
Le pool / la grille
- Par ex.,
US_OTP_VERIZON_GRID_A,US_PROMO_ATT_GRID_B. - Chaque grille :
- Représente un ensemble de cartes SIM/numéros.
- Possède une capacité et des métriques de santé par opérateur.
- Par ex.,
-
L'expéditeur au sein de la grille
- Selon :
- La stratégie de rotation.
- La santé.
- Les contraintes locales.
- Selon :
Flux de décision (simplifié)
function routeMessage(msg: Message, carrier: CarrierInfo): RouteDecision {
const profile = selectProfile(msg, carrier);
const candidateGrids = findEligibleGrids(profile, carrier);
const grid = selectBestGrid(candidateGrids);
const sender = pickSenderFromGrid(grid, msg);
return { profileId: profile.id, gridId: grid.id, senderId: sender.id };
}
Où :
-
selectProfileutilise :- Le type de message (OTP vs promo).
- Le pays/la région.
- Le risque/la verticale (par ex., crypto/adulte).
-
findEligibleGridsfiltre par :- Pays.
- Compatibilité opérateur.
- Seuils de santé.
-
selectBestGridpeut :- Privilégier les grilles avec :
- Des taux d'erreur/de plaintes sains.
- De la capacité disponible.
- Éviter :
- Les grilles approchant des seuils critiques.
- Privilégier les grilles avec :
-
pickSenderFromGrid:- Implémente une rotation :
- Round-robin (tour à tour).
- Pondérée.
- Tenant compte de la santé (en évitant les mauvais expéditeurs).
- Implémente une rotation :
Section 5 : pools/grilles et logique de rotation
Les grilles comme unité principale d'isolation
Une grille peut être définie par :
- La région :
US. - Le mix d'opérateurs : Verizon uniquement, AT&T uniquement, multi-opérateurs.
- Le cas d'usage :
OTP,PROMO,ALERT. - Le niveau de priorité.
Chaque grille suit :
- Le total des envois.
- La répartition livrés/échecs.
- Les codes d'échec définitif (hard-fail).
- Les taux de plaintes/désabonnements.
Stratégies de rotation
La plus simple :
- Round-robin entre les expéditeurs actifs.
Une meilleure approche :
- Rotation tenant compte de la santé :
- Ignorer les expéditeurs avec :
- Des taux d'erreur récents élevés.
- Des ratios de plaintes élevés.
- Favoriser :
- Les expéditeurs plus récents et en bonne santé.
- Ignorer les expéditeurs avec :
Exemple :
function pickSenderFromGrid(grid: GridState): Sender {
const healthy = grid.senders.filter((s) => s.healthScore > MIN_HEALTH);
const weighted = buildWeightedList(healthy, (s) => s.weight);
return randomChoice(weighted);
}
Avec :
healthScorebasé sur :- Le taux de livraison récent.
- Le taux d'échec définitif.
- Le taux de plaintes.
- Le temps écoulé depuis la dernière vérification/montée en charge progressive (warmup).
Mise au repos et période de récupération
Mettre en place des règles telles que :
- Retirer ou mettre au repos un expéditeur lorsque :
- Le taux d'échec définitif dépasse 1 à 2 % sur les N derniers messages.
- Les plaintes dépassent 0,3 à 0,5 % sur une période donnée.
- Les codes d'erreur spécifiques à l'opérateur s'envolent.
Les expéditeurs retirés :
- Sont sortis de la rotation active.
- Peuvent être retestés plus tard avec un trafic faible et sans risque.
Section 6 : mécanismes de repli, réessais et modes de défaillance
Même avec un bon routage, des incidents surviennent :
- Les opérateurs subissent des pannes.
- Certaines routes se dégradent.
- Une grille se trouve temporairement « grillée ».
Principes de repli
-
Privilégier d'abord les repli au sein de la même famille
- Passer de la Grille A à la Grille B au sein du même profil/pays.
- Garder l'OTP sur les grilles OTP, les promos sur les grilles promo.
-
Éviter les réessais instantanés et répétés sur le même chemin défaillant
- Reculer de manière agressive :
- Backoff exponentiel ou linéaire.
- Marquer les routes/grilles défaillantes comme dégradées.
- Reculer de manière agressive :
-
Dégradation maîtrisée
- Pour l'OTP :
- Essayer un expéditeur alternatif au sein de la même famille d'opérateur.
- Envisager un repli plus lent mais plus fiable.
- Pour les promos :
- Réduire le débit d'envoi.
- Différer les envois si les opérateurs sont clairement instables.
- Pour l'OTP :
Exemple de logique de réessai (simplifiée)
async function dispatchMessage(decision: RouteDecision, msg: Message) {
try {
const result = await sendToCarrier(decision, msg);
updateMetrics(decision, result);
return result;
} catch (err) {
markRouteAsDegraded(decision, err);
const fallbackDecision = findFallback(decision, msg);
if (!fallbackDecision) throw err;
const fallbackResult = await sendToCarrier(fallbackDecision, msg);
updateMetrics(fallbackDecision, fallbackResult);
return fallbackResult;
}
}
Section 7 : observabilité, journalisation et débogage
Le routage par correspondance opérateur ne vaut que ce que vaut son observabilité.
Vous devez pouvoir poser des questions comme :
- « Montrez-moi tous les messages vers Verizon des dernières 24 heures, routés via la Grille A vs la Grille B. »
- « Quels expéditeurs de la Grille C ont le taux d'échec définitif le plus élevé ? »
- « Qu'est-ce qui a changé au moment où la délivrabilité a chuté ? »
Champs de journalisation minimaux
Pour chaque message :
message_idtimestampcustomer_id(ou identifiant de projet/application)destination_msisdn(haché/pseudonymisé si nécessaire)carrier_idcountry_codeprofile_idgrid_idsender_idroute_id/ identifiant en amontstatus(en file d'attente, envoyé, livré, échoué, inconnu)error_code(le cas échéant)dlr_timestamplatency_mscampaign_idouflow_id(le cas échéant)
Tableaux de bord
- Cartes de chaleur opérateur × grille :
- Taux de livraison.
- Taux d'échec définitif.
- Classements des expéditeurs :
- Triés par santé et débit.
- Détection d'anomalies :
- Alertes lorsque :
- Le taux de livraison de l'opérateur X, Grille Y, tombe sous un seuil.
- Les codes d'erreur s'envolent.
- Alertes lorsque :
Exemple de déroulement d'incident
- Alerte : « La délivrabilité Verizon a chuté de plus de 3 points sur la Grille US_PROMO_A. »
- Utiliser les journaux :
- Vérifier les codes d'erreur et les volumes.
- Comparer avec les autres grilles.
- Atténuer :
- Déplacer temporairement le trafic promo Verizon vers la Grille US_PROMO_B.
- Réduire le débit d'envoi.
- Investiguer :
- Les changements récents de contenu/modèle de message.
- Les modifications de la configuration de routage.
FAQ : le routage par correspondance opérateur pour les développeurs
1. Avons-nous besoin d'un lookup HLR pour chaque message ?
Pas nécessairement.
Options :
- Mettre les résultats en cache pour une durée de vie (TTL) raisonnable.
- Résoudre en amont pour les utilisateurs à fort trafic.
- Effectuer des lookups par lots lors de l'amorçage des grilles.
2. Comment gérer la portabilité des numéros ?
Les numéros portés peuvent changer d'opérateur. Bonnes pratiques :
- Actualiser périodiquement les informations opérateur pour :
- Les destinations à haute fréquence.
- Les numéros présentant des échecs répétés.
3. La correspondance opérateur n'est-elle pertinente qu'aux États-Unis ?
Non. Elle est particulièrement utile :
- Partout où plusieurs opérateurs se comportent différemment.
- Là où les sender IDs et les modèles de message sont spécifiques à chaque opérateur (de nombreux marchés d'Europe et d'Asie-Pacifique).
4. Comment cela s'articule-t-il avec l'A2P 10DLC et les campagnes enregistrées ?
La correspondance opérateur :
- Utilise correctement les campagnes et expéditeurs enregistrés par opérateur.
- Vous aide à rester dans les limites de débit et de contenu attendues par campagne.
5. Qu'en est-il de la confidentialité et des données personnelles (PII) ?
Une implémentation privilégiant la confidentialité :
- Hache les MSISDN dans les journaux.
- Stocke un minimum de données.
- Conserve les métadonnées d'opérateur et de routage, pas le contenu brut.
6. Peut-on superposer la correspondance opérateur à un CPaaS existant ?
Parfois :
- Si le CPaaS expose :
- Des contrôles par opérateur.
- Des statistiques par expéditeur.
- Vous pouvez construire une couche de méta-routage par-dessus.
Mais les formes les plus robustes reposent sur une infrastructure propriétaire (cartes SIM, grilles privées).
Conclusion : du routage au mieux à un routage conçu comme une ingénierie
La plupart des programmes SMS fonctionnent sur un routage au mieux (best-effort) :
- Le fournisseur choisit des routes bon marché/disponibles.
- Vous obtenez une ou deux métriques.
- Vous espérez que tout se passera bien.
Le routage par correspondance opérateur transforme le SMS en un système conçu comme une ingénierie :
- Des choix de chemin déterministes par opérateur.
- Des grilles et des pools isolés.
- Une rotation et des replis tenant compte de la santé.
- Une observabilité riche pour la gestion des incidents.
Si vous tenez à :
- Atteindre et maintenir une délivrabilité de 99,4 % et plus.
- Survivre aux pics promotionnels et aux cas d'usage à haut risque.
- Donner à votre équipe SRE/infra des leviers qu'elle peut comprendre et en qui elle peut avoir confiance.
… alors mettre en place ou choisir une passerelle dotée d'une véritable architecture de correspondance opérateur n'est pas un simple plus, c'est la seule stratégie sensée à long terme.
Dach SMS Lab