WebBlocks Campaigns

Exigences

Version du package documentée : 0.7.0. WebBlocks CMS ^1.45.5 ; PHP >=8.3.

A WebBlocks CMS plugin pour envoyer un e-mail modèle à votre propre liste de clients, avec le nom, l'adresse et d'autres champs remplis par destinataire.

Le consentement est enregistré par canal. Les messages marketing et opérationnels sont des choses différentes : quelqu'un qui se désinscrit de la publicité doit toujours recevoir "votre facture est due", donc un seul signalement forcerait à choisir entre envoyer du spam aux personnes qui se sont désabonnées et retenir les messages dont ils ont besoin.

Chaque contact enregistre pourquoi sur lequel il peut être écrit - la base, d'où il vient, quand et pour le consentement explicite, la formulation exacte convenue. Une importation enregistre la même chose sur elle-même, donc « pourquoi cette adresse est-elle ici » a une réponse un an plus tard.

Le registre de suppression est une table à part entière, saisie par adresse plutôt que par contact, et aucune importation n'y touche jamais. C'est ce qui rend cette séquence sécurisée : quelqu'un se désabonne, l'opérateur efface ensuite la liste et réimporte le tableur d'origine, et la personne désabonnéene fait pasrevenir. Publier une adresse est la seule issue, et c’est délibéré.

Le consentement n'est augmenté que par une importation, jamais diminué : un retrait survit à une réimportation et une importation d'un client existant ne déclasse pas quelqu'un déjà avec son consentement explicite.

Importation

Télécharger, cartographier, prévisualiser, valider. Rien n'est écrit jusqu'à la dernière étape, et chaque ligne rejetée est signalée avec son numéro de ligne dans le fichier source afin que l'opérateur corrige la feuille de calcul plutôt que de deviner ce qui a été supprimé.

Les fichiers séparés par des points-virgules et une nomenclature UTF-8 sont lus sans problème, car c'est ce que produisent les exportations de feuilles de calcul allemandes et turques. Un mappage de colonnes est suggéré et jamais appliqué seul : une supposition qui mappe les noms sur le champ de courrier électronique est pire que pas de supposition, car il semble que cela ait fonctionné.

Une cellule vide est une absence, pas une valeur. Une réimportation comble les lacunes et n’efface pas ce qui existe déjà.

Ecriture d'un modèle

{{ first_name }} prend la valeur. {{ first_name | Kunde }} indique ce qui apparaît lorsqu'il est manquant — ce qui constitue la différence entre « Hallo Ada » et « Hallo », la façon dont un publipostage est mémorisé.

Les valeurs fusionnées sont échappées dans HTML ; le modèle ne l’est pas. Le modèle est le vôtre, les valeurs proviennent d'une feuille de calcul.

Deux éléments sont vérifiés avant de pouvoir envoyer un test :

  • An blocs de champ inconnus. {{ firstname }} où le champ est first_name est rendu vide pour le destinataire every et semble parfaitement bien dans l'éditeur. Les champs disponibles sont dérivés des contacts que vous avez réellement importés, la faute de frappe est donc détectable.
  • A avertit que la solution de repli manque. Il s'agit d'un jugement, pas d'une erreur — "Hallo" sans nom est parfois tout à fait exact.

L'aperçu s'appuie sur un contact réel plutôt que sur des données inventées, car les données inventées sont toujours bien formées et ne prouvent donc rien. Un envoi test fournit les chaînes déjà rendues. Ce qui arrive est donc ce qu'une campagne enverrait, avec le préfixe [TEST].

Envoi

A associe un modèle à une liste et déclare de quel type de message il s'agit :

  • Commercialc'est de la publicité. Il atteint uniquement les contacts dont le consentement autorise la publicité, et son modèledoitcontenir{{ unsubscribe_url }}— la file d'attente est refusée dans le cas contraire.
  • Opérationnelconcerne un contrat existant. Il ne s’agit pas de publicité, donc une désinscription marketing ne la retient pas et ne nécessite aucun lien de désabonnement.

Queuing n'envoie pas. Il matérialise l'ensemble des destinataires : un envoi prend des heures, et le dériver de la liste à mi-exécution permettrait à une modification de changer silencieusement à qui est écrit. Ensuite cron fait le travail :

php artisan webblocks-campaigns:dispatch

Each exécution envoie un lot par campagne, limité par la taille du lot par site et le plafond horaire. C'est là le point important : un envoi groupé effectué via le SMTP d'un hôte partagé est la façon dont un domaine d'envoi est bloqué, et cela prend des mois à annuler.

L'instantané n'est pas fiable. La suppression et le consentement sont revérifiés pour chaque destinataire au moment de l'envoi, de sorte qu'une personne qui se désabonne une heure après une course de deux heures ne reçoit pas le reste. La pause est relue entre les lots et arrête immédiatement l'exécution.

Désabonnement

