J'ai créé ma newsletter cette semaine et je vous partage aujourd'hui les outils et automatisations qui me permettent de le faire sans que ça ne me coûte un euro.
Et reçois un max de valeur Gratuitement !
On utilise aujourd'hui principalement 3 outils :
- Ghost : Le logiciel léger qui fait tourner mon blog -> Créer son blog avec Ghost
- Resend : Un service d'emailing orienté développeurs avec un plan gratuit très généreux.
- N8N : Mon logiciel d'automatisations favori -> Installer N8N vous pouvez sinon créer un compte gratuit sur leur site.
Créer votre compte Resend
Commençons pas créer un compte, ça se passe ici !
Pour ma part j'utilise la connexion avec Google, c'est vraiment trop pratique...
Configurer votre nom de domaine
Pour envoyer des emails, il nous fait une nom de domaine, par exemple pour moi le nom est timotion.fr
afin d'envoyer des emails avec contact@timotion.fr
. J'aurais également pu choisir timtiret.com
ou autres...
Si vous avez déjà un blog à priori, vous disposez d'un nom de domaine. Connectez-vous donc (dans un nouvel onglet) sur l'interface proposée par le vendeur de ce nom. Vous devriez voir un endroit vous permettant de configurer le DNS
ou Zone DNS
.
184.128.11.161
...Vous avez trouvé ? C'est parfait ! Revenons dans l'onglet Resend dans la catégorie Domains
puis cliquons sur + Add Domain
.
Écrivez dans le champ Name
le nom de domaine choisi et cliquez à nouveau sur + Add Domain
.
Un nouvelle page s'affiche avec des informations qui peuvent faire peur, mais ne vous en faites pas, rien de sorcier. Vous allez devoir passer de la page de votre hébergeur (ou registraire) à Resend régulièrement, je vous invite donc à ouvrir les deux à côté.
Le tableau affiché par Resend vous invite simplement à créer un enregistrement par ligne dans votre DNS, plutôt simple non ?
Commencez par copier dans la colonne Host / Name
le contenu de la première ligne, on voit que c'est un enregistrement de type MX
et il y a une valeur et une priorité de 10
.
Chez votre registraire, vous avez certainement la possibilité de créer un enregistrement, faites le avec donc un enregistrement de type MX
, le nom que vous venez de copier, la priorité de 10 et pour la valeur...Retournez sur Resend pour copier à nouveau la valeur qu'il vous manquait, collez là chez votre hébergeur et ajoutez l'enregistrement.
C'est exactement la même chose pour les 3 enregistrements qui suivent...
Une fois ceci fait, cliquez dans Resend sur I've added the records
. Vous devriez ensuite voir une page où Resend vous montre qu'il vérifie ces enregistrements, nous allons pouvoir passer à l'étape suivante.
Créer un Webhook sur N8N
Le but est de créer un lien sur lequel Ghost va pouvoir envoyer une requête à chaque modification sur un membre, par exemple quelqu'un qui s'inscrit, modifie son nom, ou se désinscrit des emails.
Le logiciel d'automatisations N8N va recevoir les modifications de la part de Ghost, puis les transmettre à Resend, et inversement lorsque quelqu'un se désinscris via un lien dans un email envoyé avec Resend, nous allons faire en sorte qu'il envoie les informations nécessaires à N8N, pour que lui-même les applique également sur Ghost.
Dans N8N créez un nouveau workflow. Pour créer votre premier bloc, cliquez sur le +
et sélectionnez On webhook call
. Un fenêtre s'ouvre, changez donc la HTTP Method
de GET
à POST
, cliquez ensuite sur l'onglet Production URL
, puis sur le lien qui s'affiche juste en dessous. Vous pouvez à présent fermer ce gros popup en cliquant en dehors ou bien en haut à gauche sur Back to canvas
.
Vous pouvez maintenant cliquer sur le bouton orange Save
en haut à droite et activer le workflow avec le switch juste à gauche où il est pour l'instant écrit Inactive
.
Faire pointer l'évènement Ghost sur le Webhook N8N
Connectez-vous à présent sur votre Panel Admin Ghost (<votre-nom-de-domaine>/ghost
) et dirigez vous dans les paramètres, section Advanced
, menu Integrations
.
En haut à droite du petit panneau, cliquez sur Add custom integration
.
Donnez-lui un petit nom, par exemple N8N -> Resend
, puis cliquez sur Add
.
Dans le modal qui s'est ouvert, en bas apparaît un lien en vert Add webhook
, cliquez dessus.
Dans le nouveau modal, vous pouvez nommer ce webhook, par exemple Member Update
, sélectionner un évènement, celui qui nous intéresse est tout en bas dans la liste : Member updated
. Dans Target URL
, collez le lien que nous venons de créer sur N8N et vous pouvez finir par cliquer sur Add
, puis Save
.
Et voilà ! 🎉 Maintenant, chaque fois qu'un membre est créé ou modifié, Ghost envoie l'information à N8N. Testons cela !
Rendez-vous sur votre blog, et créez un nouveau membre avec une adresse mail qui n'existe pas encore dedans.
Sur N8N, dans l'onglet Executions
vous devriez voir qu'il s'est passé quelque chose dans la colonne de gauche qui contient les exécutions. Notre node Webhook
créé précédemment s'affiche maintenant en vert car il contient des données, cliquez en haut à droite sur Copy to editor
.
Votre node apparaît maintenant en violet dans l'éditeur car il contient des données épinglées, celles qui nous ont été envoyées par Ghost lors de l'ajout du membre. En cliquant dessus, on peut visualiser dans la colonne de droite les données dans body>member>current
, on voit que l'on a notamment l'email, le nom et le statut de souscription (subscribed
). Fermons ce modal et passons à l'étape suivante.
Créer une clé API Resend
Pour avertir Resend des informations envoyées par Ghost, nous allons devoir connecter N8N et Resend. Pour cela, nous avons besoin d'une sorte de mot de passe que l'on appelle dans le jargon "Clé API" ou "API Key" en anglais.
Rendez-vous donc sur Resend, dans l'onglet API Keys
. Faites ensuite Create API Key
, puis nommez là, par exemple N8N -> Ghost
, enfin, cliquez sur Add
. Copiez maintenant la clé grâce au petit bouton tout à droite du champ qui est apparu.
Créer une requête HTTP sur N8N
Dans N8N, nous allons maintenant créer une requête et l'authentifier à l'aide de notre clé API pour communiquer les informations qui nous ont été transmises par Ghost à Resend.
Cliquez donc sur le petit +
à droite de votre Webhook pour déclencher à la suite de la réception automatiquement une requête HTTP, tapez donc HTTP
dans la barre qui s'est affichée sur le panneau à droite et cliquez sur l'icône Internet bleue (HTTP Request
).
Vous pouvez d'ores et déjà sélectionner la méthode POST
, puis dans Authentification
sélectionnez Generic Credential Type
, puis dans Generic Auth Type
sélectionnez Header Auth
. Enfin, dans Header Auth
sélectionnez Create new credential
.
Dans le champ Value
, vous pouvez directement écrire Bearer
, puis après un espace, coller votre clé API. Dans name, vous aurez besoin d'écrire Authorization
et puis si vous le souhaiter vous pouvez nommer cette authentification en cliquant en haut à gauche sur le nom par défaut : Header Auth Account
, pour me part je mets par exemple Resend timotion.fr
.
Vous pouvez à présent cliquer sur le bouton orange Save
pour enregistrer.
À présent, nous allons chercher quelle requête faire dans Resend, l'idée est de créer ou mettre à jour un contact, rendez-vous donc sur l'onglet Audiences
de Resend qui est l'endroit où nous ajoutons nos contacts. Resend propose quasiment à chaque fois un petit bouton API
qui permet de visualiser facilement quelles requêtes sont possibles sur une certaine entité, en l'occurence : l'audience générale.
Dans le panneau qui s'affiche maintenant à droite je vois que le premier bout de code me propose d'ajouter un contact, ça tombe bien c'est justement ce que je souhaite faire. Je clique alors sur cURL
pour voir la requête en entier.
curl -X POST 'https://api.resend.com/audiences/14a40358-c464-468a-abcc-e09ae18b84f0/contacts' \
-H 'Authorization: Bearer re_123456789' \
-H 'Content-Type: application/json' \
-d $'{
"email": "steve.wozniak@gmail.com",
"first_name": "Steve",
"last_name": "Wozniak",
"unsubscribed": false
}'
Je vois que c'est une requête avec la méthode POST
et qu'elle utilise une authentification avec jeton "Bearer", mais ce qui m'intéresse ici c'est surtout l'URL de la requête que je n'ai pas encore configurée dans N8N :
https://api.resend.com/audiences/14a40358-c464-468a-abcc-e09ae18b84f0/contacts
Et également son contenu :
{
"email": "steve.wozniak@gmail.com",
"first_name": "Steve",
"last_name": "Wozniak",
"unsubscribed": false
}
Voilà, nous pouvons dès à présent coller le lien dans le champ URL
de N8N et puis pour le contenu, nous allons activer le switch Send Body
, dans Specify Body
je sélectionne Using JSON
et puis juste en dessous je colle le contenu de ma requête.
Nous allons pour finir intégrer les variables fournies par Ghost dans le Webhook au contenu de ma requête pour que ce ne soit pas à chaque fois Steve Wozniak mais bien la personne qui a effectué une action !
Pour cela, je passe en mode expression
et en bas à droite du champ éditeur de JSON
, un bouton permet de passer en mode plein écran pour plus de clarté. Ensuite, je remplace les valeurs par défaut par mes variables en les glissant depuis les informations d'entrée à gauche et je retire le last_name
car Ghost ne fournit qu'un nom. J'obtiens quelque chose comme cela :
{
"email": "{{ $json.body.member.current.email }}",
"first_name": "{{ $json.body.member.current.name }}",
"unsubscribed": {{ !$json.body.member.current.subscribed }}
}
unsubscibed
alors que celui envoyé par Ghost se nomme subscribed
. Il faut donc inverser la valeur pour mettre true
quand c'est false
et inversement. Raison pour laquelle j'ai mis un point d'exclamation devant ma variable qui signifie non
en programmation et qui permet d'inverser, si c'est non vrai, alors c'est faux. Si mon abonné n'est pas désabonné, c'est qu'il est abonné... 🤪Transformé par N8N en cela :
{
"email": "contact@timotion.fr",
"first_name": "Tim",
"unsubscribed": false
}
Par ailleurs n'oubliez pas les double guillemets ("
) autour de l'email
et du first_name
car c'est comme cela que l'on représente une chaîne de caractères (un texte) dans le format JSON
.
Une fois que c'est tout bon, l'on peut fermer le mode plein écran, retourner sur notre canva et puis enregistrer.
Requête PATCH en cas de désinscription
Ce que nous venons de faire fonctionne bien pour créer le contact en cas d'inscription et modifier son nom lorsque c'est nécessaire mais - ne me demandez pas pourquoi - : si l'utilisateur existe déjà et qu'il se désinscrit, N8N envoie bien la même requête avec unsubscribe : true
, mais ça ne met pas à jour le statut d'abonnement du contact dans Resend, bizarre sachant que ça fonctionne pour le nom mais c'est comme ça, nous allons devoir envoyer une deuxième requête.
Le plus simple est de dupliquer notre première requête pour ne pas devoir tout refaire de zéro. Pour cela, faisons clique droit sur la première requête, puis Duplicate
et on relie la sortie du noeud précédent à l'entrée du suivant en glissant depuis la poignée à droite de la première requête vers celle d'entrée de la suivante.
Nous avons 3 petites modifications à effectuer à présent.
Déjà, la méthode n'est plus POST mais PATCH (c'est une correction / mise à jour, pas une création).
Ensuite derrière l'URL de la requête j'ajoute un slash et l'email du contact, ça donne quelque-chose comme cela :
https://api.resend.com/audiences/9ae3f7c2-6f0e-4b8f-8103-70b2a428b2a4/contacts/{{ $('Webhook').item.json.body.member.current.email }}
transformé par N8N en cela :
https://api.resend.com/audiences/9ae3f7c2-6f0e-4b8f-8103-70b2a428b2a4/contacts/contact@timotion.fr
/
et {{
.Pour finir, dans le contenu, je ne mets que le champ unsubscribe
, et je glisse à nouveau la variable qui doit être mise à jour comme nous ne somme plus dans le même noeud.
{
"unsubscribed": {{ !$('Webhook').item.json.body.member.current.subscribed }}
}
Toujours, je n'oublie pas le point d'exclamation pour obtenir l'inverse de ce que nous propose Ghost, N8N transforme donc mon JSON en cela :
{
"unsubscribed": false
}
Normalement c'est tout bon ! Enregistrez et testez, lorsqu'un utilisateur active ou désactive sa newsletter ou encore change son nom sur Ghost, la mise à jour est automatiquement faite sur Resend. 🎉
Synchronisation Resend vers Ghost
Lorsqu'une modification est faite sur Ghost, elle est transmise à Resend, maintenant j'aimerais que cela fonctionne aussi dans l'autre sens, c'est à dire que lorsque quelqu'un clique sur un lien de désinscription envoyé via Resend, la modification soit répercutée automatiquement dans Ghost.
Webhook de Resend vers N8N
Créez donc un nouveau workflow sur N8N comme tout à l'heure avec un Webhook, la méthode POST, puis copiez l'URL de production, enregistrez et activez le workflow.
On va maintenant retourner sur Resend pour ajouter notre Webhook dans l'onglet Webhooks.
Cliquez donc sur Add webhook
, puis dans le modal qui s'ouvre, on colle l'URL fournie par N8N. L'évènement qui nous intéresse est contact.updated
, on le coche donc et on finit par cliquer sur Add
.
Ça y est ! 🎉 Normalement lorsque l'on modifie un contact (ou qu'il se désabonne), on reçoit le Webhook sur N8N et cela provoque une exécution.
On peut tester en se rendant dans l'onglet Audiences
, puis sur la fiche d'un contact et dans les trois petits points en haut à droite à côté du bouton API, en cliquant sur Edit Contact
on peut par exemple décocher le slider d'inscription (Subscribed
), puis cliquer sur Save
.
De retour dans N8N, l'exécution s'est effectivement produite, en regardant les informations envoyées je vois bien mon "unsubscribed" : true
ainsi que l'email
et le first_name
, c'est parfait je vais pouvoir mettre à jour Ghost.
Éditer le membre Ghost depuis N8N
Pour modifier un contact avec l'API Admin Ghost, il faut d'abord récupérer son ID
. On va donc faire une recherche avec le champ email
de notre membre, puis dès que l'on a son ID
, on peut mettre à jour le membre.
En pratique, on copie les données de la dernière exécution dans l'éditeur avec le bouton Copy to editor
, puis, on crée un nouveau node avec une requête HTTP.
Dans le sélecteur d'authentification, on sélectionne Predefined Credential Type
, puis dans le sélecteur Credential Type
, on tape ghost
, puis on sélectionne Ghost Admin API
. Ensuite dans Ghost Admin API
, on clique sur Create new credential
et c'est là qu'il faut aller copier des informations dans la partie intégrations custom de Ghost, là où l'on avait créé notre premier Webhook.
Quand on retrouve et que l'on clique sur l'intégration (je l'avais personnellement appelée N8N -> Resend
), on a des informations qui s'affichent et notamment notre API URL
(qui est tout simplement le nom de domaine associé à notre blog) et Admin API key
dont l'on va avoir besoin tout de suite.
Renseignez donc dans N8N l'API URL
, et l'Admin API key
donnés par Ghost, et je vous conseille de renommer la connexion en cliquant sur son nom (Ghost Admin account
), pour ma part je mets Ghost Admin timtiret.com
. Ça me permettra si je gère plusieurs sites de les différencier.
Ça y est, l'authentification est enfin faite ! ✅
On va maintenant construire notre première requête. Souvenez vous, on commence par rechercher notre membre et récupérer son ID
, c'est donc une requête avec la méthode GET
. L'URL
est la suivante :
https://<votre-nom-de-domaine>/ghost/api/admin/members
Chez moi ça donne cela :
https://timtiret.com/ghost/api/admin/members
Je rajoute également un filtre sur l'email pour obtenir un truc comme cela :
https://timtiret.com/ghost/api/admin/members/?filter=email:contact@timotion.fr
Dans N8N avec une expression qui récupère les infos dans le Webhook, ça s'écrit comme cela :
https://timtiret.com/ghost/api/admin/members/?filter=email:{{ $json.body.data.email }}
Normalement c'est bon, si je clique sur Test step
, j'obtiens effectivement en sortie mon membre et toutes ses informations (dont son ID
).
Je passe donc à la création de ma dernière requête, pour cela, je duplique la précédente, j'utilise la méthode PUT
et à la place de mon filtre d'email je mets un slash et l'ID de mon membre :
https://timtiret.com/ghost/api/admin/members/{{ $json.members[0].id }}
Il va maintenant falloir que j'ajoute un body. Je coche donc le switch, passe le sélecteur Specify Body
en mode Using JSON
et entre ceci dans le champ :
{
"members": [{
"name" : "{{ $('Webhook').item.json.body.data.first_name }}",
"subscribed" : {{ !$('Webhook').item.json.body.data.unsubscribed }}
}]
}
Plus qu'à tester. Lorsque je passe mon contact Resend de subscribed
à unsubscibed
et que je vais voir dans les préférences d'email du compte que j'ai créé, la répercussion est bien présente, et celle-ci est maintenant bidirectionnelle ! 🎉
Envoyer son premier email (avec l'éditeur Markdown)
Resend propose un éditeur d'email au format Markdown que je trouve top ! Pour y accéder, rendez-vous dans la section Broadcasts
, puis on clique sur Create Broadcast
. Nous y êtes ! 🤪
Dans le champ From
, vous allez pouvoir configurer le nom d'expéditeur et l'email d'envoi :
Le nom que vous voulez <votre-mail@votre-domaine.com>
Ce qui donne pour ma part :
Tim Tiret <contact@timotion.fr>
Dans le champ To
, vous pouvez sélectionner l'audience General
, celle pour laquelle nous venons de configurer la synchronisation.
Le champ Preview
comme son nom l'indique est l'aperçu que les gens voient sur certaines apps de messagerie avant d'ouvrir l'email, vous pouvez le laisser vide, c'est comme vous préférez.
Le sujet, vous connaissez et ce qui est intéressant maintenant c'est l'éditeur Markdown. Celui-ci vous permet d'écrire et de mettre en forme rapidement en utilisant des styles et éléments prédéfinis et minimalistes.
Comme sur Notion, quand vous faites un slash, vous obtenez la liste des éléments disponibles et pouvez alors en sélectionner un.
L'autre façon de créer un élément est d'utiliser le language Markdown qui est un language très simple pour vous assister dans la mise en forme.
Par exemple quand vous mettez un #
, puis un espace devant un texte, il se transforme en titre de niveau 1, plus vous mettez de hashtags devant, plus il sera petit, par exemple si je fais #### Titre 4
, j'aurais un titre de niveau 4. De la même manière si je mets du texte entre étoiles simples il se transforme en *italique*
et entre doubles étoiles en **gras**
. Pour plus de détails au sujet du Markdown, je vous conseille cette page de documentation créée par l'association de logiciels libres Framasoft.
Pour ma part j'ai l'habitude d'utiliser Markdown à la fois dans mon logiciel de prise de notes (Bear) et dans Ghost. C'est pratique parce que je peux facilement copier coller ce que je veux sans incompatibilités entre tous ces outils.
Une fois votre rédaction terminée, vous pouvez envoyer un email de test à l'aide du bouton Test email
, il ne sera alors envoyé qu'aux addresses inscrites dans le popup qui s'affiche juste après. Quand tout est bon pour vous, vous pouvez cliquer sur Send
, Resend vous indique alors le nombre de contacts qui recevrons l'email et vous devez glisser un curseur pour le faire partir, ce que je trouve extrêmement satisfaisant... 😏
Merci pour votre lecture !