Aller au contenu

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

NatureCe qu’il faut
Transactionnelrien de plus : le consentement est dans le geste, et le numéro vient de la personne qui l’a tapé
Marketingune 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

MotifRejoué
21211, 21214, 21614 — numéro invalide ou incapable de recevoirnon
21408, 21265 — pays non autorisé sur ce comptenon
21610 — la personne a répondu STOPnon, et elle est inscrite à l’opposition
21617 — corps trop longnon
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.