Templates email

Afficher en Markdown

Messages & notifications

La plateforme écrit à vos destinataires sans que votre application ait à s’en charger : invitation à signer, relance, refus, parapheur terminé… Ces messages sont les vôtres aux yeux du signataire, et ils constituent souvent le premier contact entre votre organisation et lui. Ils se personnalisent entièrement — et, comme indiqué en Positionnement & périmètre, c’est l’une des rares opérations qui ne se font que par l’API.

Cette fondation établit où vivent ces réglages, comment ils se résolvent d’un niveau à l’autre, et ce que vous pouvez écrire dans un gabarit.

Qui envoie ces messages ? La plateforme, avec son propre expéditeur et sa propre infrastructure d’envoi — pas la vôtre. Personnaliser un gabarit change donc le contenu du message, non son adresse d’expédition ni son acheminement. Deux conséquences : vos réglages de délivrabilité (SPF, DKIM, filtres antispam de votre domaine) ne s’appliquent pas à ces notifications, qui bénéficient de ceux de la plateforme ; et les e-mails que votre application envoie de son côté — création de compte, confirmations — restent entièrement à votre charge. Ce sont deux chaînes distinctes.

Une cascade à trois niveaux

Les réglages ne sont pas un objet unique mais une superposition. Chaque niveau ne porte que ce qu’il surcharge ; le résultat effectif se lit à part, sous le nom d’appliedSettings.

NiveauCe que vous lisez / écrivezLe résultat résolu
PlateformeGET /api/defaultSettings — les réglages par défaut, communs à tous les tenants (lecture seule)
TenantGET / PUT /api/tenants/{tenantId}/settings — vos surchargesGET /api/tenants/{tenantId}/appliedSettings = les réglages par défaut surchargés par ceux du tenant
UtilisateurGET / PUT /api/users/{userId}/settings — les surcharges propres à un utilisateurGET /api/users/{userId}/appliedSettings = les réglages du tenant surchargés par ceux de l’utilisateur
ParapheurGET /api/workflows/{workflowId}/settingslecture seule : ce qui s’applique à ce parapheur

Ces réglages par défaut ne sont pas neutres : le Workflow Manager étant multi-tenants (voir Positionnement & périmètre), ils sont définis par Goodflag pour l’ensemble des tenants de la plateforme. Votre tenant vous est livré en mode SaaS avec ces messages-là — déjà rédigés, déjà traduits, immédiatement fonctionnels. Vous ne partez donc jamais d’une page blanche : vous surchargez un existant qui tient debout, et c’est aussi ce qui rend la branche « sinon » d’un gabarit conditionnel sûre à utiliser (voir section Précautions avant d’écrire).

Le piège à connaître. settings et appliedSettings ne répondent pas à la même question. Le premier dit « qu’ai-je surchargé ? » — il peut être quasi vide alors que tout fonctionne. Le second dit « que reçoit réellement mon destinataire ? ». Pour diagnostiquer un message qui ne ressemble pas à ce que vous attendiez, c’est appliedSettings qu’il faut lire, et au niveau pertinent : un réglage d’utilisateur peut expliquer à lui seul un écart que vous cherchiez au niveau du tenant.

Le niveau parapheur est en lecture seule : on ne configure pas les messages parapheur par parapheur. Pour différencier les messages selon le type d’affaire, on s’appuie sur une métadonnée portée par le parapheur et sur un gabarit conditionnel — voir la fondation Métadonnées et les cas d’usage.

Ce que contiennent les réglages

L’essentiel des réglages est constitué des gabarits de message. Chacun se décline par langue (fr, en, et de pour certains), et porte deux champs : subject et content.

Invitations et relances

CléMessage
signatureInviteEmailInvitation à signer.
approbationInviteEmailInvitation à valider.
multiInviteEmailInvitation groupée, lorsque plusieurs sollicitations sont regroupées.
signatureUninviteEmailLa signature n’est plus attendue.
approbationUninviteEmailLa validation n’est plus attendue.

Issue d’une étape

CléMessage
signatureFinishedEmailSignature enregistrée.
approbationFinishedEmailValidation enregistrée.
signatureRefusedEmailSignature refusée.
approbationRefusedEmailValidation refusée.

Cycle de vie du parapheur

CléMessage
workflowStartedEmailParapheur démarré.
workflowFinishedEmailParapheur terminé.
workflowStoppedEmailParapheur interrompu.
workflowFinishedDownloadLinkEmailTerminé, avec le lien de téléchargement des documents.

