Bloc Ajouter au calendrier
Un bloc « ajouter ceci à mon calendrier » en un tap, et la solution concrète aux invitations inter-fuseaux horaires. Un email envoyé n'a pas de JavaScript pour détecter le fuseau horaire propre d'un destinataire, donc ce bloc encode le début et la fin de l'événement comme un instant absolu plutôt qu'une chaîne d'heure locale précalculée. Ainsi, l'application de calendrier propre de chaque participant l'affiche automatiquement et correctement dans son propre fuseau horaire local.
Comment ça fonctionne
Le bloc est du contenu pur, comme Lieu : il n'y a rien à répondre, donc il n'apparaît jamais dans le tableau de bord des réponses ou l'export CSV. Les trois liens qu'il rend adoptent tous le même emplacement générique de suivi des clics que partage tout bloc porteur de lien simple, plutôt qu'une capacité sur mesure.
Les liens sont conditionnés par la présence d'un startsAt valide : un événement sans heure de début renseignée ne rend que le texte du titre et de la description, sans lien mort ne menant nulle part. Si startsAt est défini mais que endsAt ne l'est pas (ou se résout à quelque chose d'antérieur à startsAt), le bloc fixe par défaut la durée à une heure après le début — ne remplir que « quand ça commence » est traité comme le cas courant, et chaque consommateur en aval (le fichier .ics, Google Calendar, Outlook.com) a besoin qu'un instant de fin existe. location est un champ saisi librement à la main à partir du texte propre de votre bloc Lieu ou Lien de réunion ; les trois blocs ne sont pas liés automatiquement dans cette première version, donc mettez-le à jour vous-même si le lieu change.
À partir de ces props, trois liens se rendent, partageant un même blockId à des fins de suivi des clics (la carte de chaleur regroupe par bloc, pas par lien individuel, la même convention que le bloc Liens sociaux utilise pour ses multiples icônes) :
- Télécharger .ics — un lien signé vers
GET /api/calendarqui diffuse un fichier RFC 5545 (iCalendar) fait main. Il n'y a aucune dépendance npm derrière — un fichier.icsest du texte brut, construit de la même façon « pur, fait à partir de rien » que l'encodeur GIF de compte à rebours. LesDTSTART/DTENDdu fichier sont émis comme des instants UTC absolus (unZfinal, aucun composantTZID/VTIMEZONEnécessaire) — c'est le véritable correctif inter-fuseaux horaires, pas quelque chose calculé au moment du rendu, simplement une conséquence du fait questartsAt/endsAtdu bloc sont déjà stockés en millisecondes epoch. L'UIDde l'événement est un hachage sha256 déterministe de son titre/description/lieu/début/fin, donc retélécharger le même lien signé met à jour une seule entrée de calendrier plutôt que d'en créer un doublon. Le texte saisi librement est échappé selon la RFC 5545 §3.3.11 (barres obliques inverses, virgules, points-virgules, sauts de ligne littéraux) et les longues lignes sont repliées à la limite de 75 octets exigée par la spécification, afin que la longue description d'un organisateur ne puisse pas produire un fichier techniquement invalide. L'URL elle-même est signée de la même façon que les endpoints compte à rebours/formule/graphique — la charge utile complète de l'événement se sérialise dans la chaîne de requête (aucune lecture Firestore sur le chemin GET), séparée par domaine de toute autre famille d'URL signée de l'application via un préfixe"calendar:"intégré dans l'entrée HMAC, afin qu'une signature créée pour cet endpoint ne puisse jamais se vérifier contre un autre. - Ajouter à Google Calendar — un lien profond simple
calendar.google.com/calendar/render?action=TEMPLATE&...construit au moment du rendu, sans aller-retour serveur. - Ajouter à Outlook.com — un lien profond simple
outlook.live.com/calendar/0/action/compose?..., également construit au moment du rendu.
Le titre, la description et le lieu sont chacun tronqués de façon défensive à des longueurs maximales fixes (200 / 2 000 / 300 caractères) avant que l'un des trois liens ne soit construit, afin qu'un champ saisi librement très long ne puisse pas produire un lien .ics cassé ou une chaîne de requête surdimensionnée sur les deux liens web.
Champs configurables :
- Titre de l'événement.
- Description (facultatif).
- Heure de début — requise pour que des liens se rendent.
- Heure de fin (par défaut une heure après le début).
- Lieu (facultatif, texte libre).
- Couleur d'arrière-plan, marge intérieure, bordure et rayon de bordure sur la fiche.
- Couleur/taille du titre de l'événement, et surcharges de couleur/arrière-plan partagées des trois liens.
Exemples
Subject
Save the date: our fall meetup
Chaque projet d'objectif « Événement » démarre avec un bloc Ajouter au calendrier déjà en place aux côtés de Lien de réunion, Lieu, et RSVP — voir Événements et webinaires pour le motif complet d'invitation-à-rappel dont ce bloc fait partie. Un club sportif réutilise le même bloc semaine après semaine pour les horaires d'entraînement et de match, afin que le calendrier de chaque famille reflète correctement le programme quel que soit le fuseau horaire dans lequel elle voyage — voir Équipes et clubs sportifs. Une série de webinaires peut déposer ceci dans un email de confirmation envoyé juste après l'inscription, afin que le destinataire l'ajoute à son calendrier au moment même où il s'inscrit, plutôt que de compter sur lui pour s'en souvenir plus tard.
À quoi ressemble l'alternative statique
<div style="margin:12px 0;background-color:transparent">
<p style="margin:0 0 8px;font-weight:600;font-size:16px;color:#111827">Q3 Product Launch</p>
<a href="https://mailinapp.com/api/calendar?d=eyJ0aXRsZSI6...&s=abc123..."
style="display:inline-block;padding:10px 20px;background-color:#4f46e5;color:#ffffff;
border-radius:6px;text-decoration:none;font-size:14px;font-weight:600;margin:0 8px 8px 0">
Download .ics
</a>
<a href="https://calendar.google.com/calendar/render?action=TEMPLATE&text=Q3+Product+Launch&dates=20260901T170000Z%2F20260901T180000Z"
style="display:inline-block;padding:10px 20px;background-color:#4f46e5;color:#ffffff;
border-radius:6px;text-decoration:none;font-size:14px;font-weight:600;margin:0 8px 8px 0">
Add to Google Calendar
</a>
</div>
Ceci est l'intégralité du bloc envoyé — trois liens simples (le troisième, Outlook.com, omis ici par souci de concision) construits à partir des mêmes détails d'événement, sans image ni contenu conditionné.