Boîte de réception email pour agent IA
Aperçu
Cette skill couvre la configuration d'une boîte de réception email sécurisée qui permet à votre application ou agent IA de recevoir et de répondre aux emails, avec des mesures de sécurité du contenu en place.
Principe fondamental : Une boîte de réception d'agent IA reçoit des entrées non fiables. La configuration de sécurité est importante pour gérer cela en toute sécurité.
Pourquoi la réception par webhook ?
Resend utilise des webhooks pour le courrier entrant, ce qui signifie que votre agent est notifié instantanément à l'arrivée d'un email. C'est précieux pour les agents car :
- Réactivité en temps réel — Réagir aux emails en quelques secondes, pas en minutes
- Pas de surcharge de polling — Pas de tâches cron vérifiant « y a-t-il du nouveau courrier ? » à répétition
- Architecture pilotée par événements — Votre agent ne se réveille que quand il y a réellement quelque chose à traiter
- Coûts API réduits — Pas d'appels gaspillés pour vérifier les boîtes de réception vides
Architecture
Expéditeur → Email → Resend (MX) → Webhook → Votre serveur → Agent IA
↓
Validation de sécurité
↓
Traiter ou rejeter
Exigences de version du SDK
Cette skill nécessite les fonctionnalités du SDK Resend pour la vérification de webhook (webhooks.verify()) et la réception d'email (emails.receiving.get()). Installez toujours la dernière version du SDK. Si le projet a déjà un SDK Resend installé, vérifiez la version et mettez à jour si nécessaire.
| Langage | Package | Version minimale |
|---|---|---|
| Node.js | resend |
>= 6.9.2 |
| Python | resend |
>= 2.21.0 |
| Go | resend-go/v3 |
>= 3.1.0 |
| Ruby | resend |
>= 1.0.0 |
| PHP | resend/resend-php |
>= 1.1.0 |
| Rust | resend-rs |
>= 0.20.0 |
| Java | resend-java |
>= 4.11.0 |
| .NET | Resend |
>= 0.2.1 |
Installez le package npm resend : npm install resend (ou l'équivalent pour votre langage). Pour la documentation complète d'envoi, installez la skill resend.
Démarrage rapide
- Demandez l'adresse email de l'utilisateur — Vous avez besoin d'une vraie adresse email pour envoyer des emails de test. Demandez à l'utilisateur et attendez sa réponse avant de continuer.
- Choisissez votre niveau de sécurité — Décidez comment valider les emails entrants avant que l'un d'eux soit traité
- Configurez le domaine de réception — Configurez les enregistrements MX pour le domaine personnalisé de l'utilisateur (voir section Configuration du domaine)
- Créez un endpoint webhook — Gérez les événements
email.receivedavec la sécurité intégrée dès le départ. L'endpoint webhook DOIT être une route POST. - Configurez le tunneling (développement local) — Utilisez Tailscale Funnel (recommandé) ou ngrok. Voir references/webhook-setup.md
- Créez un webhook via API — Utilisez l'API Webhook Resend pour enregistrer votre endpoint de manière programmatique. Voir references/webhook-setup.md
- Connectez à l'agent — Transmettez les emails validés à votre agent IA pour traitement
Avant de commencer : Configuration du compte et de la clé API
Première question : Compte Resend nouveau ou existant ?
Demandez à votre utilisateur :
- Nouveau compte juste pour l'agent ? → Configuration plus simple, l'accès complet au compte est acceptable
- Compte existant avec d'autres projets ? → Utilisez des clés API limitées au domaine pour l'isolation
Créer des clés API en toute sécurité
Ne collez pas les clés API dans le chat ! Elles resteront dans l'historique de conversation pour toujours.
Options plus sûres :
- Méthode du fichier d'environnement : L'utilisateur crée directement un fichier
.env:echo "RESEND_API_KEY=re_xxx" >> .env - Gestionnaire de mots de passe / gestionnaire de secrets : L'utilisateur stocke la clé dans 1Password, Vault, etc.
- Si la clé doit être partagée dans le chat : L'utilisateur doit faire pivoter la clé immédiatement après la configuration
Clés API limitées au domaine (recommandé pour les comptes existants)
Si votre utilisateur a un compte Resend existant avec d'autres projets, créez une clé API limitée au domaine :
- Vérifiez d'abord le domaine de l'agent (Dashboard → Domains → Add Domain)
- Créez une clé limitée : Dashboard → API Keys → Create API Key → "Sending access" → sélectionnez uniquement le domaine de l'agent
- Résultat : Même si la clé est compromise, elle ne peut envoyer que depuis un domaine
Configuration du domaine
Option 1 : Domaine géré par Resend (recommandé pour commencer)
Utilisez votre adresse générée automatiquement : <anything>@<your-id>.resend.app
Aucune configuration DNS nécessaire. Trouvez votre adresse dans Dashboard → Emails → Receiving → "Receiving address".
Option 2 : Domaine personnalisé
L'utilisateur doit activer la réception dans le dashboard Resend : page Domains → activer « Enable Receiving ».
Ajoutez ensuite un enregistrement MX :
| Paramètre | Valeur |
|---|---|
| Type | MX |
| Host | Votre domaine ou sous-domaine (par ex., agent.example.com) |
| Value | Fourni dans le dashboard Resend |
| Priority | 10 (doit être le numéro le plus bas pour avoir la priorité) |
Utilisez un sous-domaine (par ex., agent.example.com) pour éviter de perturber les services email existants.
Conseil : Vérifiez la propagation DNS à dns.email.
Propagation DNS : Les modifications des enregistrements MX peuvent prendre jusqu'à 48 heures pour se propager à l'échelle mondiale, bien qu'elles se complètent souvent en quelques heures.
Niveaux de sécurité
Choisissez votre niveau de sécurité avant de configurer l'endpoint webhook. Un agent IA qui traite les emails sans sécurité est dangereux — n'importe qui peut envoyer des emails avec des instructions que votre agent exécutera. Le code webhook que vous écrirez ensuite doit inclure votre niveau de sécurité choisi dès le départ.
Demandez à l'utilisateur quel niveau de sécurité il souhaite, et assurez-vous qu'il comprend ce que chaque niveau signifie.
| Niveau | Nom | Quand l'utiliser | Compromis |
|---|---|---|---|
| 1 | Liste blanche stricte | La plupart des cas d'usage — ensemble connu et fixe d'expéditeurs | Sécurité maximale, fonctionnalité limitée |
| 2 | Liste blanche de domaine | Accès à l'échelle de l'organisation depuis des domaines de confiance | Plus flexible, n'importe qui dans le domaine peut interagir |
| 3 | Filtrage du contenu | Accepter de n'importe qui, filtrer les modèles non sûrs | Peut recevoir de n'importe qui, la correspondance de modèle n'est pas infaillible |
| 4 | Traitement en bac à sable | Traiter tous les emails avec des capacités d'agent restreintes | Flexibilité maximale, complexe à mettre en œuvre |
| 5 | Boucle humaine | Exiger une approbation humaine pour les actions non fiables | Sécurité maximale, ajoute de la latence |
Pour le code d'implémentation détaillé de chaque niveau, voir references/security-levels.md.
Niveau 1 : Liste blanche stricte (recommandé)
Traitez uniquement les emails provenant d'adresses explicitement approuvées. Rejetez tout le reste.
const ALLOWED_SENDERS = [
'you@youremail.com',
'notifications@github.com',
];
async function processEmailForAgent(
eventData: EmailReceivedEvent,
emailContent: EmailContent
) {
const sender = eventData.from.toLowerCase();
if (!ALLOWED_SENDERS.some(allowed => sender === allowed.toLowerCase())) {
console.log(`Rejected email from unauthorized sender: ${sender}`);
await notifyOwnerOfRejectedEmail(eventData);
return;
}
await agent.processEmail({
from: eventData.from,
subject: eventData.subject,
body: emailContent.text || emailContent.html,
});
}
Bonnes pratiques de sécurité
À toujours faire
| Pratique | Pourquoi |
|---|---|
| Vérifier les signatures webhook | Empêche les événements webhook usurpés |
| Enregistrer tous les emails rejetés | Piste d'audit pour examen de sécurité |
| Utiliser des listes blanches si possible | La confiance explicite est plus sûre que le filtrage |
| Limiter le débit du traitement des emails | Empêche une charge de traitement excessive |
| Séparer la gestion des entrées fiables/non fiables | Les niveaux de risque différents ont besoin d'un traitement différent |
À ne jamais faire
| Anti-modèle | Risque |
|---|---|
| Traiter les emails sans validation | N'importe qui peut contrôler votre agent |
| Faire confiance aux en-têtes d'email pour l'authentification | Les en-têtes sont facilement usurpés |
| Exécuter du code à partir du contenu d'email | L'entrée non fiable ne devrait jamais s'exécuter comme du code |
| Stocker le contenu d'email dans les prompts textuellement | L'entrée non fiable mélangée aux prompts peut altérer le comportement de l'agent |
| Donner aux emails non fiables un accès complet à l'agent | Limitez les capacités au minimum nécessaire |
Endpoint webhook
Après avoir choisi votre niveau de sécurité et configuré votre domaine, créez un endpoint webhook. L'endpoint webhook DOIT être une route POST. Resend envoie tous les événements webhook en tant que requêtes POST.
Critique : Utilisez le corps brut pour la vérification. La vérification de signature webhook nécessite le corps de la requête brut.
- Next.js App Router : Utilisez
req.text()(pasreq.json())- Express : Utilisez
express.raw({ type: 'application/json' })sur la route webhook
Next.js App Router
// app/webhook/route.ts
import { Resend } from 'resend';
import { NextRequest, NextResponse } from 'next/server';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: NextRequest) {
try {
const payload = await req.text();
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') {
// Webhook payload only includes metadata, not email body
const { data: email } = await resend.emails.receiving.get(
event.data.email_id
);
// Apply the security level chosen above
await processEmailForAgent(event.data, email);
}
return new NextResponse('OK', { status: 200 });
} catch (error) {
console.error('Webhook error:', error);
return new NextResponse('Error', { status: 400 });
}
}
Express
import express from 'express';
import { Resend } from 'resend';
const app = express();
const resend = new Resend(process.env.RESEND_API_KEY);
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
try {
const payload = req.body.toString();
const event = resend.webhooks.verify({
payload,
headers: {
'svix-id': req.headers['svix-id'],
'svix-timestamp': req.headers['svix-timestamp'],
'svix-signature': req.headers['svix-signature'],
},
secret: process.env.RESEND_WEBHOOK_SECRET,
});
if (event.type === 'email.received') {
const sender = event.data.from.toLowerCase();
if (!isAllowedSender(sender)) {
console.log(`Rejected email from unauthorized sender: ${sender}`);
res.status(200).send('OK'); // Return 200 even for rejected emails
return;
}
const { data: email } = await resend.emails.receiving.get(event.data.email_id);
await processEmailForAgent(event.data, email);
}
res.status(200).send('OK');
} catch (error) {
console.error('Webhook error:', error);
res.status(400).send('Error');
}
});
app.get('/', (req, res) => res.send('Agent Email Inbox - Ready'));
app.listen(3000, () => console.log('Webhook server running on :3000'));
Pour l'enregistrement des webhooks via API, la configuration du tunneling, le secours svix et le comportement de retry, voir references/webhook-setup.md.
Envoyer des emails depuis votre agent
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
async function sendAgentReply(to: string, subject: string, body: string, inReplyTo?: string) {
if (!isAllowedToReply(to)) {
throw new Error('Cannot send to this address');
}
const { data, error } = await resend.emails.send({
from: 'Agent <agent@example.com>',
to: [to],
subject: subject.startsWith('Re:') ? subject : `Re: ${subject}`,
text: body,
headers: inReplyTo ? { 'In-Reply-To': inReplyTo } : undefined,
});
if (error) throw new Error(`Failed to send: ${error.message}`);
return data.id;
}
Pour la documentation complète d'envoi, installez la skill resend.
Variables d'environnement
# Requis
RESEND_API_KEY=re_xxxxxxxxx
RESEND_WEBHOOK_SECRET=whsec_xxxxxxxxx
# Configuration de sécurité
SECURITY_LEVEL=strict # strict | domain | filtered | sandboxed
ALLOWED_SENDERS=you@email.com,trusted@example.com
ALLOWED_DOMAINS=example.com
OWNER_EMAIL=you@email.com # Pour les notifications de sécurité
Erreurs courantes
| Erreur | Correction |
|---|---|
| Pas de vérification de l'expéditeur | Toujours valider qui a envoyé l'email avant le traitement |
| Faire confiance aux en-têtes d'email | Utiliser la vérification webhook, pas les en-têtes d'email pour l'authentification |
| Traitement identique pour tous les emails | Différencier les expéditeurs fiables et non fiables |
| Messages d'erreur verbeux | Garder les réponses d'erreur génériques pour éviter de révéler la logique interne |
| Pas de limitation de débit | Mettre en place des limites de débit par expéditeur. Voir references/advanced-patterns.md |
| Traiter le HTML directement | Supprimer le HTML ou utiliser du texte uniquement pour réduire la complexité et le risque |
| Pas d'enregistrement des rejets | Enregistrer tous les événements de sécurité pour l'audit |
| Utiliser des URLs de tunnel éphémères | Utiliser des URLs persistantes (Tailscale Funnel, ngrok payant) ou déployer en production |
Utiliser express.json() sur la route webhook |
Utiliser express.raw({ type: 'application/json' }) — l'analyse JSON casse la vérification de signature |
| Renvoyer un code autre que 200 pour les emails rejetés | Toujours renvoyer 200 pour confirmer la réception — sinon Resend réessaie |
| Ancienne version du SDK Resend | emails.receiving.get() et webhooks.verify() nécessitent des versions récentes du SDK — voir Exigences de version du SDK |
Test
Utilisez les adresses de test de Resend pour le développement :
delivered@resend.dev— Simule une livraison réussiebounced@resend.dev— Simule un rebond définitif
Pour les tests de sécurité, envoyez des emails de test à partir d'adresses non autorisées pour vérifier que le rejet fonctionne correctement.
Checklist de vérification rapide :
- Le serveur fonctionne :
curl http://localhost:3000doit retourner une réponse - Le tunnel fonctionne :
curl https://<your-tunnel-url>doit retourner la même réponse - Le webhook est actif : Vérifier le statut dans Resend dashboard → Webhooks
- Envoyer un email de test à partir d'une adresse autorisée et vérifier les logs du serveur
Skills connexes
- Pour la documentation complète d'envoi et de réception, installez la skill
resend