Réponses et webhooks
Tout ce que les destinataires renvoient — votes de sondage, soumissions de formulaire, notations, tours de roue — est collecté par projet. Cela vous revient de deux façons : une vue des réponses par destinataire dans le tableau de bord, et un webhook facultatif qui pousse chaque interaction vers votre propre endpoint dès son arrivée.
Réponses par destinataire dans le tableau de bord
Ouvrez Tableau de bord → votre email → Réponses. Chaque interaction que l'email a collectée est regroupée par destinataire et jointe à la source de données du projet. Chaque groupe montre qui a répondu — son adresse email et les autres champs de sa ligne — ainsi que *ce qu'*il a fait : quel bloc, quelle action, les valeurs soumises, et quand.
L'attribution fonctionne via les mêmes jetons signés qui protègent les liens de vue en direct. Lorsqu'un email est personnalisé à partir d'une source de données, les liens de chaque destinataire portent un jeton lié à sa ligne, et les interactions arrivant avec un jeton valide sont attribuées à cette ligne. Les interactions qui arrivent sans jeton (par exemple un vote de sondage provenant d'un email envoyé sans personnalisation) comptent tout de même — elles sont listées dans un groupe Anonyme séparé.
La liste brute des événements est paginée (les plus récents d'abord) : une fois que vous avez chargé la dernière page, une action Charger plus récupère les événements plus anciens. Tout ce qui suit — synthèses, histogrammes, l'entonnoir et la tendance — n'est pas affecté par cette pagination ; c'est précalculé et couvre toujours l'historique complet du projet.
Commandes, traitement et remboursements
Tout projet avec un bloc produit obtient un tableau Commandes sur sa page Réponses — une ligne par paiement, avec l'acheteur, le montant, le statut et l'heure de passation.
- Dès qu'un paiement est validé, l'acheteur reçoit automatiquement un email : le contenu de livraison d'un produit numérique, ou une confirmation qu'une commande physique est en cours de traitement.
- Pour les commandes physiques, cliquez sur Marquer comme traitée une fois que vous l'avez expédiée — MailInApp ne gère pas l'expédition elle-même, mais il envoie bien un avis d'expédition à l'acheteur dès que vous activez le commutateur.
- Cliquez sur Rembourser sur n'importe quelle commande payée pour annuler la charge via votre compte Stripe connecté ; l'acheteur reçoit un email de confirmation de remboursement. Le même email est envoyé automatiquement si une vente se conclut juste au moment où la dernière unité s'épuise — MailInApp rembourse l'acheteur plutôt que de vendre silencieusement au-delà du stock.
- Contacter l'acheteur ouvre un ticket d'assistance prérempli avec le contexte de cette commande — le moyen le plus rapide de demander quelque chose directement à un acheteur.
Métrique principale pilotée par l'objectif
Si un projet a un objectif défini (enquête, promotion, newsletter ou événement), la page Réponses met en avant le chiffre qui compte le plus pour cet objectif : le taux de réponse pour les enquêtes, les destinataires engagés pour les promotions, et les ouvertures suivies pour les newsletters et les événements. Les projets transactionnels et ceux sans objectif défini passent directement à l'entonnoir et aux synthèses ci-dessous. Modifiez ou effacez l'objectif à tout moment depuis le menu déroulant situé à côté du titre de la page ; cela n'affecte que le chiffre mis en avant, jamais ce qui est enregistré.
Synthèses CSAT, CES et NPS
Chaque bloc de notation obtient une synthèse au-dessus de la liste des destinataires : nombre de réponses, moyenne, et un histogramme (la distribution derrière la moyenne — une moyenne de 4,1 cache s'il s'agit de tous des 4 ou d'un partage entre des 5 et des 1). Les blocs de type NPS affichent les nombres de promoteurs/passifs/détracteurs et le score de −100 à 100 au lieu d'une simple moyenne. Une ventilation de distribution des réponses fait de même pour les blocs sondage, par option.
Un entonnoir d'engagement (Envoyé → Ouvert (approx.) → Répondu) se trouve au-dessus des synthèses. Un graphique de tendance des réponses par bloc (par jour ou par semaine) montre la moyenne au fil du temps — la valeur d'une enquête récurrente est la courbe de tendance, pas un seul instantané. Il ne s'affiche qu'une fois qu'un bloc dispose d'au moins deux périodes de données.
Synthèses des questions d'enquête
Chaque bloc formulaire obtient une synthèse par question, de la même façon que les blocs de notation et de sondage. Les questions à choix multiples, cases à cocher, échelle linéaire et notation par étoiles obtiennent un graphique à barres des comptes par option ; les questions en texte libre (texte court, texte long, email, nombre, téléphone, date) obtiennent un nombre de réponses ainsi que quelques exemples de réponses. Les enquêtes multi-pages se synthétisent de façon identique aux enquêtes à page unique — une soumission ne compte qu'une fois que toutes les pages ont été complétées, donc une enquête abandonnée n'apparaît jamais comme une réponse partielle.
Ces résultats de sondage, de notation et de questions d'enquête ne sont pas une impasse — n'importe lequel peut être tracé directement dans un futur email en liant un bloc graphique à « réponse de campagne », sans nouvelle saisie manuelle. Voir Lier des graphiques à des données réelles.
Devoirs et carnet de notes
Chaque bloc devoir ayant au moins une réalisation ou une soumission obtient une carte de statistiques (réalisations, réalisations tardives, soumissions) au-dessus d'un tableau Carnet de notes. Le tableau a une ligne par élève et une colonne par devoir, affichant « Fait » ou la réponse soumise en vert, ou en rouge si elle est arrivée après la date d'échéance du bloc. Les devoirs sans réponse encore n'encombrent pas le tableau. Comme toute autre synthèse, elle est précalculée et couvre l'historique complet d'un projet, et les deux exports CSV incluent une colonne devoir par bloc.
Carte de chaleur des clics
Sous les synthèses, une carte de chaleur des clics classe chaque bloc porteur de lien simple — boutons, images liées, icônes sociales — par nombre de clics, avec une longueur de barre et une intensité proportionnelles au volume relatif. Voir comment les clics sont suivis pour savoir ce qui compte et ce qui ne compte pas.
Entonnoir de profondeur de défilement
Un entonnoir de profondeur de défilement montre quelle part des visiteurs de la vue en direct a atteint chaque jalon de 25/50/75/100 % de la page, afin que vous puissiez voir si les gens abandonnent tôt ou lisent jusqu'au bout. Il ne reflète que les visites de la vue en direct hébergée, pas l'email envoyé lui-même — voir Profondeur de défilement pour comprendre pourquoi.
Test A/B et gagnants automatiques
Envoyer avec plus d'une variante (voir Envoi) ajoute une comparaison des variantes à la page Réponses : taux d'ouverture, taux de clic et taux de réponse côte à côte pour chaque variante, avec le leader actuel signalé selon la métrique utilisée par le test. Chaque destinataire se voit attribuer une variante de façon déterministe à partir de son adresse email, donc les renvois et les nouvelles tentatives ne rebrassent jamais qui a vu quelle variante. Les résultats sont cumulatifs pour le projet, couvrant chaque envoi A/B qu'il a jamais exécuté, pas seulement le plus récent.
Une variante ne se limite pas au libellé de la ligne d'objet ; elle peut aussi changer l'identité de l'expéditeur, ou l'ensemble du contenu du projet. Les propres réponses de sondage/quiz/RSVP et les ouvertures d'une variante à contenu variable sont suivies sur la propre page Réponses de ce projet plutôt que fondues dans cette comparaison, car la validation des interactions lie une soumission au projet exact depuis lequel elle a été rendue. Le panneau de comparaison renvoie vers celui-ci au lieu d'afficher un zéro trompeur.
Choisir un gagnant automatiquement transforme un test A/B manuel en un test qui se déroule tout seul. Choisissez une fraction de test (par ex. envoyer à 20 % de la liste répartis entre les variantes), combien de temps attendre avant de décider, et sur quelle métrique décider : ouverture, clic, réponse dans l'email, ou revenu. La réponse dans l'email (complétion de sondage/quiz/RSVP) est la valeur par défaut recommandée, car elle n'est pas affectée par la Protection de la confidentialité du courrier d'Apple comme peut l'être le suivi des ouvertures.
Une fois le délai d'attente écoulé, MailInApp choisit la variante ayant le meilleur taux par destinataire. Ce n'est jamais un total brut, donc une variante simplement envoyée à plus de personnes dans le test ne peut pas sembler gagnante uniquement par le volume. Le gagnant est envoyé à tous ceux qui ont été retenus lors du test initial. Si le résultat est une égalité ou si l'échantillon était trop petit, MailInApp se rabat sur la variante 1 et l'indique clairement plutôt que de jamais déclarer un faux gagnant. La bannière de statut sur la page Réponses montre exactement dans quel état se trouve un test : encore en décision, décidé, égalité, ou échantillon trop petit.
Optimisation du moment d'envoi
Disponible sur Pro et au-dessus. Au lieu que tout le monde dans un envoi parte en même temps, Envoyer au meilleur moment de chaque destinataire examine l'historique d'ouverture propre à chaque contact — à quelle heure de la journée, en UTC, il a réellement le plus souvent ouvert votre courrier. Le message de ce contact est retenu jusqu'à cette heure. Quiconque n'a pas encore assez d'historique d'ouverture pour disposer d'un signal fiable passe directement par un envoi immédiat ordinaire.
Cela s'applique de la même façon à un envoi manuel, à une programmation récurrente, et à sa propre étape d'envoi dans un parcours ; une programmation envoie tout de même tout le monde sans signal à son heure configurée, conformément au comportement d'avant l'optimisation. Cela ne peut actuellement pas être combiné avec un test de gagnant automatique dans le même envoi, puisqu'un destinataire différé ne serait pas comptabilisé au moment où un gagnant est décidé.
Ventiler par un champ
Utilisez Ventiler par pour regrouper les mêmes synthèses par n'importe quel champ de votre source de données — CSAT moyen par agent, NPS par forfait, etc. Les destinataires dont la ligne a été supprimée ou réduite depuis l'envoi se regroupent sous (inconnu) ; si un champ en texte libre produit plus de 20 valeurs distinctes, les plus petits groupes fusionnent dans un groupe final Autre afin que la vue n'explose pas.
Export CSV
Télécharger le CSV sur la page Réponses exporte un fichier large, une ligne par destinataire : chaque champ de la source de données, l'heure de première ouverture, et une colonne par bloc interactif (avec sa question en en-tête). Les réponses de suivi obtiennent leur propre colonne <question> — follow-up. Un second export d'événements bruts donne une ligne par événement (destinataire, bloc, action, valeur, horodatage) pour les analystes qui préfèrent le format long.
Cycle de vie de l'enquête
Un projet peut avoir une date de clôture et/ou un plafond de réponses (maxResponses). Une fois l'un ou l'autre atteint, les nouveaux événements d'interaction sont rejetés — la vue en direct affiche un avis de clôture au lieu des blocs interactifs, bien que le contenu statique continue de s'afficher — et la page Réponses indique si l'enquête est actuellement close. Rien n'est filtré rétroactivement : les réponses déjà enregistrées restent dans vos données.
Alertes de score faible dans l'application
Au-delà de l'indicateur lowScore du webhook (ci-dessous), un projet peut lister jusqu'à quelques adresses email à notifier directement — sans étape Zapier/Make nécessaire. Chaque fois qu'une réponse de notation franchit le seuil configuré de son bloc, MailInApp envoie un email à ces adresses (via vos propres paramètres SMTP) avec la question, le score, l'identité du destinataire lorsqu'elle est connue, et un lien direct vers la page Réponses. Si aucun relais SMTP n'est configuré, l'alerte est ignorée silencieusement — le webhook se déclenche quand même. Les alertes sont plafonnées par projet par heure afin qu'une salve de scores faibles ne puisse pas saturer votre relais.
Reconstruction des agrégats
Les synthèses, l'entonnoir et la tendance sont servis à partir d'un agrégat précalculé par projet, mis à jour à l'arrivée des événements — afin qu'ils restent rapides quelle que soit la quantité d'historique d'un projet. Si un projet affiche des totaux étonnamment faibles ou nuls, il a probablement collecté des réponses avant que cet agrégat n'existe pour lui ; cliquez une fois sur Reconstruire les agrégats sur sa page Réponses pour rejouer tout son historique d'événements dans l'agrégat. Les nouveaux projets n'en ont jamais besoin.
Webhooks
Si vous préférez que les données arrivent dans vos propres systèmes — un CRM, une feuille de calcul, un outil d'automatisation — configurez un webhook sur la même page Réponses : entrez une URL HTTPS et cliquez sur Activer.
Deux choses se produisent alors :
- Un secret de signature (
whsec_…) vous est affiché — copiez-le immédiatement, il n'est affiché qu'une seule fois. Il est stocké côté serveur et masqué partout ensuite, comme tous les identifiants dans MailInApp. - À partir de là, chaque interaction est envoyée en POST vers votre URL sous forme de JSON, juste après son enregistrement.
Vous pouvez régénérer le secret (un nouveau est créé et affiché une fois) ou supprimer le webhook à tout moment.
Charge utile
{
"type": "interaction.received",
"projectId": "abc123",
"event": {
"campaignId": "abc123",
"blockId": "poll-1",
"blockType": "poll",
"action": "vote",
"value": { "option": "Blue" },
"recipient": "row:3",
"projectId": "abc123",
"receivedAt": 1752480000000
},
"recipient": {
"key": "row:3",
"row": { "email": "[email protected]", "first_name": "Ada" }
},
"lowScore": false
}
event.valueest la donnée collectée elle-même — l'option de sondage choisie, les valeurs des champs du formulaire, le nombre d'étoiles.recipientestnullpour les interactions anonymes. Pour celles attribuées,keyest l'index de ligne du destinataire dans votre source de données ("row:3"= quatrième ligne).recipient.row— la ligne de données complète du destinataire — est incluse pour les sources de données hébergées. Pour les sources de type API, nous n'appelons pas votre endpoint à chaque interaction ; effectuez la jointure sur l'index de ligne de votre côté.lowScoreesttruelorsque l'événement est une actionratesur un bloc de notation dont la valeur est égale ou inférieure au seuil d'alerte configuré de ce bloc — le signal sur lequel une automatisation Zapier/Make (ou votre propre alerte dans l'application) filtre pour avertir un responsable de l'assistance. Il est totalement omis sur les événements autres que de notation, ou lorsque le bloc n'a aucun seuil configuré.
Vérification des signatures
Chaque livraison est signée afin que votre endpoint puisse confirmer qu'elle provient bien de MailInApp. Deux en-têtes sont envoyés :
| En-tête | Contenu |
| --- | --- |
| X-MailInApp-Timestamp | Moment où la livraison a été signée, en millisecondes depuis l'epoch |
| X-MailInApp-Signature | v1= suivi de HMAC-SHA256(secret, timestamp + "." + rawBody) au format hexadécimal |
Calculez la signature attendue à partir du corps brut de la requête (avant tout parsing JSON) et comparez-la avec une comparaison en temps constant. Rejeter les horodatages périmés bloque les livraisons rejouées :
import { createHmac, timingSafeEqual } from "node:crypto";
function isValidDelivery(headers, rawBody, secret) {
const timestamp = headers["x-mailinapp-timestamp"];
const given = Buffer.from(headers["x-mailinapp-signature"] ?? "");
const expected = Buffer.from(
"v1=" +
createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex"),
);
if (given.length !== expected.length || !timingSafeEqual(given, expected)) {
return false;
}
// Reject deliveries signed more than 5 minutes ago (replay protection).
return Math.abs(Date.now() - Number(timestamp)) < 5 * 60 * 1000;
}
Sémantique de livraison
- La première tentative est immédiate, puis relancée automatiquement. Les livraisons expirent après 5 secondes ; tout ce qui n'est pas une réponse
2xx(un délai dépassé, un échec de connexion, ou un statut d'erreur) est traité comme un échec. L'événement est toujours d'abord stocké dans MailInApp, donc une livraison manquée ne perd rien — considérez le webhook comme un signal en temps réel et la vue Réponses comme la source de vérité. - Nouvelles tentatives automatiques avec délai croissant. Une livraison échouée est retentée à intervalles croissants — environ 1 minute, 5 minutes, 30 minutes, 2 heures, puis 6 heures — vers l'URL et le secret actuels de votre webhook, afin qu'un secret régénéré ou une URL mise à jour soit pris en compte automatiquement. Si chaque nouvelle tentative échoue encore, la livraison arrête de se relancer d'elle-même, mais elle n'est jamais abandonnée.
- Renvoi manuel. Toute livraison qui échoue encore (en cours de nouvelle tentative ou épuisée) apparaît sous Livraisons échouées sur la page Réponses, avec la raison du dernier échec et un bouton Renvoyer — utile juste après avoir corrigé ce qui était cassé de votre côté, plutôt que d'attendre la prochaine tentative programmée.
- Jamais sur le chemin du destinataire. Les livraisons se produisent après que l'interaction du destinataire a été confirmée ; un endpoint lent ou cassé ne peut pas retarder ou faire échouer son vote ou sa soumission.
- Répondez vite. Renvoyez un
2xxrapidement et effectuez le traitement lourd de façon asynchrone.
À noter sur la confiance : les endpoints d'interaction sont publics par nécessité (une boîte de réception ne peut pas s'authentifier), donc les événements anonymes ne sont pas authentifiés par conception. Les événements attribués sont protégés par des jetons de destinataire signés. Vérifiez la signature de livraison, et traitez
event.valuecomme une entrée utilisateur.