14 déc. 2024·8 min de lecture

Système de notification multicanal : modèles, réessais, préférences

Concevoir un système de notification multicanal pour email, SMS et Telegram avec modèles, suivi de livraison, réessais et préférences utilisateur cohérentes.

Système de notification multicanal : modèles, réessais, préférences

Ce que résout un système de notification unique

Quand l'email, le SMS et Telegram sont développés comme des fonctionnalités séparées, les fissures apparaissent vite. La « même » alerte finit par avoir un libellé différent, un timing différent et des règles différentes sur qui la reçoit. Les équipes support se retrouvent alors à courir après trois versions de la vérité : une chez le fournisseur d'email, une chez la passerelle SMS et une dans les logs du bot.

Un système de notification multicanal corrige cela en considérant les notifications comme un seul produit, pas trois intégrations. Un événement se produit (réinitialisation de mot de passe, facture payée, serveur en panne), et le système décide comment le délivrer selon les modèles, les préférences utilisateur et les règles de livraison. Le message peut encore être formaté différemment selon le canal, mais il reste cohérent en sens, données et suivi.

La plupart des équipes finissent par avoir besoin des mêmes fondations, quel que soit le canal de départ : modèles versionnés avec variables, suivi du statut de livraison ("envoyé, délivré, échoué, pourquoi"), réessais et basculements sensés, préférences utilisateur avec consentement et heures calmes, et une piste d'audit pour que le support voie ce qui s'est passé sans deviner.

Le succès est ennuyeux, dans le bon sens. Les messages sont prévisibles : la bonne personne reçoit le bon contenu, au bon moment, via les canaux qu'elle a autorisés. Quand quelque chose casse, le dépannage est simple car chaque tentative est enregistrée avec un statut clair et un code raison.

Une alerte « nouvelle connexion » est un bon exemple. Vous la créez une fois, la remplissez avec les mêmes données utilisateur, appareil et emplacement, puis la délivrez en email pour les détails, en SMS pour l'urgence et en Telegram pour une confirmation rapide. Si le fournisseur SMS dépasse le délai, le système réessaie selon le planning, enregistre le timeout et peut basculer sur un autre canal au lieu d'abandonner l'alerte.

Concepts clés et un modèle de données simple

Un système de notification multicanal reste gérable quand vous séparez le « pourquoi on notifie » du « comment on le délivre ». Cela signifie un petit ensemble d'objets partagés, plus des détails spécifiques aux canaux uniquement là où ils diffèrent vraiment.

Commencez par un event. Un event est un déclencheur nommé comme order_shipped ou password_reset. Gardez des noms cohérents : minuscules, underscores, et au passé quand c'est pertinent. Traitez l'event comme le contrat stable dont dépendent les modèles et les règles de préférences.

À partir d'un event, créez un enregistrement notification. C'est l'intention visible par l'utilisateur : pour qui c'est, ce qui s'est passé, et quelles données sont nécessaires pour rendre le contenu (numéro de commande, date de livraison, code de réinitialisation). Stockez ici les champs partagés comme user_id, event_name, locale, priority et scheduled_at.

