guide · api e-mail

Comment une équipe produit doit-elle implémenter une API e-mail en toute sécurité ?

Implémentez une API e-mail comme un workflow asynchrone soumis à permissions plutôt que comme un appel direct du formulaire vers le fournisseur. Authentifiez l’appelant, confirmez que le locataire possède un domaine From vérifié, validez et dimensionnez le message, attribuez un identifiant de tâche applicatif stable, mettez en file d’attente une seule fois et soumettez depuis un worker. Enregistrez l’identifiant de message du fournisseur à l’acceptation, ingérez les événements de livraison de façon idempotente et placez en liste de suppression les bounces définitifs et les plaintes. N’utilisez des nouvelles tentatives bornées que lorsque le risque de doublon est maîtrisé. Gardez les identifiants côté serveur, réduisez au minimum les données de message dans les logs et distinguez l’acceptation par l’API, la livraison au serveur de messagerie et l’arrivée en boîte de réception.

Définissez la frontière de l’API avant de choisir un fournisseur

Une API e-mail doit exposer l’intention applicative sans faire fuiter chaque détail du fournisseur dans le code produit. Définissez des ressources pour les messages, les domaines d’envoi, les clés API, les événements et les suppressions. Décidez quels champs les appelants peuvent contrôler, notamment From, To, Reply-To, l’objet, le texte, le HTML et une courte liste autorisée d’en-têtes. Rejetez les en-têtes de transport fournis par l’appelant qui pourraient entrer en conflit avec la signature ou le routage du fournisseur. Traitez l’envoi comme une écriture lourde de conséquences : la réponse doit identifier une ressource de message applicative et son état actuel, sans laisser entendre un résultat en boîte aux lettres. Gardez le compte fournisseur, la Region, le configuration set et les identifiants de transport derrière un adaptateur. Cette frontière rend la migration de fournisseur possible et donne un emplacement stable aux contrôles d’autorisation, de rétention et d’abus.

Authentifiez les appelants et autorisez chaque domaine d’expéditeur

Ne stockez les clés API que sous forme de hash à sens unique et n’affichez le secret complet qu’une seule fois. Donnez à chaque clé un espace de travail propriétaire, un statut, une date de création et un moyen de révocation ; ajoutez des portées plus étroites lorsqu’une intégration ne doit qu’envoyer ou que lire des événements. L’authentification répond à la question de savoir qui a présenté un identifiant, tandis que l’autorisation décide si ce principal peut utiliser le domaine From et la ressource de message demandés. Vérifiez la propriété du domaine à chaque envoi, y compris sur les endpoints de lot, plutôt que de faire confiance à un identifiant de domaine fourni par le client. Exigez la vérification par le fournisseur avant d’activer le trafic de production. Ne placez jamais d’identifiants de fournisseur ni de clés API d’espace de travail dans du JavaScript côté navigateur, des chaînes de requête, des outils d’analyse ou des messages d’erreur. L’autorisation au niveau objet est particulièrement importante pour les identifiants de message, d’événement, de suppression, de boîte de réception et de domaine dans une API multi-locataire.

Vérifiez le domaine et alignez l’authentification

Un domaine d’envoi exige plus qu’un indicateur en base de données. Effectuez la vérification de propriété du fournisseur et publiez les enregistrements DKIM requis. SPF autorise des hôtes pour l’identité SMTP MAIL FROM ou HELO, tandis que DKIM associe un domaine de signature à une signature cryptographique du message. DMARC évalue si un identifiant SPF ou DKIM validé est aligné avec le domaine From RFC 5322 visible et permet au propriétaire du domaine de publier une politique de traitement et de rapports. Si un domaine a déjà un enregistrement SPF, fusionnez le mécanisme requis dans l’enregistrement existant ; la RFC 7208 indique qu’un domaine ne doit pas publier plusieurs enregistrements conduisant à la sélection de plus d’un enregistrement SPF. Ne déployez une politique DMARC plus stricte qu’une fois que des messages contrôlés et les rapports agrégés montrent que chaque expéditeur légitime est aligné. L’authentification réduit l’utilisation non autorisée du domaine mais ne garantit pas l’arrivée en boîte de réception.

Validez la structure du message et réduisez au minimum les entrées acceptées

La RFC 5322 définit un message Internet comme des champs d’en-tête suivis d’un corps optionnel, les spécifications MIME étendant le contenu au-delà du texte simple. Une API peut masquer la plupart des détails du format de transmission tout en les faisant respecter. Normalisez les tableaux de destinataires, plafonnez le nombre de destinataires et la taille encodée totale, exigez au moins un corps texte ou HTML, et validez les adresses sans prétendre que la syntaxe prouve l’existence de la boîte aux lettres. Supprimez les caractères de retour chariot et de saut de ligne des champs qui deviennent des en-têtes. Générez le Message-ID ou laissez le fournisseur le faire ; ne le réutilisez pas comme identifiant de tâche applicatif, car une nouvelle version du message peut légitimement recevoir un nouvel identifiant. N’autorisez que les en-têtes personnalisés documentés, rejetez les doublons de champs protégés et effectuez le rendu des modèles avant la soumission au fournisseur, afin que les variables manquantes échouent dans un état applicatif maîtrisé.

