SMS et WhatsApp (Twilio)
Extension payante. Trois messages transactionnels : la confirmation d’une soumission, celle d’un créneau réservé, et le lien de reprise d’un formulaire abandonné. Par SMS, ou par WhatsApp avec un modèle approuvé.
Ce document décrit ce que le module garantit et ce qu’il refuse. Le guide utilisateur en donne la version courte, dans la section « Envoyer un SMS ou un WhatsApp ».
Ce module ne fait pas de campagnes, et ne peut pas en faire
Les trois déclencheurs naissent chacun d’un geste de la personne : elle soumet, elle réserve, elle demande un lien. Il n’existe nulle part un écran, une action groupée ou une route qui enverrait à plusieurs personnes à la fois.
Ce n’est pas un oubli de la V1. Un SMS non sollicité coûte à celui qui le reçoit ; dans l’essentiel des pays où ce plugin sera employé, l’envoyer sans consentement préalable est une infraction, et elle se poursuit contre l’éditeur du site.
Le consentement n’est pas le même selon ce qu’on envoie
| Nature | Ce qu’il faut |
|---|---|
| Transactionnel | rien de plus : le consentement est dans le geste, et le numéro vient de la personne qui l’a tapé |
| Marketing | une case cochée, désignée dans le réglage ; sans elle, rien ne part |
Un réglage marketing sans case désignée n’envoie rien non plus, et le dit :
l’écran de diagnostic affiche no_consent_field, pour qu’on cherche un champ
manquant et non une panne.
L’opposition passe avant tout
Qui a répondu STOP ne reçoit plus rien, y compris s’il coche une case le lendemain. L’opposition est plus récente et plus coûteuse à exprimer qu’un consentement : cocher demande une seconde, répondre STOP demande d’avoir reçu un message dont on ne voulait pas.
La liste n’est pas lisible, et c’est le point
Elle ne contient que des empreintes — jamais les numéros. Comparer suffit à ce qu’une opposition demande : savoir si ce numéro-là en fait partie.
Une liste d’opposition affichée serait une liste de numéros valides, classée par date, exportable d’un copier-coller : exactement ce qu’elle refuse d’être. L’écran permet donc de vérifier un numéro, d’en ajouter un, d’en retirer un. Il ne permet pas de la parcourir, parce qu’il n’y a rien à parcourir.
Twilio nous apprend les STOP, et nous les gardons
Le module ne lit aucune réponse — le plan l’exclut, et lire les réponses
demanderait un point d’entrée public que rien d’autre ne justifie. Il l’apprend
par le code 21610 que Twilio rend quand il refuse de délivrer, et il inscrit
alors le destinataire dans la liste locale : sans quoi chaque soumission suivante
relancerait un envoi refusé, et l’opérateur compterait ces tentatives.
La liste survit à l’effacement des soumissions. L’effacer reviendrait à réécrire à qui a dit STOP.
Le numéro, et le zéro qui coûte un message
Twilio n’accepte que le format E.164 : +33612345678. Personne ne saisit cela —
on reçoit 06 12 34 56 78, +33 (0)6 12 34 56 78, 0033612345678.
Le piège est le zéro initial. En France, au Royaume-Uni, en Belgique et ailleurs,
il ne fait pas partie du numéro international : +330612345678 part sans erreur
visible et n’arrive jamais. Il est donc retiré — y compris dans la forme
+33 (0)6 …, celle dont les entreprises impriment leurs numéros —, sauf là
où il appartient au numéro, comme en Italie.
Ce qui ne peut pas être mis en forme est refusé, jamais complété : compléter un numéro national sans savoir de quel pays il vient enverrait un message à un inconnu ailleurs. Le pays par défaut d’un formulaire sert à cela, et à cela seulement — un numéro saisi en international s’en passe.
Le module ne vérifie pas qu’un numéro existe, ni qu’il est mobile. Cela demanderait la base de numérotation de chaque opérateur, que Twilio a et que nous n’avons pas ; son refus est journalisé avec son code.
Trois messages par heure et par destinataire
Quelle que soit la raison, et sans réglage pour l’augmenter. C’est la seule protection contre un formulaire soumis en boucle — par un robot, ou par quelqu’un qui recharge — et un réglage qui protège de soi-même finit désactivé.
Trois suffisent à un parcours réel : une confirmation, un créneau, un lien de reprise dans la même heure. Au-delà, ce n’est plus un parcours.
La limite compte ce qui est parti, pas ce qui a été tenté : un service en panne ne doit pas finir par interdire les envois suivants.
Un message, une fois
UNIQUE (soumission, déclencheur) : une soumission ne reçoit pas deux fois sa
confirmation, et reçoit tout de même son rappel de réservation. Un courriel en
double se pardonne ; un SMS en double est facturé, arrive sur un téléphone, et
compte dans ce que l’opérateur considère comme du harcèlement.
La prise de ligne — UPDATE … WHERE state NOT IN ('sent','blocked') — décide qui
envoie quand deux tâches se croisent, ce qui arrive dès qu’un envoi dépasse
l’intervalle de reprise.
Le texte, et ce qu’il coûte
Les jetons de fusion sont ceux des courriels : {field:identifiant}. Les champs
sensibles ne s’y résolvent pas — mot de passe, paiement, fichier, signature —
comme pour toutes les sorties du plugin.
{all_fields} est neutralisé : dans un SMS, il produirait un message de plusieurs
segments, facturé autant de fois, et recopierait dans un réseau d’opérateurs des
valeurs que personne n’a décidé d’y mettre.
L’alphabet à sept bits n’est pas celui qu’on croit
Un SMS se facture par segment : 160 caractères, ou 70 dès qu’un seul caractère sort de l’alphabet GSM. « é » et « à » en font partie ; « ç », « œ » et l’apostrophe typographique « ’ » non — et cette dernière, les traitements de texte la substituent à l’apostrophe droite sans le dire.
Le panneau compte donc les segments pendant qu’on écrit : « Merci, votre demande est bien enregistrée » tient en un segment ; la même phrase avec une apostrophe typographique en coûte deux.
Trop long : refusé, pas tronqué
Tronquer un message transactionnel coupe ce qui se trouve à la fin, c’est-à-dire le lien de reprise ou l’heure du rendez-vous. La personne reçoit alors un message complet en apparence et inutile en fait, et personne ne s’en aperçoit. Un refus, lui, se voit à l’écran de diagnostic, avec la longueur.
WhatsApp n’accepte que des modèles approuvés
Hors fenêtre de conversation, un message WhatsApp ne peut employer qu’un modèle validé par Meta, désigné par son identifiant de contenu. Un texte libre est refusé — et quand il ne l’est pas, c’est que la fenêtre est ouverte, ce que le module ne peut pas savoir puisqu’il ne lit aucune réponse.
Il exige donc toujours un modèle : la seule voie qui marche à tous les coups. Le texte vit chez Meta ; le module ne fournit que les variables, numérotées à partir de 1 comme Meta l’attend.
Les échecs, et lesquels se rejouent
| Motif | Rejoué |
|---|---|
21211, 21214, 21614 — numéro invalide ou incapable de recevoir | non |
21408, 21265 — pays non autorisé sur ce compte | non |
21610 — la personne a répondu STOP | non, et elle est inscrite à l’opposition |
21617 — corps trop long | non |
63016, 63018 — WhatsApp hors modèle approuvé | non |
401, 403 — jeton refusé | non : cela se corrige à l’écran du compte |
429, 5xx, réseau coupé | oui — 1, 5 puis 30 minutes |
« Bloqué » et « échoué » ne disent pas la même chose. Bloqué : rien n’a été tenté — consentement absent, opposition, numéro illisible, plafond horaire ; il y a un réglage à corriger, ou rien à faire. Échoué : Twilio a refusé ou n’a pas répondu. Confondre les deux envoie chercher une panne là où il y a une case non cochée.
« Accepté », et non « reçu »
Twilio prend le message en charge ; l’opérateur le délivre, ou non. Le module ne lit pas les accusés de remise, et appeler cela « délivré » serait affirmer ce qu’on ne sait pas.
Ce que le journal ne contient pas
Ni le numéro, ni le texte du message. Le journal des envois est conservé bien après la soumission ; il consigne l’adresse de l’API, le code de retour et la réponse de Twilio.
La table des envois, elle, ne porte qu’une empreinte du destinataire : sans quoi elle serait un fichier de contacts avec l’horodatage de chaque message reçu.
Renvoyer
Le détail de la soumission porte un bouton par déclencheur. Renvoyer coûte un message — c’est la différence avec les autres renvois du plugin, qui corrigent une fiche dans un CRM.
Les contrôles ne sont pas contournés : la ligne repasse par l’opposition, le consentement et le plafond horaire. Un bouton qui permettrait de forcer l’envoi à quelqu’un qui a dit STOP n’aurait aucune raison d’exister.
Les deux évènements ajoutés aux autres modules
Réservation et reprise vivent ailleurs, et n’émettaient rien. Ils émettent désormais chacun un évènement public :
solis_forms_pro_booking_reserved( $entry_id, $form_id, $creneau );solis_forms_pro_recovery_reminded( $entry_id, $form_id ).
Le second n’est émis que si le courriel de relance est bien parti : doubler d’un SMS une relance qui a échoué enverrait un rappel sans le lien qu’il annonce.
Aller lire les tables de ces modules depuis celui-ci aurait lié deux extensions payantes que rien ne garantit activées ensemble.
Schéma
slf_twilio_messages : une ligne par soumission et par déclencheur, avec son
état, son identifiant Twilio, l’empreinte du destinataire et le motif du dernier
problème.
slf_twilio_optouts : une ligne par empreinte opposée, avec sa source — saisie en
administration, ou refus de Twilio.
Le compte vit dans une option, jeton chiffré.
Ce que la V1 ne fait pas
Pas de conversation bidirectionnelle, pas de lecture des réponses, pas de vérification par code à usage unique, pas de campagne, et pas de message WhatsApp hors modèle approuvé. Le plan le bornait ainsi.
