Webhook email entrant
Transformez les emails de votre propre boîte
en JSON analysé sur votre serveur.
Les services de parsing veulent vos enregistrements MX ou une adresse de transfert. Connectez plutôt la boîte que vous utilisez déjà : chaque nouvel email arrive sur votre URL avec son objet, son HTML, ses pièces jointes et son fil, et vous répondez depuis la même adresse.
Pressé ? Résumez cet article avec une IA
La réponse courte
Comment envoyer les emails entrants vers un webhook ?
Connectez la boîte elle-même. Unlimited Messaging se connecte à votre boîte mail existante en IMAP (Gmail avec un mot de passe d'application, votre propre domaine, tout hébergeur IMAP), surveille sa boîte de réception et envoie chaque nouvel email à votre URL sous forme d'événement JSON signé, message.received, avec objet, texte, HTML, pièces jointes et identifiants de fil. Vos MX restent en place, contrairement à SendGrid Inbound Parse. Les webhooks sont inclus dans les offres payantes Medium et Max.
Les services de parsing se placent devant le courrier. SendGrid vous demande de pointer le MX d'un nom d'hôte dédié vers mx.sendgrid.net, puis envoie du multipart/form-data (ou le MIME brut) à votre URL. Postmark donne à chaque serveur une adresse du type [email protected], vers laquelle vous transférez depuis Gmail ou via l'inbound domain forwarding, et son traitement entrant est réservé à l'offre Pro, à partir de 16,50 $ par mois. Dans les deux cas, l'adresse à laquelle vos clients écrivent change, ou son courrier est relayé.
Unlimited Messaging lit la boîte à laquelle vos clients écrivent déjà. Une passerelle garde une connexion IMAP IDLE sur sa boîte de réception, en lecture seule : un nouvel email est pris dès que le serveur l'annonce. L'email est stocké, ses pièces jointes aussi (20 par email au plus), et votre webhook reçoit un seul corps JSON : externalId est le Message-ID, conversation.id la racine de son fil, replyTo le message auquel il répond.
La réponse boucle la boucle : POST /message avec replyToMessageId envoie depuis la même boîte, par son propre serveur SMTP, avec Re: et les en-têtes In-Reply-To et References, et range une copie dans ses Éléments envoyés. Le fil reste un seul fil dans la messagerie de votre client.
Avant de connecter : configurer Gmail en IMAP avec un mot de passe d'application, et pourquoi envoyer depuis votre propre boîte compte.

Les événements
Que contient le webhook d'email entrant ?
L'email partage l'enveloppe de tous les canaux et ajoute trois champs : subject, html et attachments.
message.received
Un nouvel email est arrivé dans la boîte de réception. content est le corps texte, ou le HTML converti en texte quand l'email n'a pas de partie texte ; html est le corps tel que reçu, non fiable, à nettoyer avant tout affichage.
attachments
Chaque fichier dans l'ordre, 20 par email au plus : url (la copie stockée), filename, mimeType, size, et contentId pour une image intégrée que le HTML référence en cid:. Le premier est aussi recopié dans mediaUrl.
Fils de discussion
externalId est le Message-ID RFC 5322 sans chevrons. conversation.id est la racine du fil (premier élément de References, sinon In-Reply-To, sinon l'email lui-même) : tous les emails d'un fil le partagent.
message.sent et message.status
Vos réponses sont annoncées en message.sent, et un rebond définitif passe le message en UNDELIVERABLE (message.status). L'adresse en échec est alors suspendue 30 jours sur cette boîte pour protéger sa réputation.
account.status_changed
La boîte s'est déconnectée, par exemple parce que le serveur a refusé les identifiants après un changement de mot de passe. Abonnez-vous-y pour qu'une boîte muette ne passe pas inaperçue.
{
"type": "message.received",
"eventId": "whd_9a4f2e61-7c3b-4d85-b0e9-5f1a8c2d7e34",
"occurredAt": "2026-11-09T14:05:12.000Z",
"data": {
"message": {
"id": "msg_3f8a1c2e-9d4b-4e7a-8b6c-2d1e0f9a8b7c",
"externalId": "[email protected]",
"direction": "IN",
"fromMe": false,
"content": "Hi, please find the signed quote attached. Claire",
"sentAt": "2026-11-09T14:05:12.000Z",
"receivedAt": "2026-11-09T14:05:12.000Z",
"sender": "[email protected]",
"senderId": "[email protected]",
"senderName": null,
"participant": null,
"replyTo": { "externalId": "[email protected]", "participant": null },
"mediaUrl": "https://api.unlimitedmessaging.app/message/media/stored/4c1d...",
"mediaType": "document",
"mimeType": "application/pdf",
"mediaFilename": "quote-1042-signed.pdf",
"transcript": null,
"subject": "Re: Quote #1042",
"html": "<p>Hi, please find the signed quote attached.</p><p>Claire</p>",
"attachments": [
{
"url": "https://api.unlimitedmessaging.app/message/media/stored/4c1d...",
"filename": "quote-1042-signed.pdf",
"mimeType": "application/pdf",
"size": 184320,
"contentId": null
}
]
},
"channel": {
"type": "EMAIL",
"account": { "id": "acc_8b2e4f6a-1c3d-4e5f-a7b9-0c1d2e3f4a5b", "name": "[email protected]" },
"conversation": {
"id": "[email protected]",
"isGroup": false,
"address": "[email protected]"
}
}
}
}Mise en place
Comment analyser les emails entrants en Next.js ?
Connectez la boîte, enregistrez un endpoint, vérifiez chaque POST. Ni parser MIME ni bibliothèque IMAP dans votre code.
- 01
Connectez votre boîte
Dans l'application web, ajoutez un compte email avec l'adresse et son mot de passe (un mot de passe d'application pour Gmail). Les réglages IMAP et SMTP sont détectés à partir de l'adresse.
- 02
Enregistrez l'endpoint
POST /webhooks avec votre URL et vos eventTypes, ou ajoutez-le sur la page Webhooks du tableau de bord. Le secret (whsec_...) n'est affiché qu'une fois.
- 03
Vérifiez, enregistrez, répondez
Contrôlez l'en-tête webhook-signature, faites un upsert sur eventId, récupérez les pièces jointes par leur url quand vous en avez besoin, répondez avec replyToMessageId.
curl https://api.unlimitedmessaging.app/webhooks \
-H "Authorization: Bearer $UM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/um",
"eventTypes": ["message.received", "account.status_changed"],
"description": "Inbound email"
}'
# The response carries "secret": "whsec_..." once. Store it as UM_WEBHOOK_SECRET.// app/api/webhooks/um/route.ts (Next.js App Router)
import crypto from 'node:crypto';
import { UnlimitedMessagingApiClient } from '@unlimited-messaging/sdk';
const um = new UnlimitedMessagingApiClient({ token: process.env.UM_API_KEY! });
const key = Buffer.from(process.env.UM_WEBHOOK_SECRET!.replace(/^whsec_/, ''), 'base64');
// Standard Webhooks: HMAC-SHA256 of "id.timestamp.rawBody", base64.
function verify(raw: string, id: string, ts: string, header: string) {
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = crypto.createHmac('sha256', key).update(`${id}.${ts}.${raw}`).digest('base64');
return header.split(' ').some((entry) => {
const sig = entry.startsWith('v1,') ? entry.slice(3) : '';
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
});
}
export async function POST(req: Request) {
const raw = await req.text(); // the raw body, before any JSON parsing
const h = req.headers;
if (!verify(raw, h.get('webhook-id') ?? '', h.get('webhook-timestamp') ?? '',
h.get('webhook-signature') ?? '')) {
return new Response('bad signature', { status: 401 });
}
const event = JSON.parse(raw);
if (event.type === 'message.received' && event.data.channel.type === 'EMAIL') {
const m = event.data.message;
const thread = event.data.channel.conversation.id; // same id for the whole thread
const files = m.attachments ?? []; // [{ url, filename, mimeType, size, contentId }]
await saveTicket({ eventId: event.eventId, thread, from: m.sender, subject: m.subject,
text: m.content, files }); // upsert on eventId: delivery is at least once
// Answer in the same thread, from the same mailbox.
await um.messages.messageSend({ replyToMessageId: m.id, text: 'Thanks, received. We reply within a day.' });
}
return new Response(null, { status: 200 }); // within 10 s; queue slow work
}Vibe coding
Vous codez avec Cursor, Claude Code, Lovable ou Bolt ? Collez ceci
Votre éditeur IA reçoit la route, la vérification de signature et les champs email utiles, sans inventer de parser MIME.
Add an Unlimited Messaging webhook to this app so incoming emails from my own mailbox become support tickets.
1. Create a POST route (Next.js: app/api/webhooks/um/route.ts) that reads the RAW body with req.text().
2. Verify the Standard Webhooks signature: key = base64-decode(UM_WEBHOOK_SECRET without "whsec_"); expected = base64(HMAC-SHA256(key, `${webhook-id}.${webhook-timestamp}.${rawBody}`)); accept if any space-separated entry of the webhook-signature header equals `v1,${expected}` (constant-time compare); reject timestamps more than 5 minutes off; return 401 otherwise.
3. On type "message.received" with data.channel.type "EMAIL": upsert a ticket keyed on body.eventId with data.channel.conversation.id (thread id), data.message.sender, data.message.subject, data.message.content (text) and data.message.attachments ([{ url, filename, mimeType, size, contentId }]). Treat data.message.html as untrusted: sanitise before rendering.
4. To answer, install @unlimited-messaging/sdk, read UM_API_KEY from env, and call `client.messages.messageSend({ replyToMessageId: data.message.id, text })`: it replies in the same thread from the same mailbox.
5. Return 200 within 10 seconds; queue slow work.
6. Put UM_API_KEY and UM_WEBHOOK_SECRET in .env and .env.example.
Docs: https://docs.unlimitedmessaging.app (Webhooks). Register with POST https://api.unlimitedmessaging.app/webhooks and eventTypes ["message.received"].Ce que l'on construit
Que construire sur les emails entrants ?
Tout ce qui, aujourd'hui, consiste à recopier un email dans un autre outil.
Un helpdesk sur support@
Un ticket par conversation.id, chaque réponse ajoutée, des réponses envoyées depuis support@ dans le même fil. Aucune adresse de ticketing à publier.
Tri et réponse automatique par IA
Donnez subject et content à un LLM, étiquetez et aiguillez l'email, ou envoyez une première réponse avec replyToMessageId avant qu'un humain prenne le relais.
Factures et documents entrants
Récupérez le PDF via attachments[].url et envoyez-le à votre comptabilité ou à votre OCR.
Captation de leads
Transformez les notifications de formulaire ou les emails directs en leads CRM, par adresse d'expéditeur.
Une seule boîte avec WhatsApp et SMS
Le même handler traite les événements WhatsApp et SMS : seul data.channel.type change.
Flux no-code
Pointez le webhook vers n8n, Make ou Zapier et aiguillez selon l'objet ou l'expéditeur, sans serveur.
Le tableau
Email entrant vers webhook : SendGrid, Postmark et Unlimited Messaging
Les services de parsing reçoivent le courrier d'une nouvelle adresse ou d'un nouveau nom d'hôte. Unlimited Messaging lit la boîte que vous avez déjà.
| SendGrid Inbound ParseMX sur un nom d'hôte dédié | Postmark InboundAdresse ou domaine entrant | Unlimited MessagingVotre boîte en IMAP, offres payantes | |
|---|---|---|---|
| Adresse qui reçoit | Toute adresse d'un nom d'hôte dédié au parsing | [email protected], ou un transfert vers elle | Votre adresse existante |
| Changement DNS | MX vers mx.sendgrid.net | Aucun avec un transfert ; DNS pour l'inbound domain forwarding | Aucun |
| Format du corps | multipart/form-data, ou le message MIME brut | JSON ; authentification HTTP basic dans l'URL comme protection | JSON, signé selon Standard Webhooks |
| Identifiants de fil | Dans les en-têtes à analyser | Dans les en-têtes analysés | conversation.id (racine du fil) et replyTo, prêts à l'emploi |
| Répondre depuis la même adresse | Via l'envoi SendGrid, à configurer à part | Via l'envoi Postmark, à configurer à part | replyToMessageId, par le SMTP de votre boîte, copie dans Envoyés |
| Prix | Inclus dans une offre SendGrid | Entrant sur l'offre Pro, à partir de 16,50 $ par mois | Webhooks avec Medium ou Max ; aucun frais par email |
| WhatsApp et SMS dans le même webhook | Non | Non | Oui, même enveloppe |
Vérifié le 9 novembre 2026 sur le guide de configuration de l'Inbound Parse de SendGrid, le guide des serveurs entrants et la page tarifs de Postmark (liens dans les sources).
Les contreparties
Quelles sont les limites d'une passerelle boîte mail vers webhook ?
Lire votre propre boîte supprime le travail DNS. Elle en apporte les règles.
Les webhooks sont payants
Avec l'offre Free, les emails reçus s'affichent dans la boîte de réception de l'application web, regroupés par fil. Les pousser vers votre serveur demande Medium (19 € par mois, ou 17 € par mois en annuel) ou Max.
Boîte de réception uniquement
La passerelle surveille INBOX. Un email que votre hébergeur classe en spam, ou qu'un filtre déplace dans un autre dossier, n'est jamais vu.
Pas encore d'Outlook ni de Microsoft 365
Outlook, Hotmail et Microsoft 365 exigent OAuth, prévu mais pas encore disponible. Gmail fonctionne avec un mot de passe d'application, qui demande la validation en deux étapes sur le compte Google.
20 pièces jointes par email au plus
Les fichiers au-delà du 20e ne sont pas stockés. Le HTML est transmis tel que reçu : nettoyez-le avant de l'afficher où que ce soit.
Au moins une fois, sans ordre garanti
Le même événement peut arriver deux fois, et les événements n'arrivent pas dans l'ordre des faits : faites un upsert sur eventId et triez sur sentAt.
FAQ
Questions sur les webhooks d'email entrant
Sources
Sources & références
Pour vérifier par vous-même les informations de cet article :
- Setting up the Inbound Parse webhook (MX vers mx.sendgrid.net, payload)Twilio SendGrid Docs
- Configure an inbound server (adresse entrante, JSON, transfert)Postmark
- Tarifs (traitement entrant sur l'offre Pro, dès 16,50 $ par mois)Postmark
- RFC 5322, Internet Message Format (Message-ID, In-Reply-To, References)IETF
- Se connecter avec des mots de passe d'applicationAide Compte Google
- Spécification Standard Webhooksstandardwebhooks.com
- Référence de l'API Unlimited Messaging - WebhooksUnlimited Messaging

Écrit par
Ilian · Senior Software Engineer
Ingénieur logiciel senior, il fonde et dirige plusieurs sociétés tech. Il conçoit des produits autour des API de messagerie, de l’automatisation et de l’intégration de l’IA, et partage ici ce qu’il apprend en construisant.
Votre boîte de réception, en JSON propre.
Créez un compte, connectez votre boîte mail, et activez les webhooks avec Medium ou Max. L'envoi d'emails reste gratuit sur toutes les offres.