Mettez en file d’attente une seule fois et utilisez des identifiants applicatifs stables

Une requête utilisateur doit créer une tâche de message durable dans une transaction, puis un worker doit effectuer l’appel au fournisseur. Donnez à la tâche un identifiant stable et enregistrez une empreinte de la requête ou une clé d’idempotence fournie par l’appelant lorsque le contrat le permet. HTTP définit POST comme non idempotent par défaut et met en garde contre les nouvelles tentatives automatiques, sauf si le client sait que l’opération est effectivement idempotente ou que la requête d’origine n’a pas été appliquée. C’est important pour l’e-mail, car un timeout peut survenir après que le fournisseur a accepté le message mais avant que le worker ait reçu la réponse. En cas d’échec ambigu, rapprochez d’abord la tâche enregistrée et l’état chez le fournisseur au lieu de créer un nouvel envoi. Utilisez un modèle outbox lorsque l’état applicatif et la publication dans la file doivent évoluer ensemble, et placez une contrainte d’unicité autour de la frontière d’idempotence.

Concevez les nouvelles tentatives en fonction des classes d’échec

Séparez validation, autorisation, limitation de débit, rejet par le fournisseur, échec de transport transitoire et échec de livraison au destinataire. Une entrée invalide et un domaine From non autorisé doivent échouer sans nouvelle tentative. Les limites de débit du fournisseur et les erreurs de service temporaires peuvent être réessayées avec un backoff exponentiel borné, du jitter, un plafond de tentatives et un délai de visibilité de la file supérieur à l’échéance de requête du worker. Un timeout réseau ambigu nécessite un rapprochement tenant compte des doublons plutôt qu’une nouvelle requête inconditionnelle. SMTP distingue lui-même les réponses 4xx transitoires des réponses 5xx définitives, mais une application qui passe par l’API d’un fournisseur doit suivre la sémantique d’erreur documentée par ce fournisseur. Placez les tâches épuisées dans un état de lettre morte (dead-letter) consultable et conservez la raison assainie. Ne réessayez pas un bounce définitif comme s’il s’agissait d’une panne d’API, et ne transformez pas une plainte en nouvelle tentative d’envoi.

Enregistrez l’acceptation et ingérez les événements de livraison

Conservez l’identifiant de message du fournisseur immédiatement après l’acceptation et associez-le à l’ID de message de l’application. Les événements du fournisseur peuvent alors mettre à jour la bonne ressource, même lorsqu’un rapport de plainte masque les détails du destinataire. Amazon SES, par exemple, distingue un envoi réussi de la livraison au serveur de messagerie du destinataire et peut publier des événements de livraison, bounce, plainte, rejet, retard de livraison, échec de rendu, ouverture et clic. Vérifiez l’authenticité du webhook avec le mécanisme documenté du fournisseur, validez le schéma d’événement, dédupliquez à l’aide d’un identifiant d’événement du fournisseur ou d’une empreinte déterministe et autorisez la livraison répétée du même événement sans répéter les effets de bord. Ne stockez les payloads bruts que si nécessaire, en les chiffrant, en limitant les accès et en limitant leur conservation. L’état normalisé doit distinguer les résultats acceptés, livrés au serveur, ayant généré un bounce, ayant fait l’objet d’une plainte, retardés, rejetés et placés en liste de suppression.

Faites de la suppression un contrôle au moment de l’envoi

Un enregistrement de suppression doit être vérifié avant chaque soumission au fournisseur, et pas seulement affiché dans un tableau de bord. Les adresses en bounce définitif et les plaintes nécessitent normalement une suppression ; les retards de livraison temporaires exigent une autre politique. Définissez délibérément la portée de la suppression. Une liste à l’échelle du compte peut protéger une réputation partagée, mais risque de laisser le résultat d’un destinataire chez un locataire bloquer un autre locataire. Une liste par locataire réduit ce couplage, mais nécessite tout de même une couche de protection contre les abus et de sécurité de la plateforme. Consignez la raison, l’événement source, le locataire, la date de création et un moyen de retrait contrôlé. Retirer une suppression liée à une plainte ou à un bounce définitif est lourd de conséquences et doit exiger une revue délibérée et la preuve que l’adresse est valide et que le destinataire attend le message. Évitez de copier les adresses brutes des destinataires dans les logs généraux ou les expérimentations : le stockage opérationnel peut faire respecter la politique d’envoi, tandis que l’analyse utilise des comptages agrégés.

Protégez les envois par lot et les flux métier sensibles

