Comment concevoir une application web capable d'envoyer, en quelques secondes, des campagnes de SMS et d'emails à des centaines de destinataires, sans base de données à administrer et sans plateforme marketing tierce ? C'est la problématique que nous avons résolue pour un établissement scolaire, et nous détaillons ici l'ensemble des choix techniques qui ont guidé le développement de cette application web sur mesure.
Cet article s'adresse à toute organisation (école, association, PME, cabinet de gestion locative, réseau de franchises) qui gère déjà ses contacts dans un tableur Google Sheets et cherche une solution d'envoi de SMS et d'emails en masse simple, fiable et évolutive, sans les coûts et la complexité d'une plateforme de marketing automation généraliste.
Le contexte : automatiser la communication sans complexifier l'existant
De nombreuses structures gèrent encore leurs listes de contacts dans des tableurs. C'est un outil que les équipes connaissent déjà, qu'elles peuvent modifier librement, et qui ne nécessite aucune formation. Le problème n'est donc pas l'outil de stockage, mais l'absence de passerelle entre ce tableur et un canal d'envoi de SMS ou d'email professionnel.
Les alternatives classiques posent chacune un problème :
- Les plateformes marketing tout en un imposent leur propre base de contacts, ce qui oblige à dupliquer et resynchroniser les données en permanence
- Les exports manuels de fichiers CSV vers un outil d'envoi sont chronophages et source d'erreurs (doublons, numéros mal formatés, listes obsolètes)
- Les solutions sans code génériques manquent de souplesse dès que la logique métier devient un peu spécifique (sélection par classe, historique détaillé, validation stricte des données)
Nous avons donc opté pour une application web sur mesure, construite spécifiquement autour du tableur existant, plutôt que d'imposer un nouvel outil de gestion de contacts.
Une architecture full stack unifiée avec Next.js et TypeScript
Le choix technique central de ce projet a été d'utiliser Next.js et TypeScript dans une architecture dite full stack monolithique : une seule base de code héberge à la fois l'interface utilisateur (les pages consultées par l'équipe administrative) et la logique serveur (les routes API qui communiquent avec Google Sheets et avec le fournisseur d'envoi).
Ce choix d'architecture logicielle présente plusieurs avantages concrets pour un développement d'application métier :
- Un seul projet à versionner, tester et déployer, ce qui réduit la charge de maintenance
- Un typage strict de bout en bout grâce à TypeScript, qui limite fortement les bugs liés à des données mal formées (un numéro de téléphone traité comme un nombre, un champ manquant, etc.)
- Une compatibilité native avec les environnements serverless, où chaque route API devient une fonction indépendante, facturée et mise à l'échelle automatiquement selon l'usage réel
Nous privilégions systématiquement ce type d'architecture simple et robuste plutôt qu'une séparation entre frontend et backend qui n'apporterait aucune valeur pour ce volume de fonctionnalités.
Google Sheets comme unique source de données : le cœur du système
Le parti pris le plus structurant du projet est l'absence totale de base de données technique (pas de PostgreSQL, MongoDB ou autre système de stockage additionnel). Google Sheets fait office de base de données unique, aussi bien en lecture (élèves, classes, coordonnées) qu'en écriture (historique des campagnes, paramètres de configuration).
Une lecture des données par mapping dynamique des colonnes
Techniquement, l'application communique avec Google Sheets via l'API officielle Google Sheets (bibliothèque googleapis), authentifiée par un compte de service (authentification JWT côté serveur, sans intervention humaine).
Plutôt que de coder en dur la position de chaque colonne, ce qui rendrait l'application fragile au moindre changement dans le tableur, nous avons développé un mapping dynamique des colonnes : à chaque lecture, l'application analyse la ligne d'en tête du tableur et retrouve automatiquement les colonnes utiles (nom de l'élève, classe, numéro de téléphone, adresse email) par correspondance de leur intitulé, indépendamment de leur ordre ou de leur position exacte.
Cette approche apporte une évolutivité réelle : une nouvelle colonne (niveau scolaire, statut actif ou inactif, matière) peut être ajoutée dans le tableur à tout moment, sans nécessiter la moindre modification du code de l'application. C'est un point technique essentiel pour toute solution logicielle destinée à évoluer dans le temps sans générer de dette technique.
Deux onglets générés et maintenus automatiquement
Au delà de l'onglet existant contenant les élèves, l'application crée et gère automatiquement deux onglets supplémentaires dans le même classeur :
- Un onglet Historique, qui enregistre chaque campagne envoyée (date, heure, utilisateur, canal, message, nombre de destinataires, nombre d'envois réussis, nombre d'erreurs, statut global)
- Un onglet Config, structuré en paires clé valeur, qui stocke les paramètres opérationnels (clé API du fournisseur d'envoi, expéditeurs SMS et email) directement modifiables depuis l'interface, sans jamais toucher au code ni redéployer l'application
Cette conception évite toute dépendance à des variables d'environnement pour des réglages que l'équipe administrative doit pouvoir changer elle même, en autonomie complète.
L'envoi de SMS et d'emails via l'API Brevo
Pour l'envoi effectif des messages, l'application s'appuie sur l'API REST de Brevo, une seule clé API servant à la fois pour les campagnes SMS et pour les campagnes email. Ce choix d'un fournisseur unique multicanal simplifie considérablement la configuration côté client, la facturation, et la maintenance à long terme, en évitant de multiplier les intégrations tierces.
Un traitement par lots pour fiabiliser les envois de masse
L'un des points techniques les plus sensibles d'une application d'envoi de SMS en masse hébergée en environnement serverless est la limite de temps d'exécution des fonctions, généralement de quelques secondes à quelques dizaines de secondes. Envoyer plusieurs centaines de messages en une seule requête risquerait de dépasser cette limite et de faire échouer l'intégralité de la campagne.
Nous avons donc implémenté un traitement par lots : les destinataires sont découpés en groupes de taille maîtrisée, envoyés séquentiellement, avec un suivi de progression affiché en temps réel à l'utilisateur. Cette approche garantit la fiabilité de l'envoi quel que soit le volume de destinataires, tout en restant compatible avec les contraintes d'une architecture serverless.
Une validation systématique avant chaque envoi
Avant tout déclenchement de campagne, plusieurs contrôles automatiques sont appliqués côté serveur :
- Validation du format des numéros de téléphone, avec normalisation au format international E.164 et détection du pays par défaut
- Validation du format des adresses email
- Suppression des doublons, insensible à la casse pour les adresses email
- Exclusion des lignes incomplètes, quand un destinataire n'a aucune coordonnée exploitable
- Calcul en temps réel du nombre exact de destinataires valides, affiché avant confirmation
Cette couche de validation limite drastiquement le risque d'erreurs d'envoi et de messages perdus, un enjeu central pour toute organisation qui communique avec un grand nombre de contacts.
Authentification et sécurité : une approche adaptée au serverless
L'accès à l'application est protégé par une authentification administrateur, avec une gestion de session reposant sur iron session : la session est encodée dans un cookie chiffré et signé côté client, sans qu'aucune donnée de session ne soit stockée sur un serveur. Cette architecture sans état est particulièrement adaptée à un hébergement serverless, où il n'existe justement pas de serveur permanent pour conserver un état.
Les informations sensibles, comme les identifiants d'accès à Google Sheets ou la clé API du fournisseur d'envoi, ne transitent jamais vers le navigateur : elles restent confinées aux fonctions serveur, soit sous forme de variables d'environnement pour les secrets d'infrastructure, soit stockées côté Google Sheets pour les paramètres modifiables par l'équipe. Chaque donnée saisie par l'utilisateur est par ailleurs revalidée côté serveur, indépendamment des contrôles déjà réalisés côté interface.
Déploiement serverless et qualité logicielle
L'application est hébergée sur Netlify, sous forme de fonctions serverless générées automatiquement à partir du projet Next.js. Ce mode de déploiement présente des avantages directs pour un projet logiciel destiné à durer :
- Aucune administration de serveur, ni mises à jour système, ni supervision, ni sécurité réseau à gérer
- Un déploiement continu automatique : chaque mise à jour du code, versionnée sur GitHub, déclenche un nouveau déploiement sans intervention manuelle
- Une mise à l'échelle automatique selon la charge réelle, sans surcoût en période de faible utilisation
La fiabilité du traitement métier, validation des numéros et emails, calcul des segments SMS, lecture dynamique des colonnes du tableur, est garantie par une suite de tests automatisés avec Vitest, exécutée à chaque modification du code. Cette démarche de test systématique est, à notre sens, non négociable dès lors qu'une application traite des envois réels vers des destinataires réels : une régression non détectée peut se traduire par des messages non délivrés ou envoyés en doublon.
Une interface pensée pour des utilisateurs non techniques
Toute la sophistication technique décrite ci dessus reste invisible pour l'utilisateur final. L'interface se limite volontairement à quatre écrans, connexion, nouvelle campagne, historique et paramètres, avec un parcours de création de campagne réduit au strict minimum : choix du canal, sélection des classes concernées, rédaction du message, confirmation, envoi.
C'est un principe que nous appliquons à chaque développement d'application métier sur mesure : la complexité technique doit rester du côté du code, jamais du côté de l'utilisateur.