Chaque message commercial comporte un lien construit à partir d'un jeton par destinataire, de sorte qu'un opt-out enregistre la campagne qui l'a déclenché. L'en-tête List-Unsubscribe est également défini, car son absence est l'un des signaux qui trie le courrier en masse en spam.

Le GET affiche une page de confirmation et le POST fait le travail : les clients de messagerie et les dispositifs de sécurité suivent les liens sans invite, donc agir sur GET désabonnerait les personnes qui n'ont jamais cliqué. Un deuxième clic indique "vous êtes désabonné" plutôt que d'échouer.

List-Unsubscribe-Post (un clic) est délibérément annoncé comme not : il demande au client de POST sans jeton CSRF, ce que le CMS rejette avec un 419. Réclamer une fonctionnalité qui échoue est pire que de ne pas la revendiquer.

Un désabonnement écrit deux enregistrements : une suppression, qui est absolue et survit à une réimportation, et un retrait de consentement sur le contact, qui est ce qu'un opérateur voit et qui prouve que le site s'est arrêté lorsqu'on lui a demandé.

Lecture du résultat

Le journal d'envoi répertorie chaque destinataire avec son statut et la raison qui le sous-tend, filtrable. Au-dessus, les raisons de saut et d'échec sont regroupées : « 412 ignorés » n'est pas exploitable, tandis que « 390 supprimés, 22 consentements retirés » est soit une réassurance, soit une tâche.

Les échecs peuvent être réessayés ; les sauts ne le peuvent pas. Un saut était une décision, et réessayer serait soit de le répéter, soit de l'ignorer - la seconde est la façon dont une personne qui s'est désabonnée reçoit à nouveau du courrier. Les destinataires réessayés sont soumis aux mêmes contrôles de consentement et de suppression que tout le monde.

Settings

Par site : taille du lot, plafond horaire, nom et adresse de l'expéditeur, réponse. Les plafonds sont la raison pour laquelle le traitement par lots existe : un envoi groupé effectué via le SMTP d'un hôte partagé est la façon dont un domaine d'envoi est bloqué, et cela prend des mois à annuler. L'écran indique également clairement quand le courrier sortant est inutilisable, afin qu'une campagne pleine de sauts ne soit pas confondue avec un bug.

Rebonds

Les rejets sont classés de trois manières, et un seul d'entre eux supprime :

Moyens

Supprime

Adresse morte

« aucun utilisateur de ce type », « domaine introuvable »

YOui, immédiatement

Temporaire

boîte aux lettres pleine, liste grise, débit limité

Uniquement après des échecs répétés

Refusé par le récepteur

spam, stratégie, SPF/DKIM/DMARC, relais refusé

Jamais

La troisième ligne est le point central de toute la fonctionnalité. Ces refus arrivent avec des codes 5xx permanents et semblent identiques à une boîte aux lettres morte, mais ils concernent l'envoi de votre, pas le destinataire. Les supprimer supprimerait les clients valides en raison d’un défaut de réputation ou de configuration – en silence, une campagne à la fois. Les cas ambigus se résolvent en faveur de la non-suppression : conserver une adresse morte coûte un rebond, supprimer une adresse active coûte un client.

La classification se produit au moment de l'envoi suite à l'échec SMTP. Elle ne nécessite donc aucun webhook, aucune boîte aux lettres de chemin de retour et aucune intégration de fournisseur : elle fonctionne avec le transport que le site utilise déjà.

Chaque rejet est conservé comme historique, et pas seulement comme une suppression. Une suppression ne peut pas dire pourquoi ni à quelle fréquence, et une série de refus du récepteur est invisible sans elle. L'écran Problèmes de livraison vous avertit lorsque ce modèle apparaît et indique ce qu'il faut vérifier.

Installer

composer plugin:build

Ensuite, installez l'artefact via System → Plugins dans l'administrateur du CMS. Installation des plugins désactivée ; activer explicitement après avoir examiné.

Congrès

handle              webblocks-campaigns
settings namespace  webblocks_campaigns
database prefix     webblocks_campaigns_
admin routes        /webadmin/plugins/webblocks-campaigns
public routes       /plugins/webblocks-campaigns
route names         webblocks.plugins.webblocks_campaigns.*
permissions         webblocks-campaigns.view, .manage, .send, .settings

send est volontairement distinct de manage : éditer un brouillon et le transmettre à deux mille personnes sont des actes différents, et une organisation devrait pouvoir accorder l'un sans l'autre.

Collectez des abonnés avec le double opt-in

Ajoutez le bloc d'inscription à une page et choisissez la liste cible, le titre, l'introduction, le libellé de consentement et le champ de nom facultatif. Une demande crée un abonnement en attente. Le destinataire doit utiliser le lien de confirmation envoyé par e-mail et confirmer avant que l'adresse ne puisse être envoyée. Les liens de confirmation expirent après sept jours.

Le plugin enregistre le libellé de consentement affiché lors de l'inscription. Une confirmation peut lever un désabonnement ou un rebond définitif ; il n'annule pas une plainte pour spam ou un blocage manuel de l'opérateur. Les noms de contacts existants sont conservés.