Un endpoint de lot multiplie l’impact d’une erreur d’autorisation ou de validation. Appliquez à chaque élément les mêmes contrôles de propriété du domaine, de suppression, de taille et de contenu, imposez une longueur de lot maximale stricte et renvoyez des résultats par élément sans divulguer les données d’un autre locataire. Des limites de débit doivent exister au niveau de l’identifiant, de l’espace de travail, du domaine et du fournisseur, avec des contrôles distincts pour les pics et le volume glissant. Une limite globale unique de requêtes par seconde ne suffit pas, car une seule requête peut contenir de nombreux destinataires. Exigez une confirmation délibérée dans les outils pilotés par des agents avant la soumission d’un lot à fort impact. Séparez les permissions transactionnelles et marketing lorsque leurs règles de consentement et d’exploitation diffèrent. Surveillez la croissance inhabituelle du nombre de destinataires, les domaines rejetés à répétition, les variations importantes des bounces ou des plaintes et la création rapide de clés. La limitation de débit contribue à la sécurité, mais ne remplace ni l’authentification, ni l’autorisation au niveau objet, ni le consentement vérifié, ni la réponse aux abus.

Testez les chemins d’échec avant la production

Utilisez les simulateurs du fournisseur ou des boîtes aux lettres contrôlées pour tester l’acceptation, la livraison au serveur destinataire, le hard bounce, la plainte, le retard, le domaine invalide, la clé révoquée, la limitation de débit, le timeout du fournisseur, le webhook en double et la relivraison depuis la file. Vérifiez qu’une même clé d’idempotence crée un seul message applicatif, qu’un événement rejoué ne produit pas d’effet de bord en double et qu’un locataire ne peut ni lire ni envoyer avec le domaine ou l’identifiant de message d’un autre locataire. Inspectez un vrai message reçu pour contrôler From, Return-Path, DKIM, SPF, l’alignement DMARC, le rendu texte et HTML, le comportement de désinscription le cas échéant et les liens. Faites des tests de charge sur la file en dessous des limites approuvées par le fournisseur et vérifiez la contre-pression plutôt que de la contourner. Ajoutez des alarmes sur l’âge de la file, les nouvelles tentatives épuisées, les échecs d’ingestion d’événements, la marge de quota, les variations de bounces et de plaintes et les callbacks manquants du fournisseur. Une checklist de lancement doit désigner un responsable pour chaque alerte et action de reprise.

Appliquez ce modèle avec SendHQ en restant prudent

SendHQ fournit des clés bearer limitées à l’espace de travail, des vérifications de domaine From, la création de messages uniques et par lot, des boîtes de réception entrantes, des événements de message et des ressources de suppression. Ces fonctionnalités prennent en charge l’architecture de ce guide : conservez la clé côté serveur, créez une ressource de message, gardez son ID et lisez les événements ultérieurs plutôt que de traiter la réponse initiale comme une livraison finale. Quelle que soit la plateforme, les appelants restent responsables des destinataires prévus, des e-mails légaux et attendus, de l’exactitude du contenu et de l’approbation attentive des envois conséquents.

Questions fréquentes

Une API e-mail doit-elle envoyer de manière synchrone depuis la requête web ?

En général, non. Créez un message applicatif durable et mettez-le en file d’attente, puis laissez un worker appeler le fournisseur. Cela isole la latence, permet des nouvelles tentatives bornées et facilite le rapprochement des résultats ambigus du fournisseur.

Comment éviter les e-mails en double lorsqu’une requête expire ?

Utilisez un identifiant de tâche applicatif stable et une frontière d’idempotence protégée par une contrainte d’unicité. En cas de timeout ambigu, rapprochez la tâche existante avant d’émettre une nouvelle soumission au fournisseur avec une nouvelle identité.

Une réponse réussie de l’API e-mail signifie-t-elle que le message est livré ?

Non. Elle indique normalement que l’API ou le fournisseur a accepté la requête. Utilisez les événements ultérieurs pour distinguer de l’acceptation initiale la livraison au serveur destinataire, le bounce, la plainte, le retard, le rejet et la suppression.

De quels enregistrements DNS une API e-mail a-t-elle besoin ?

Les enregistrements exacts dépendent du fournisseur, mais l’envoi en production nécessite généralement la vérification du domaine et DKIM, ainsi qu’une stratégie SPF correcte et une politique DMARC alignée avec les flux d’envoi légitimes.

Faut-il stocker les clés API dans le code du navigateur ?

Non. Gardez les identifiants de l’espace de travail et du fournisseur dans un stockage de secrets côté serveur, hachez les clés API applicatives au repos lorsque c’est possible, n’affichez les secrets complets qu’une seule fois et prévoyez des moyens rapides de révocation et de rotation.

Comment une API e-mail doit-elle gérer les bounces définitifs ?

Normalisez l’événement du fournisseur, associez-le au message applicatif et bloquez les futurs envois courants vers ce destinataire dans la portée prévue. Le retrait doit être délibéré et étayé par des preuves.

Sources