Cloudflare
Email Workers
MIME
Automação
Serverless

Email Routing + Workers : traitez les e-mails par programmation à la périphérie

Le routage des e-mails vers un Worker au lieu d'une adresse de destination change complètement ce que vous pouvez faire avec les e-mails entrants.

Email Routing + Workers : traitez les e-mails par programmation à la périphérie

La plupart des didacticiels Cloudflare Email Routing montrent comment transférer contato@seudominio.com vers un compte Gmail. Cela résout le cas d’utilisation le plus simple, mais cache la partie la plus intéressante du service. Lorsque vous acheminez un e-mail vers un Worker au lieu d'une adresse de destination, l'e-mail devient des données : vous lisez l'expéditeur, le sujet, les en-têtes, le corps complet et décidez quoi faire de tout cela dans une fonction JavaScript exécutée en périphérie. Cela change considérablement ce qui est viable à construire sans votre propre infrastructure de messagerie.

Le gestionnaire de courrier électronique et ce que vous recevez

La structure de base d'un Email Worker utilise un export nommé email dans l'objet par défaut :

export default { async email(message, env, ctx) { // message.from — endereço do remetente // message.to — endereço de destino no seu domínio // message.headers — objeto Headers com todos os cabeçalhos RFC 2822 // message.raw — ReadableStream com a mensagem completa } }

message.from et message.to sont des chaînes avec des adresses. message.headers est un objet d'en-têtes d'API Web standard : vous accédez à message.headers.get('subject') ou message.headers.get('x-mailer') de la même manière que vous le feriez dans un gestionnaire d'extraction. message.raw est un ReadableStream avec l'intégralité du message RFC 2822, y compris les en-têtes et le corps, avec prise en charge de messages jusqu'à 25 Mo.

Quatre actions sont disponibles : message.forward(address) pour transférer vers une adresse vérifiée, message.reply(response) pour répondre, message.setReject(reason) pour rejeter le message avec un message d'erreur, ou simplement revenir sans rien appeler, ce qui rejette le message en silence. Vous pouvez combiner : filtrer par expéditeur, en transférer certains, en rejeter d'autres et traiter le reste.

L'écart dans l'analyse MIME

Voici le point que la documentation mentionne discrètement : il n'y a pas d'analyseur MIME intégré. message.raw vous donne le flux brut. Si vous souhaitez extraire le sujet avec l'encodage UTF-8, le corps en texte brut, le HTML alternatif ou les pièces jointes, vous devez analyser le MIME vous-même ou utiliser une bibliothèque.

postal-mime fonctionne bien dans l’environnement des travailleurs. La valeur par défaut consiste à consommer le flux, à le convertir en ArrayBuffer et à le transmettre à l'analyseur :

import PostalMime from 'postal-mime'; const raw = await new Response(message.raw).arrayBuffer(); const parsed = await new PostalMime().parse(raw); // parsed.subject, parsed.text, parsed.html, parsed.attachments

parsed.attachments est un tableau d'objets avec filename, mimeType et content (ArrayBuffer). Vous pouvez enregistrer le contenu dans un bucket R2, extraire les métadonnées d'un NF-e en XML ou transmettre un PDF à une API d'extraction. Le runtime Workers prend en charge cela sans aucune configuration supplémentaire autre que l'importation de la bibliothèque.

Le coût de la consommation de l’intégralité du flux est la mémoire. Pour les messages contenant des pièces jointes volumineuses proches de la limite de 25 Mo, vous chargez tout en mémoire dans Worker. Dans la plupart des cas, cela ne pose pas de problème, mais dans le cas de pipelines à volume élevé, cela vaut la peine d'être surveillé.

Modèles qu'il est logique de créer ici

Création automatique de tickets d'assistance. L'e-mail arrive, vous extrayez l'expéditeur, le sujet et le corps, assemblez une charge utile et POSTez-la sur l'API linéaire, Zendesk, Notion ou tout autre outil utilisé par votre équipe. Le ticket apparaît désormais avec le contexte complet sans que personne n’ait besoin de copier-coller. Pour les équipes qui reçoivent des demandes par e-mail mais travaillent avec des outils de suivi des problèmes, cela élimine une étape manuelle constante.

Capture des factures et des documents fiscaux. Vous créez une adresse dédiée — nfe@seudominio.com — et tout fournisseur qui envoie du NF-e par email voit la pièce jointe XML ou PDF automatiquement traitée : métadonnées extraites, fichier enregistré en R2, enregistrement créé en D1. Le travailleur fait ce qu'un humain ferait, mais sans avoir à ouvrir l'e-mail.

** Filtrage avant transfert. ** Avec le catch-all actif, *@seudominio.com capture le spam envoyé à des adresses aléatoires sur votre domaine. Un travailleur peut vérifier l'expéditeur par rapport à une liste de domaines problématiques connus stockés dans le KV, vérifier si le sujet contient des modèles de spam typiques et appeler le message.setReject('spam detectado') avant de le transférer vers votre boîte de réception. Ce n'est pas un filtre anti-spam complet, mais il réduit le bruit sans frais supplémentaires.

Alertes et notifications reformatées. Les outils de surveillance (Grafana, PagerDuty, outils CI) envoient des alertes par e-mail dans des formats qui ne sont pas toujours lisibles sur un téléphone. Un Worker intercepte ces e-mails, extrait les informations pertinentes du corps et publie un message formaté sur un canal Slack ou Discord via un webhook. L'e-mail original peut être supprimé ou transféré sous forme d'archive.

Qu'est-ce qui ne fonctionne pas comme vous le pensez

message.reply() existe et fonctionne, mais la réponse vient de noreply@cloudflare.com. Si vous souhaitez que le destinataire reçoive une réponse automatique qui semble provenir de suporte@seudominio.com, le Worker doit appeler un service SMTP sortant (Resend, Mailgun, SES) en lui transmettant les en-têtes nécessaires. Email Routing n'a pas accès au flux sortant de votre domaine.

Si le Worker lève une exception non interceptée, l'e-mail est rejeté avec l'erreur 500. Il n'y a pas de nouvelle tentative automatique, il n'y a pas de file d'attente de lettres mortes. Toute logique susceptible d'échouer nécessite un essai/catch avec un repli explicite - généralement un message.forward() vers une adresse de tri manuel en cas de problème lors du traitement. Découvrir ce comportement en production, avec des emails clients rejetés, est une expérience désagréable.

Où est-il judicieux d'aller au-delà du transfert

Si Email Routing pour vous n'est qu'un alias pour Gmail, vous ne toucherez jamais à Workers et vous n'en aurez pas besoin. Mais si votre équipe utilise déjà Workers à d'autres fins (API, tâches cron, intégrations), Email Worker s'intègre dans la même infrastructure avec les mêmes liaisons KV, D1, R2 et services externes. Vous n'ajoutez pas une nouvelle pièce à la pile ; vous ajoutez un type de déclencheur à un environnement qui existe déjà.

Le bon moment pour arrêter le transfert simple est lorsque vous remarquez qu'un membre de l'équipe ouvre des e-mails pour copier des informations vers un autre système plus d'une ou deux fois par semaine. Si le modèle est reproductible et que les données se trouvent dans l'e-mail, le travailleur le résout en moins de temps que la tâche manuelle n'en prendra en un mois.

A lire aussi

-Cloudflare Durable Objects : État cohérent à la périphérie – ce qui change vraiment