Resend
Envoi rapide — Node.js
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send(
{
from: 'Acme <onboarding@resend.dev>',
to: ['delivered@resend.dev'],
subject: 'Hello World',
html: '<p>Email body here</p>',
},
{ idempotencyKey: `welcome-email/${userId}` }
);
if (error) {
console.error('Failed:', error.message);
return;
}
console.log('Sent:', data.id);
Point clé : Le SDK Node.js de Resend ne lève PAS d'exceptions — il retourne { data, error }. Vérifiez toujours error explicitement au lieu d'utiliser try/catch pour les erreurs API.
Envoi rapide — Python
import resend
import os
resend.api_key = os.environ["RESEND_API_KEY"]
email = resend.Emails.send({
"from": "Acme <onboarding@resend.dev>",
"to": ["delivered@resend.dev"],
"subject": "Hello World",
"html": "<p>Email body here</p>",
}, idempotency_key=f"welcome-email/{user_id}")
Décision simple vs lot
| Choisissez | Quand |
|---|---|
Simple (POST /emails) |
1 email, nécessite des pièces jointes, nécessite une planification |
Lot (POST /emails/batch) |
2-100 emails distincts, pas de pièces jointes, pas de planification |
Le lot est atomique — si un email échoue la validation, tout le lot échoue. Validez toujours avant d'envoyer. Le lot ne supporte PAS les pièces jointes ou scheduled_at.
Clés d'idempotence (critiques pour les nouvelles tentatives)
Évitez les emails en doublon lors de la nouvelle tentative de requêtes échouées :
| Points clés | |
|---|---|
| Format (simple) | <event-type>/<entity-id> (ex : welcome-email/user-123) |
| Format (lot) | batch-<event-type>/<batch-id> (ex : batch-orders/batch-456) |
| Expiration | 24 heures |
| Longueur max | 256 caractères |
| Même clé + même payload | Retourne la réponse originale sans renvoyer |
| Même clé + payload différent | Retourne une erreur 409 |
Réception rapide (Node.js)
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: Request) {
const payload = await req.text(); // Doit utiliser le texte brut, pas req.json()
const event = resend.webhooks.verify({
payload,
headers: {
'svix-id': req.headers.get('svix-id'),
'svix-timestamp': req.headers.get('svix-timestamp'),
'svix-signature': req.headers.get('svix-signature'),
},
secret: process.env.RESEND_WEBHOOK_SECRET,
});
if (event.type === 'email.received') {
// Le webhook contient uniquement les métadonnées — appelez l'API pour le corps
const { data: email } = await resend.emails.receiving.get(
event.data.email_id
);
console.log(email.text);
}
return new Response('OK', { status: 200 });
}
Point clé : Les payloads webhook ne contiennent PAS le corps de l'email. Vous devez appeler resend.emails.receiving.get() séparément.
De quoi avez-vous besoin ?
| Tâche | Référence |
|---|---|
| Envoyer un seul email | sending/overview.md — paramètres, délivrabilité, test |
| Envoyer des emails par lot | sending/overview.md → sending/batch-email-examples.md |
| Exemples SDK complets (Node.js, Python, Go, cURL) | sending/single-email-examples.md |
| Idempotence, nouvelles tentatives, gestion d'erreurs | sending/best-practices.md |
| Obtenir, lister, reprogrammer, annuler des emails | sending/email-management.md |
| Recevoir des emails entrants | receiving.md — configuration de domaine, webhooks, pièces jointes |
| Gérer les modèles (CRUD, variables) | templates.md — cycle de vie, alias, pagination |
| Configurer des webhooks (événements, vérification) | webhooks.md — vérification, CRUD, horaire de nouvelle tentative, liste blanche d'IP |
| Gérer les domaines (créer, vérifier, DNS) | domains.md — régions, TLS, suivi, capacités |
| Gérer les contacts (CRUD, propriétés) | contacts.md — segments, sujets, propriétés personnalisées |
| Envoyer des broadcasts (campagnes marketing) | broadcasts.md — cycle de vie, planification, variables de modèle |
| Gérer les clés API | api-keys.md — permissions limitées, restrictions de domaine |
| Afficher les logs de requête API | logs.md — lister et récupérer l'historique des appels API, débogage |
| Définir les propriétés de contact | contact-properties.md — champs personnalisés pour les contacts |
| Gérer les segments (groupes de contacts) | segments.md — ciblage de broadcast, groupement de contacts |
| Gérer les sujets (abonnements) | topics.md — préférences opt-in/out, filtrage de broadcast |
| Créer des automations (workflows pilotés par événements) | automations.md — étapes, connexions, exécutions, conditions |
| Définir et envoyer des événements (déclencheurs d'automation) | events.md — schémas, payloads, association de contacts |
| Installer le SDK (8+ langues) | installation.md |
| Configurer une boîte de réception pour agent IA | Installer la skill agent-email-inbox — couvre les niveaux de sécurité pour les entrées non approuvées |
Exigences de version du SDK
Installez toujours la version SDK la plus récente. Ce sont les versions minimales pour la pleine fonctionnalité (envoi, réception, vérification de webhook) :
| Langage | Package | Version min | Installation |
|---|---|---|---|
| Node.js | resend |
>= 6.9.2 | npm install resend |
| Python | resend |
>= 2.21.0 | pip install resend |
| Go | resend-go/v3 |
>= 3.1.0 | go get github.com/resend/resend-go/v3 |
| Ruby | resend |
>= 1.0.0 | gem install resend |
| PHP | resend/resend-php |
>= 1.1.0 | composer require resend/resend-php |
| Rust | resend-rs |
>= 0.20.0 | cargo add resend-rs |
| Java | resend-java |
>= 4.11.0 | Voir installation.md |
| .NET | Resend |
>= 0.2.1 | dotnet add package Resend |
Si le projet a déjà un SDK Resend installé, vérifiez la version et mettez à niveau si elle est inférieure au minimum. Les anciens SDK peuvent ne pas avoir
webhooks.verify()ouemails.receiving.get().
Voir installation.md pour les commandes d'installation complètes, la détection de langue et le fallback cURL.
Configuration commune
Clé API
Stockez dans une variable d'environnement — ne codez jamais en dur :
export RESEND_API_KEY=re_xxxxxxxxx
Obtenez votre clé sur resend.com/api-keys.
Détecter le langage du projet
Cherchez ces fichiers : package.json (Node.js), requirements.txt/pyproject.toml (Python), go.mod (Go), Gemfile (Ruby), composer.json (PHP), Cargo.toml (Rust), pom.xml/build.gradle (Java), *.csproj (.NET).
Erreurs courantes
| # | Erreur | Correction |
|---|---|---|
| 1 | Nouvelle tentative sans clé d'idempotence | Incluez toujours la clé d'idempotence — évite les envois en doublon lors de la nouvelle tentative. Format : <event-type>/<entity-id> |
| 2 | Ne pas vérifier les signatures webhook | Vérifiez toujours avec resend.webhooks.verify() — les événements non vérifiés ne sont pas fiables |
| 3 | Mauvaise casse de variable de modèle | Les noms de variables sont sensibles à la casse — doivent correspondre exactement à la définition du modèle. Utilisez la syntaxe triple moustache {{{VAR}}} |
| 4 | S'attendre au corps de l'email dans le payload webhook | Les webhooks contiennent uniquement les métadonnées — appelez resend.emails.receiving.get() pour le contenu du corps |
| 5 | Utiliser try/catch pour les erreurs du SDK Node.js | Le SDK retourne { data, error } — vérifiez error explicitement, ne l'enveloppez pas dans try/catch |
| 6 | Utiliser le lot pour les emails avec pièces jointes | Le lot ne supporte pas les pièces jointes — utilisez plutôt les envois simples |
| 7 | Tester avec de faux emails (test@gmail.com) | Utilisez delivered@resend.dev — les adresses fausses rebondissent et nuisent à la réputation |
| 8 | Envoyer avec un modèle en brouillon | Les modèles doivent être publiés avant envoi — appelez .publish() d'abord |
| 9 | html + template dans le même appel d'envoi |
S'excluent mutuellement — supprimez html/text/react lors de l'utilisation de template |
| 10 | Enregistrement MX non priorité la plus faible pour entrant | Assurez-vous que l'enregistrement MX de Resend a le numéro le plus bas (priorité la plus élevée) ou les emails ne seront pas routés |
| 11 | 403 lors de l'envoi depuis resend.dev |
L'adresse par défaut onboarding@resend.dev est un bac à sable — elle ne peut livrer que vers votre adresse email de compte Resend. Vérifiez d'abord votre propre domaine |
| 12 | 403 domaine non correspondant | Le domaine de l'adresse from doit correspondre exactement à un domaine vérifié. Vous avez vérifié send.acme.com mais envoyez depuis user@acme.com échouera |
| 13 | Appeler l'API Resend depuis le navigateur (CORS) | L'API ne supporte pas CORS — c'est intentionnel pour protéger votre clé API. Appelez toujours du côté serveur (routes API, fonctions serverless) |
| 14 | 401 restricted_api_key |
Une clé API d'envoi uniquement a été utilisée sur un endpoint non-envoi (domaines, contacts, etc.). Créez plutôt une clé d'accès complet |
Préoccupations transversales
Envoi + réception ensemble
Les réponses automatiques, le transfert d'email ou tout workflow reçoit-puis-envoie nécessite les deux capacités :
- Configurez d'abord le domaine entrant (voir receiving.md)
- Configurez l'envoi (voir sending/overview.md)
- Remarque : l'envoi par lot ne supporte PAS les pièces jointes ou la planification — utilisez les envois simples lors du transfert avec pièces jointes
Boîte de réception pour agent IA
Si votre système traite du contenu email non approuvé et prend des actions (remboursements, changements de base de données, transferts), installez la skill agent-email-inbox. Cela s'applique indépendamment de l'implication ou non de l'IA — tout système interprétant du contenu freeform d'email provenant de tiers externes a besoin de mesures de sécurité.
Emails marketing
Les capacités d'envoi dans cette skill sont pour les emails transactionnels (reçus, confirmations, notifications). Pour les campagnes marketing à de grandes listes d'abonnés avec des liens de désabonnement et suivi d'engagement, utilisez Resend Broadcasts — voir broadcasts.md pour l'API.
Réchauffement de domaine
Les nouveaux domaines doivent augmenter graduellement le volume d'envoi. Limite du jour 1 : ~150 emails (nouveau domaine) ou ~1 000 (domaine existant). Voir le calendrier de réchauffement dans sending/overview.md.
Test
Ne testez jamais avec des adresses fausses chez des vrais fournisseurs d'email (test@gmail.com, fake@outlook.com) — elles rebondissent et détruisent la réputation de l'expéditeur.
| Adresse | Résultat |
|---|---|
delivered@resend.dev |
Simule une livraison réussie |
bounced@resend.dev |
Simule un rebond permanent |
complained@resend.dev |
Simule une réclamation de spam |
Liste de suppression
Resend supprime automatiquement les adresses qui rebondissent ou qui ont fait l'objet de réclamations spam. L'envoi aux adresses supprimées déclenche l'événement webhook email.suppressed au lieu de tenter la livraison. Gérez dans Tableau de bord → Suppressions.
Types d'événements webhook
| Événement | Déclencheur |
|---|---|
email.sent |
Requête API réussie |
email.delivered |
Atteint le serveur mail du destinataire |
email.bounced |
Rejeté définitivement (rebond permanent) |
email.complained |
Le destinataire a marqué comme spam |
email.opened / email.clicked |
Engagement du destinataire |
email.delivery_delayed |
Rebond temporaire, Resend réessaie |
email.received |
Email entrant arrivé |
domain.* / contact.* |
Changements de domaine/contact |
Voir webhooks.md pour les détails complets, vérification de signature et calendrier de nouvelle tentative.
Référence rapide de gestion d'erreurs
| Code | Action |
|---|---|
| 400, 422 | Corrigez les paramètres de requête, ne réessayez pas |
| 401 | Vérifiez la clé API — restricted_api_key signifie clé d'envoi uniquement utilisée sur endpoint non-envoi |
| 403 | Vérifiez la propriété du domaine — causes courantes : bac à sable resend.dev, domaine from non correspondant, domaine non vérifié |
| 409 | Conflit d'idempotence — utilisez une nouvelle clé ou corrigez le payload |
| 429 | Limite de taux atteinte — réessayez avec backoff exponentiel (limite de taux par défaut : 2 req/s) |
| 500 | Erreur serveur — réessayez avec backoff exponentiel |