Collaboration et divers

CléMessage
coManagerAddedEmail / coManagerRemovedEmailCogestionnaire ajouté ou retiré.
commentCreatedEmail / commentCreatedSecuredEmailCommentaire déposé (variante sécurisée).
anonymizedUsersInStepEmailUtilisateurs anonymisés dans une étape.
rolesTranslationInEmailException : pas de subject/content, mais les libellés des rôles cités dans les messages (manager, comanager, watcher, cc).

À côté des gabarits, preferredLocales fixe la ou les langues retenues.

Personnaliser l’invitation sans toucher aux autres messages produit une expérience incohérente si ces autres messages partent effectivement. Deux réponses possibles : habiller les gabarits d’une même famille, ou réduire le nombre de messages émis (voir les réglages de notification du parapheur, fondation Parapheurs).

Écrire un gabarit

La référence ne nomme pas le moteur de gabarit. La syntaxe employée par les gabarits par défaut — {{variable}}, {{{variable}}}, {{#if}} … {{else}} … {{/if}}, assistants à paramètres nommés — est celle de la famille Handlebars, et c’est sur cette base que nous raisonnons ici.

Le contexte offert au gabarit s’organise en quatre objets. Ce qui suit a été établi en envoyant une invitation réelle dont le corps listait chaque chemin candidat :

ObjetCe qu’il porteChemins vérifiés
workflowLe parapheur lui-même, avec ses métadonnéesname, id, workflowStatus, created, data1data16
recipientLe destinataire du messageemail, firstName, lastName, organizationId
stepL’étape en coursstepType, validityPeriod, invitePeriod
notificationL’événement qui déclenche l’envoiworkflowName, creatorName, linkUrl, stepType

S’y ajoute log.reason, le motif saisi lors d’un refus, et l’assistant {{durationToDays duration=… singular=… plural=… zero=…}}.

L’organisation : l’identifiant seulement. recipient.organizationId rend bien l’identifiant org_… de l’organisation au nom de laquelle le destinataire signe — à condition qu’elle ait été portée sur le destinataire à la création du parapheur, l’héritage depuis la fiche ne la transmettant pas (voir la fondation Provisionnement). En revanche le nom de l’organisation et la fonction ne sont pas exposés : recipient.organization, organizationName, organizationTitle, title et organization.name rendent tous une chaîne vide. Pour la fonction, le constat va plus loin que le gabarit : envoyée sur le destinataire à la création, elle n’est pas restituée lorsqu’on relit le parapheur (voir la fondation Provisionnement).

Conséquence pratique : on peut aiguiller selon l’organisation — {{#eq recipient.organizationId 'org_…'}} — mais pas afficher son nom ni la fonction du signataire. Le libellé lisible doit être écrit dans la branche correspondante du gabarit. Pour faire figurer l’organisation et la fonction sur le document, c’est le cartouche de signature qu’il faut employer ({{signerOrganization}}, {{signerOrganizationTitle}} — fondation Profils de signature).

Chemins qui n’existent pas — vérifié : signer.* et user.* ne rendent rien, alors que recipient.email fonctionne ; notification.recipientName non plus. Pour désigner le destinataire, c’est bien recipient qu’il faut employer. De même, le préfixe est obligatoire : {{data10}} seul ne rend rien, il faut {{workflow.data10}}.

Deux formats à connaître avant d’insérer une valeur brute. Les durées sont en millisecondes (validityPeriod rend 604800000 pour sept jours) — d’où l’assistant durationToDays, qui existe précisément pour cela. Et les dates sortent dans un format long à l’anglaise (Sun Aug 02 14:38:32 CEST 2026), qui n’est ni ISO ni localisé en français : à insérer tel quel, on obtient un message peu soigné.

Insérer une variable, ou conditionner sur elle

Deux usages qu’il faut distinguer, car ils n’obéissent pas aux mêmes contraintes.

Insérer est sans difficulté : toute variable du contexte peut être écrite dans le sujet ou dans le corps — le nom du parapheur, celui de son créateur, la durée de validité de l’étape. C’est ce que font les gabarits par défaut, et c’est ce qui permet d’adresser un message circonstancié.

Conditionner se fait de deux façons, qui répondent à deux questions différentes.

Sur la présence{{#if …}} teste qu’une valeur est renseignée, sans regarder laquelle. C’est la bonne réponse à la question « ce parapheur est-il le mien ? » : une variable toujours présente, comme le nom du parapheur, serait vraie pour tout le monde et ne distinguerait rien. Une métadonnée fait au contraire un discriminant parfait, parce que c’est la seule valeur dont vous maîtrisez à la fois la présence et l’absence — renseignée sur vos parapheurs, vide sur ceux des autres applications du tenant.

Sur la valeur — un assistant de comparaison est disponible, sous deux formes équivalentes :

{{#eq workflow.data10 'partenaire'}} … {{else}} … {{/eq}}
{{#if (eq workflow.data10 'partenaire')}} … {{else}} … {{/if}}

Cela répond à la question suivante : « de quelle catégorie relève-t-il ? ». Un seul emplacement « type d’entité » suffit alors à s’adresser différemment à un client, un partenaire, un fournisseur ou un auditeur — au lieu d’en consommer un par catégorie, ce qui compterait vite sur seize. En revanche {{#compare}} n’existe pas : son emploi est refusé dès l’écriture.

En pratique, les deux se combinent : {{#if …}} sur la métadonnée pour n’affecter que vos parapheurs, puis une comparaison à l’intérieur pour choisir le ton selon la catégorie.

⚠️ Cet assistant n’est pas documenté par la référence — qui ne nomme ni le moteur de gabarit, ni ses assistants. Son fonctionnement a été vérifié, mais rien ne garantit sa stabilité dans une version future. Écrivez donc la branche {{else}} de façon qu’elle tienne seule : si la comparaison venait à ne plus être reconnue, votre message resterait correct.

Deux accolades ou trois ? En double accolade, la valeur est échappée pour le HTML : une apostrophe devient ', une esperluette &. En triple, elle est insérée telle quelle. Le bon choix dépend de l’endroit où vous écrivez.

Dans le sujet — qui est du texte brut, jamais interprété comme du HTML — l’échappement n’a aucune vertu et se voit : un sujet contenant {{notification.workflowName}} en double accolade affiche « Bulletin d’adhésion — … » chez le destinataire. Employez donc la triple accolade dans les sujets ; le risque d’injection y est nul, faute de HTML à injecter.

Dans le corps HTML — l’échappement protège : une valeur venue d’un tiers (un nom, un titre de parapheur, une métadonnée) pourrait sinon y insérer des balises. Restez en double accolade, avec une exception : une URL placée dans un attribut href se met en triple, sinon les & de sa chaîne de requête deviennent & et le lien casse.

Précautions avant d’écrire

Les gabarits appartiennent au tenant, pas à votre application. Si votre tenant sert plusieurs usages, écraser un gabarit impose votre charte à tout le monde. Le moyen d’y échapper est un gabarit conditionnel dont la condition porte sur une valeur présente sur vos seuls parapheurs — en pratique une métadonnée, pour la raison exposée au section Écrire un gabarit : la branche « sinon » restitue alors aux autres applications le gabarit d’origine, celui fourni par Goodflag.

Repartez toujours des réglages en vigueur. Avant d’écrire, relisez GET /api/defaultSettings pour la branche par défaut et les réglages actuels du tenant pour tout ce que vous ne modifiez pas — puis renvoyez l’ensemble. Composer une nouvelle version à partir de votre propre version précédente conduit, à la longue, à emboîter des conditions les unes dans les autres et à faire de votre charte le défaut de tous.

La plateforme valide vos gabarits à l’écriture. Un contenu qu’elle ne sait pas analyser est refusé par le PUT lui-même, avec un 400 et le code InvalidEmailTemplate (An email template could not be parsed). C’est une garantie appréciable : on ne peut pas mettre ses notifications en panne en publiant un gabarit mal formé — une expression inconnue, une balise de bloc non refermée, un assistant qui n’existe pas sont écartés avant d’atteindre le moindre destinataire. Corollaire pratique : pour savoir si une syntaxe est acceptée, il suffit de tenter l’écriture, sans avoir à provoquer d’envoi.

Vérifiez le résultat au bon endroit. Après un PUT, relisez appliedSettings — et non vos settings — pour constater ce que recevront vos destinataires.

*[Handlebars] : langage de gabarit utilisé par les messages — variables {{…}}, conditions {{#if}} *[tenant] : espace client isolé dans la plateforme, avec ses réglages, ses groupes et ses pages de consentement *[gabarit] : modèle de message, composé d’un sujet et d’un contenu, déclinés par langue