Puis divisez en messages par canal. Une notification peut produire de 0 à 3 messages (email, SMS, Telegram). Les messages contiennent des champs spécifiques au canal tels que destination (adresse email, numéro de téléphone, Telegram chat_id), template_id et contenu rendu (sujet/corps pour l'email, texte court pour le SMS).

Enfin, suivez chaque envoi comme une delivery attempt. Les tentatives incluent provider request_id, horodatages, codes de réponse et un statut normalisé. C'est ce que vous inspectez quand un utilisateur dit « je ne l'ai jamais reçu ».

Un modèle simple tient souvent dans quatre tables ou collections :

  • Event (catalogue des noms d'événements autorisés et valeurs par défaut)
  • Notification (une par intention utilisateur)
  • Message (une par canal)
  • DeliveryAttempt (une par tentative)

Planifiez l'idempotence tôt. Donnez à chaque notification une clé déterministe telle que (event_name, user_id, external_ref) pour que les réexécutions depuis des systèmes en amont ne créent pas de doublons. Si une étape de workflow est relancée, la clé d'idempotence évitera d'envoyer deux SMS au même utilisateur.

Conservez à long terme uniquement ce dont vous avez besoin pour l'audit (event, notification, statut final, horodatages). Gardez les files de livraison à court terme et les payloads bruts des fournisseurs seulement le temps nécessaire à l'exploitation et au dépannage.

Un flux pratique de bout en bout (étape par étape)

Un système de notification multicanal fonctionne mieux quand il traite « décider quoi envoyer » séparément de « l'envoyer ». Cela garde votre application rapide et rend les échecs plus faciles à gérer.

Un flux pratique ressemble à ceci :

  1. Un producteur d'événements crée une requête de notification. Cela peut être "password reset", "invoice paid" ou "ticket updated". La requête inclut un ID utilisateur, le type de message et les données de contexte (numéro de commande, montant, nom de l'agent support). Enregistrez la requête immédiatement pour garder une trace d'audit.

  2. Un routeur charge les règles utilisateur et message. Il consulte les préférences utilisateur (canaux autorisés, opt-ins, heures calmes) et les règles de message (par exemple : les alertes de sécurité doivent essayer l'email en premier). Le routeur décide d'un plan de canaux, comme Telegram puis SMS puis email.

  3. Le système met en file des jobs d'envoi par canal. Chaque job contient une clé de modèle, le canal et les variables. Les jobs vont dans une queue pour que l'action utilisateur ne soit pas bloquée par l'envoi.

  4. Des workers de canal délivrent via les fournisseurs. L'email passe par SMTP ou une API email, le SMS par une passerelle SMS, Telegram via votre bot. Les workers doivent être idempotents, ainsi relancer un même job n'entraîne pas d'envois en double.

  5. Les mises à jour de statut convergent en un seul endroit. Les workers enregistrent queued, sent, failed, et quand c'est possible, delivered. Si un fournisseur confirme seulement "accepted", enregistrez-le aussi et traitez-le différemment de delivered.

  6. Basculements et réessais s'appuient sur le même état. Si Telegram échoue, le routeur (ou un worker de retry) peut planifier SMS ensuite sans perdre le contexte.

Exemple : un utilisateur change son mot de passe. Votre backend émet une seule requête avec l'utilisateur et l'IP. Le routeur voit que l'utilisateur préfère Telegram, mais les heures calmes l'en empêchent la nuit, donc il planifie l'email maintenant et Telegram le matin, tout en suivant les deux sous le même enregistrement notification.

Si vous implémentez cela dans AppMaster, gardez la requête, les jobs et les tables de statut dans le Data Designer et exprimez le routage et la logique de réessai dans le Business Process Editor, avec l'envoi géré de façon asynchrone pour que l'UI reste réactive.

Structure de modèle qui fonctionne entre canaux

Un bon système de modèles part d'une idée : vous notifiez à propos d'un event, pas "vous envoyez un email" ou "vous envoyez un SMS". Créez un modèle par event (Password reset, Order shipped, Payment failed), puis stockez des variantes par canal sous ce même event.

Gardez les mêmes variables dans chaque variante de canal. Si l'email utilise first_name et order_id, le SMS et Telegram doivent utiliser exactement les mêmes noms. Cela évite des bugs subtils où un canal affiche correctement et un autre affiche des champs vides.

Une forme de modèle simple et répétable

Pour chaque event, définissez un petit ensemble de champs par canal :

  • Email : subject, preheader (optionnel), HTML body, fallback en texte
  • SMS : corps en texte brut
  • Telegram : corps en texte brut, plus boutons optionnels ou métadonnées courtes

La seule chose qui change par canal est le formatage, pas le sens.

Le SMS nécessite des règles spéciales car il est court. Décidez en amont de ce qui se passe si le contenu dépasse la longueur : fixez une limite de caractères, choisissez une règle de troncature (couper et ajouter ... ou supprimer d'abord les lignes optionnelles), évitez les URLs longues et la ponctuation superflue, et placez l'action clé en début (code, échéance, prochaine étape).

Locale sans dupliquer la logique métier

Traitez la langue comme un paramètre, pas comme un workflow séparé. Stockez les traductions par event et par canal, puis rendez avec les mêmes variables. La logique "Order shipped" reste la même tandis que le sujet et le corps changent selon la locale.

Un mode aperçu rentabilise l'effort. Rendez les modèles avec des données d'exemple (y compris des cas limites comme un nom long) pour que le support puisse vérifier les variantes email, SMS et Telegram avant mise en production.

Statut de livraison auquel on peut faire confiance et déboguer

Rendre le statut facile à déboguer
Fournissez au support une vue consultable de chaque tentative, statut et raison d'erreur.
Créer un tableau de bord

Une notification n'est utile que si vous pouvez répondre plus tard à la question : qu'est‑il arrivé ? Un bon système de notification multicanal sépare le message que vous vouliez envoyer de chaque tentative de livraison.

Commencez par un petit ensemble de statuts partagés qui signifient la même chose pour email, SMS et Telegram :

  • queued : accepté par votre système, en attente d'un worker
  • sending : une tentative de livraison est en cours
  • sent : remis avec succès à l'API du fournisseur
  • failed : la tentative s'est terminée par une erreur exploitable
  • delivered : preuve qu'il a atteint l'utilisateur (quand c'est possible)

Conservez ces statuts sur l'enregistrement principal du message, mais tracez chaque tentative dans une table d'historique. Cette histoire facilite le débogage : tentative #1 échouée (timeout), tentative #2 réussie, ou SMS ok alors que l'email rebondit.

Que stocker par tentative

Normalisez les réponses des fournisseurs pour pouvoir rechercher et agréger les problèmes même si les fournisseurs utilisent des mots différents.

  • provider_name et provider_message_id
  • response_code (code normalisé comme TIMEOUT, INVALID_NUMBER, BOUNCED)
  • raw_provider_code et raw_error_text (pour les cas support)
  • started_at, finished_at, duration_ms
  • channel (email, sms, telegram) et destination (masquée)

Prévoyez les succès partiels. Une notification peut créer trois messages de canal partageant le même parent_id et le même contexte métier (order_id, ticket_id, alert_type). Si le SMS est envoyé mais que l'email échoue, vous voulez encore toute l'histoire en un seul endroit, pas trois incidents sans lien.

Que signifie réellement "délivré"

"Envoyé" n'est pas "délivré". Pour Telegram, vous n'avez parfois que l'acceptation de l'API. Pour le SMS et l'email, la livraison dépend souvent des webhooks ou callbacks des fournisseurs, qui ne sont pas tous fiables de la même façon.

Définissez "delivered" par canal dès le départ. Utilisez la livraison confirmée par webhook quand elle est disponible ; sinon considérez la livraison comme inconnue et continuez de reporter "sent". Cela maintient vos rapports honnêtes et vos réponses support cohérentes.

Réessais, basculements et quand arrêter

Les réessais sont souvent la faiblesse des systèmes de notification. Réessayer trop vite crée des tempêtes. Réessayer indéfiniment crée des doublons et des maux de tête pour le support. L'objectif est simple : retenter quand il y a une vraie chance que ça marche, et arrêter quand ce n'est plus le cas.

Commencez par classer les échecs. Un timeout d'un fournisseur email, un 502 d'une passerelle SMS ou une erreur temporaire de l'API Telegram sont généralement réessayables. Une adresse email malformée, un numéro de téléphone invalide ou un chat Telegram ayant bloqué votre bot ne le sont pas. Les traiter pareil gaspille de l'argent et noie les logs.

Un plan de réessai pratique est borné et utilise du backoff :

  • Tentative 1 : envoyer maintenant
  • Tentative 2 : après 30 secondes
  • Tentative 3 : après 2 minutes
  • Tentative 4 : après 10 minutes
  • Arrêter après un âge maximal (par exemple 30–60 minutes pour les alertes)

L'arrêt doit exister dans votre modèle de données. Marquez le message comme dead-letter (ou failed-permanently) une fois les limites de réessai dépassées. Conservez le dernier code d'erreur et un court message d'erreur pour que le support agisse sans deviner.

Empêchez les envois répétés après succès avec l'idempotence. Créez une clé d'idempotence par message logique (souvent notification_id + user_id + channel). Si un fournisseur répond en retard et que vous réessayez, la seconde tentative doit être reconnue comme un doublon et ignorée.

Les basculements doivent être délibérés, pas une panique automatique. Définissez des règles d'escalade selon la gravité et le temps. Exemple : une réinitialisation de mot de passe ne doit pas basculer vers un autre canal (risque de confidentialité), mais une alerte d'incident de production peut essayer le SMS après deux échecs Telegram, puis l'email après 10 minutes.

Préférences utilisateur, consentement et heures calmes

Passer du développement au déploiement
Déployez sur AppMaster Cloud ou votre propre cloud quand vous êtes prêt à exécuter.
Déployer l'app

Un système de notification semble "intelligent" quand il respecte les personnes. Le moyen le plus simple est de laisser les utilisateurs choisir les canaux par type de notification. Beaucoup d'équipes segmentent les types en catégories comme sécurité, compte, produit et marketing car les règles et obligations légales diffèrent.

Commencez par un modèle de préférences qui fonctionne même quand un canal n'est pas disponible. Un utilisateur peut avoir un email mais pas de numéro de téléphone, ou ne pas avoir connecté Telegram. Votre système multicanal doit considérer cela comme normal, pas comme une erreur.

La plupart des systèmes finissent par nécessiter un ensemble compact de champs : type de notification (security, marketing, billing), canaux autorisés par type (email, SMS, Telegram), consentement par canal (date/heure, source et preuve si nécessaire), raison d'opt-out par canal (choix utilisateur, email en bounce, réponse "STOP"), et une règle d'heures calmes (début/fin plus le fuseau horaire de l'utilisateur).

Les heures calmes sont souvent la source d'erreurs. Stockez le fuseau horaire de l'utilisateur (pas seulement un offset) pour que les changements d'heure d'été n'en surprennent pas. Quand un message est programmé pendant les heures calmes, ne le marquez pas comme échec. Marquez-le comme différé et choisissez la prochaine heure d'envoi autorisée.

Les valeurs par défaut comptent, surtout pour les alertes critiques. Une approche commune : les notifications de sécurité ignorent les heures calmes (tout en respectant les opt-outs légaux), tandis que les mises à jour non critiques suivent les heures calmes et les choix de canal.

Exemple : une réinitialisation de mot de passe doit partir immédiatement par le canal le plus rapide autorisé. Un digest hebdomadaire doit attendre le matin et éviter le SMS sauf si l'utilisateur l'a explicitement activé.

Exploitation : monitoring, logs et workflows support

Unifier les notifications dans un seul système
Créez un flux de notification unique qui achemine email, SMS et Telegram à partir d'un seul événement.
Essayer AppMaster

Quand les notifications touchent email, SMS et Telegram, les équipes support ont besoin de réponses rapides : l'avons-nous envoyé, est‑il arrivé, et qu'est‑ce qui a échoué ? Un système de notification multicanal doit ressembler à un seul endroit d'investigation, même s'il utilise plusieurs fournisseurs en coulisses.

Commencez par une vue admin simple que n'importe qui peut utiliser. Rendez-la searchable par utilisateur, type d'événement, statut et fenêtre temporelle, et affichez la dernière tentative en premier. Chaque ligne doit révéler le canal, la réponse du fournisseur et l'action planifiée suivante (réessai, basculement ou arrêté).

Indicateurs qui attrapent les problèmes tôt

Les pannes n'apparaissent rarement comme une erreur unique. Suivez un petit ensemble de chiffres et revoyez-les régulièrement :

  • Taux d'envoi par canal (messages par minute)
  • Taux d'échec par fournisseur et par code d'échec
  • Taux de réessai (combien de messages ont nécessité une seconde tentative)
  • Temps de livraison (queued à delivered, p50 et p95)
  • Taux d'abandon (arrêtés en raison des préférences utilisateur, du consentement ou du max de réessais)

Corrélez tout. Générez un ID de corrélation quand l'événement arrive (comme "invoice overdue") et passez‑le via le templating, les files, les appels aux fournisseurs et les mises à jour de statut. Dans les logs, cet ID devient le fil à suivre quand un événement se propage sur plusieurs canaux.

Replays support sans surprises

Les replays sont essentiels, mais ils ont besoin de garde‑fous pour ne pas spammer les gens ou facturer deux fois. Un flux de replay sûr signifie généralement : renvoyer seulement un message ID spécifique (pas tout l'événement), montrer la version exacte du modèle et le contenu rendu avant envoi, exiger une raison et enregistrer qui a déclenché le replay, bloquer le replay si le message a déjà été délivré sauf si on force explicitement, et appliquer des limites de débit par utilisateur et par canal.

Sécurité et confidentialité de base pour les notifications

Un système de notification multicanal manipule des données personnelles (emails, numéros de téléphone, chat IDs) et couvre souvent des moments sensibles (connexions, paiements, support). Supposez que chaque corps de message et chaque ligne de log peut être vue plus tard, et concevez pour limiter ce qui est stocké et qui peut y accéder.

Évitez les données sensibles dans les modèles autant que possible. Un modèle doit être réutilisable et sobre : "Votre code est {{code}}" est correct, mais évitez d'inclure des détails de compte complets, de longs tokens ou tout ce qui pourrait permettre de reprendre un compte. Si un message doit contenir un code à usage unique ou un token de réinitialisation, stockez seulement ce dont vous avez besoin pour le vérifier (par exemple un hash et une date d'expiration), pas la valeur brute.

Quand vous stockez ou loggez des événements de notification, masquezz agressivement. Un agent support a généralement besoin de savoir qu'un code a été envoyé, pas du code lui‑même. Il en va de même pour les numéros de téléphone et les emails : conservez la valeur complète pour la livraison, mais affichez une version masquée sur la plupart des écrans.

Contrôles minimaux qui préservent la plupart des incidents

  • Accès basé sur les rôles : seule une petite équipe peut voir les corps de messages et les destinataires complets.
  • Séparez l'accès debug de l'accès support pour que le dépannage ne devienne pas une fuite de confidentialité.
  • Protégez les endpoints webhook : utilisez des callbacks signés ou des secrets partagés, validez les horodatages et rejetez les sources inconnues.
  • Chiffrez les champs sensibles au repos et utilisez TLS en transit.
  • Définissez des règles de rétention : gardez les logs détaillés brièvement, puis ne conservez que des agrégats ou des identifiants hachés.

Un exemple pratique : si un SMS de réinitialisation échoue et que vous basculez vers Telegram, enregistrez la tentative, le statut fournisseur et le destinataire masqué, mais évitez de stocker le lien de réinitialisation lui‑même dans la base ou les logs.

Scénario d'exemple : une alerte, trois canaux, résultats réels

Respecter les préférences utilisateur par conception
Implémentez consentement, heures calmes et choix de canaux sans dupliquer la logique.
Configurer les préférences

Une cliente, Maya, a activé deux types de notifications : Password reset et New login. Elle préfère Telegram d'abord, puis email. Elle veut le SMS seulement comme dernier recours pour les réinitialisations de mot de passe.

Un soir, Maya demande une réinitialisation de mot de passe. Le système crée un seul enregistrement notification avec un ID stable, puis le décompose en tentatives de canal selon ses préférences actuelles.

Ce que Maya voit est simple : un message Telegram arrive en quelques secondes avec un court code de réinitialisation et une durée d'expiration. Rien d'autre n'arrive puisque Telegram a réussi et aucun basculement n'était nécessaire.

Ce que le système enregistre est plus détaillé :

  • Notification : type=PASSWORD_RESET, user_id=Maya, template_version=v4
  • Tentative #1 : channel=TELEGRAM, status=SENT puis DELIVERED
  • Aucun email ni SMS créés (politique : arrêter après le premier succès)

Plus tard dans la semaine, une alerte New login se déclenche depuis un nouvel appareil. Les préférences de Maya pour ces alertes sont Telegram uniquement. Le système envoie Telegram, mais le fournisseur Telegram renvoie une erreur temporaire. Le système réessaie deux fois avec backoff, marque ensuite la tentative comme FAILED et s'arrête (aucun basculement autorisé pour ce type d'alerte).

Un vrai échec : Maya demande une autre réinitialisation pendant un voyage. Telegram est envoyé, mais le basculement SMS est configuré si Telegram ne délivre pas sous 60 secondes. Le fournisseur SMS timeoute. Le système enregistre le timeout, réessaie une fois et la seconde tentative réussit. Maya reçoit le code SMS une minute plus tard.

Quand Maya contacte le support, celui‑ci recherche par utilisateur et fenêtre temporelle et voit immédiatement l'historique des tentatives : horodatages, codes de réponse fournisseur, nombre de réessais et résultat final.

Liste de contrôle rapide, erreurs fréquentes et prochaines étapes

Un système de notification multicanal est plus facile à exploiter quand vous pouvez répondre à deux questions rapidement : "Qu'avons‑nous exactement essayé d'envoyer ?" et "Qu'est‑il arrivé ensuite ?" Utilisez cette checklist avant d'ajouter d'autres canaux ou événements.

Checklist rapide

  • Noms d'event clairs et responsabilités définies (par exemple invoice.overdue géré par billing)
  • Variables de modèle définies une fois (requises vs optionnelles, valeurs par défaut, règles de formatage)
  • Statuts convenus à l'avance (created, queued, sent, delivered, failed, suppressed) et leur signification
  • Limites et backoff de réessai (max tentatives, espacements, règle d'arrêt)
  • Règles de rétention (durée de conservation des corps de message, réponses fournisseurs et historique de statut)

Si vous ne faites qu'une seule chose, écrivez clairement la différence entre sent et delivered. Sent est ce que votre système a fait. Delivered est ce que le fournisseur rapporte (et cela peut être retardé ou manquant). Confondre les deux embrouillera le support et les parties prenantes.

Erreurs courantes à éviter

  • Prendre "sent" pour un succès et afficher des taux de livraison gonflés
  • Laisser les modèles spécifiques aux canaux diverger jusqu'à ce que l'email, le SMS et Telegram se contredisent
  • Réessayer sans idempotence, provoquant des doublons quand les fournisseurs timeout mais acceptent plus tard
  • Réessayer indéfiniment, transformant une panne temporaire en incident bruyant
  • Stocker trop de données personnelles dans les logs et les historiques "au cas où"

Commencez par un event et un canal principal, puis ajoutez un second canal comme basculement (pas comme envoi parallèle). Une fois le flux stable, étendez événement par événement en gardant les modèles et variables partagés pour maintenir la cohérence.

Si vous voulez construire cela sans coder chaque partie à la main, AppMaster (appmaster.io) est un choix pratique pour les éléments centraux : modélisez events, modèles et tentatives de livraison dans le Data Designer, implémentez le routage et les réessais dans le Business Process Editor, et connectez email, SMS et Telegram comme intégrations tout en gardant le suivi centralisé.

Facile à démarrer
Créer quelque chose d'incroyable

Expérimentez avec AppMaster avec un plan gratuit.
Lorsque vous serez prêt, vous pourrez choisir l'abonnement approprié.

Démarrer