Give the request a way in.
Use a forwarding address or a receiving subdomain to bring the customer’s email into your application.
Bring received messages, content, and attachments into your application. Start the next workflow with the details your customer has already sent.
Could we move booking FN–1042 to the afternoon? The original booking is attached.
event: email.receivedmessage: rem_example_fn1042 Verify the event.Read the content.Start the application workflow.
Could we move booking FN–1042 to the afternoon? The original booking is attached.
from alex@example.comsubject A little question about Friday.text Could we move booking FN–1042 to the afternoon? attachment name booking.pdf type application/pdf
from alex@example.comsubject A little question about Friday.text Could we move booking FN–1042 to the afternoon? attachment name booking.pdf type application/pdf
Companies that trust Bird across their communications.
Read Bird customer storiesA reply, document, or request can be the beginning of your next application workflow. Receive the content without making your team run an inbound mail server.
Use a forwarding address or a receiving subdomain to bring the customer’s email into your application.
Read parsed text, message details, and attachments so your workflow starts with what the customer supplied.
Use the incoming-message event to queue work in your application, with a durable record for recovery.
A server-side acceptance handler: verifies the raw body and durably inserts each webhook-id once. Your worker processes the inbox, checks sender authentication, and owns business actions. Prepare the durable inbox table shown in the sample, then use the webhook guide for retries and recovery.
Open the implementation guide →npm install @messagebird/sdk pgimport { BirdClient } from "@messagebird/sdk";
import { Pool } from "pg";
const bird = new BirdClient({
apiKey: process.env.BIRD_API_KEY,
webhooks: { secret: process.env.BIRD_WEBHOOK_SECRET }
});
const db = new Pool({ connectionString: process.env.DATABASE_URL });
// Prepare PostgreSQL once before serving this handler:
// CREATE TABLE bird_inbound_inbox (
// delivery_id text PRIMARY KEY, payload jsonb NOT NULL,
// received_at timestamptz NOT NULL DEFAULT now()
// );
// A separate worker owns processing and safe business retries.
export async function POST(request) {
const rawBody = await request.text();
const headers = Object.fromEntries(request.headers);
let event;
try {
event = bird.webhooks.unwrap(rawBody, headers);
} catch {
return new Response("Invalid signature", { status: 400 });
}
if (event.type !== "email.received") return new Response(null, { status: 204 });
const deliveryId = headers["webhook-id"];
if (!deliveryId) return new Response("Missing delivery ID", { status: 400 });
try {
await db.query(
`INSERT INTO bird_inbound_inbox (delivery_id, payload)
VALUES ($1, $2::jsonb) ON CONFLICT (delivery_id) DO NOTHING`,
[deliveryId, JSON.stringify(event)]
);
} catch {
return new Response("Retry later", { status: 503 });
}
return new Response(null, { status: 202 });
}
Inspect the received content, verify the event and preview durable acceptance. The booking stays unchanged until your application checks authority and availability.
Create a generated forwarding address, then configure your existing inbox to forward to it. This does not create a stored Agent Mailbox or require a DNS change.
Register and DKIM-verify a dedicated receiving subdomain, enable receiving and publish that registration’s MX records. Preserve your corporate domain’s current mail routing.
Could we move booking FN–1042 to the afternoon? The original booking is attached.
Bird retains received messages for 30 days. Your application owns durable event acceptance, business retries and the retention of any content it stores.
Need durable threads and replies? ↗Could we move booking FN–1042 to the afternoon?
GET /v1/email/inbound-messages/{id}/body<p>Could we move booking FN–1042 to the afternoon?</p>
GET /v1/email/inbound-messages/{id}/bodybooking.pdf
Content type: application/pdf
GET /v1/email/inbound-messages/{id}/attachments
GET /v1/email/inbound-messages/{id}/attachments/{attachment_id}From: Alex Lee <alex@example.com>
Subject: A little question about Friday.
MIME-Version: 1.0
GET /v1/email/inbound-messages/{id}/rawwebhook-id: evt_example_fn1042
{
"type": "email.received",
"timestamp": "2026-09-17T10:42:00Z",
"data": {
"inbound_message_id": "rem_example_fn1042",
"from": "alex@example.com",
"authentication": "unknown",
"spf_pass": true,
"dkim_pass": true,
"dmarc_pass": null
}
}Selected fields and content are illustrative excerpts. The event identifies stored content; it does not contain attachment bytes. Fetch the body, raw MIME or attachments through their separate reads.
Verify the signature over the raw body. Durably accept this webhook-id before acknowledging the delivery.
Example: 202 accepted after one durable inbox write. Sender authentication is unknown, so the application holds the request for review. No booking was changed and no confirmation was sent.
Example replay: the unique delivery ID already exists. No second work item is created. Business processing still needs its own safe retries.
Example: storage failed, return 503. No work was durably accepted. Repair storage and let the documented webhook retry policy redeliver the event.
Example: invalid or stale signature, return 400. Do not accept work or trust this payload. Check the signing secret and deployment before a retry.
A valid webhook signature authenticates Bird’s delivery. It does not verify the email sender. Unknown or missing authentication remains unverified; SPF or DKIM alone does not establish alignment with the visible sender.
Read the receiving setup ↗A generated forwarding address receives mail from an existing inbox. Use a dedicated, verified receiving subdomain when the address itself should belong to your brand.
Read the product guide ↗Documented behavior; confirm current access and setup in your workspace.Bring a parsed message and its attachments into your application workflow through events.
Set up receiving ↗Add a durable address, retained threads, and reply operations when the inbox is part of your product.
Explore Agent Mailboxes ↗Bring inbound messages into your application, send a response with the Email API, or use Mailboxes when the conversation needs a home.
Alex asks to change booking FN–1042 and attaches the receipt.
Alex Lee · Original booking attached
Keep the thread when the workflow needs an ongoing agent conversation.
Alex Lee · Friday, 14:00Your app sends a confirmation after its booking operation succeeds.
Compare event ingestion with a persistent mailbox, including retention and reply decisions.
Read the field guide →Forwarding addresses, MX records, and parsed messages.
Raw-body signature verification and stable delivery IDs.
List attachment metadata, then retrieve bytes by attachment ID.
A persistent address and conversation lifecycle.
Plan receiving volume, attachment handling, and application processing with the email your business sends. Talk to sales about the exact allowances your workflow needs.
Review Email plans ↗Confirm the receiving scope of your Email setup.
Une clé API de test est disponible immédiatement. L'accès production se débloque dès que vous ajoutez un moyen de paiement et vérifiez un expéditeur.
Lire la doc