Architecture du flux
Le site statique, généré avec Eleventy (11ty), est hébergé sur Cloudflare Pages (plan Pro). Le formulaire POST s’adresse à /api/contact, qui correspond à une Pages Function exécutée dans un Worker. Le Worker récupère le token reCAPTCHA v3, le valide auprès de l’API Google, puis transmet les champs name, email et message à l’API Resend pour l’envoi d’un email. Enfin, il renvoie une redirection HTTP 302 vers une page “Thank You”.
export async function onRequestPost({ request }) {
const { name, email, message, token } = await request.json();
const verify = await fetch(`https://www.google.com/recaptcha/api/siteverify?secret=${RECAPTCHA_SECRET}&response=${token}`);
const { success, score } = await verify.json();
if (!success || score < 0.5) return new Response('Spam détecté', { status: 400 });
const emailRes = await fetch('https://api.resend.com/email', {
method: 'POST',
headers: { 'Authorization': `Bearer ${RESEND_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ from: 'contact@mydomain.com', to: 'me@mydomain.com', subject: `Message de ${name}`, text: message })
});
return Response.redirect('https://mydomain.com/thank-you', 302);
}
Mécanisme de reCAPTCHA v3
reCAPTCHA v3 ne présente aucun widget visible. À chaque interaction, le script collecte plus de trente signaux – mouvements de souris, vitesse de frappe, défilement, timing des clics – et les agrège dans un score compris entre 0 (probable bot) et 1 (probable humain). Le token généré est valable 2 minutes, ce qui contraint le Worker à vérifier le score avant l’expiration. La validation s’effectue via l’endpoint https://www.google.com/recaptcha/api/siteverify, qui renvoie un objet JSON contenant success et score. Le seuil de 0,5 est couramment retenu comme compromis entre faux positifs et faux négatifs.
Gestion de l’envoi d’email avec Resend
Resend propose une API REST facturée à partir de 20 $ / mois pour les volumes supérieurs au plan gratuit. L’appel POST inclut les champs from, to, subject et text. La réponse HTTP 202 indique que le message a été accepté par le service, qui assure la délivrabilité grâce à des mécanismes de SPF/DKIM automatisés. L’utilisation d’une API externe évite de déployer un serveur SMTP dans le Worker, ce qui réduit la surface d’attaque et la consommation de ressources V8.
Alternatives et limites
Avant d’adopter cette solution, l’auteur a testé cinq alternatives : Netlify Forms (gratuit selon le plan), Cloudflare Pages Functions + MailChannels (service désormais payant), Formspree.io (plan gratuit limité, 15 $ / mois au-delà), Formspark.io (9 $ / mois) et Botpoison (vérifications invisibles, 4 $ / mois). Toutes ces options requièrent soit un service tiers de stockage, soit un coût récurrent. La combinaison Worker + reCAPTCHA v3 + Resend minimise les dépendances, mais elle reste sensible aux pannes d’API externes : si Google ou Resend sont indisponibles, le formulaire échoue sans fallback. De plus, le score de reCAPTCHA v3 peut varier selon le navigateur ou le réseau, ce qui peut entraîner des rejets légitimes si le seuil n’est pas ajusté.