Process inbound email
Receiving Email
Configure your domain to deliver inbound email to Mailpipe, then read messages through the API or receive real-time webhook notifications as mail arrives.
MX Records
To receive email, point your domain's MX record at Mailpipe's inbound mail server. MX records tell the internet where to deliver email addressed to your domain.
Type: MX Host: @ (root domain, e.g. example.com) Priority: 10 Value: mx.mailpipe.dev # If you also want a subdomain to receive mail (e.g. mail.example.com): Type: MX Host: mail Priority: 10 Value: mx.mailpipe.dev
You can verify that the record has propagated using dig or an online MX lookup tool:
dig MX example.com +short # Expected output: 10 mx.mailpipe.dev.
Remove conflicting MX records
If your domain already has MX records pointing at another provider (e.g., Google Workspace, Microsoft 365), remove or replace them. Multiple conflicting MX providers will cause unpredictable delivery.
Mailbox Setup
A Mailpipe mailbox is an email address that stores inbound messages. Once your MX record points at mx.mailpipe.dev, create a mailbox for each address you want to receive mail at.
Create a mailbox in the dashboard
- Go to Inbox and click + New Mailbox
- Enter the local part (e.g.,
support,hello,billing) - Select a verified domain from the dropdown
- Optionally set a display name and configure webhook delivery
- Click Create
Create a mailbox via API
curl -X POST "https://api.mailpipe.dev/v1/mailboxes" \
-H "Authorization: Bearer mp_live_your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"address": "support",
"domain_id": "dom_xxxxxxxxxxxxxxxx",
"display_name": "Support Team",
"forward_to_webhook": true
}'{
"id": "mbx_01hx8yq3vdkj1p4nze7rbc56wf",
"address": "support@example.com",
"display_name": "Support Team",
"forward_to_webhook": true,
"created_at": "2025-01-15T10:30:00.000Z"
}Mailpipe accepts mail for any mailbox you create. Mail delivered to an address that has no mailbox is rejected at the SMTP level with a 550 No such user response.
Webhooks
Webhooks let Mailpipe push a notification to your server the moment a message is received, eliminating the need to poll for new mail. Configure a webhook endpoint in the dashboard or via the API.
Registering a webhook endpoint
curl -X POST "https://api.mailpipe.dev/v1/webhooks" \
-H "Authorization: Bearer mp_live_your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/api/webhooks/mailpipe",
"events": ["message.received", "message.bounced"],
"mailbox_ids": ["mbx_01hx8yq3vdkj1p4nze7rbc56wf"]
}'Webhook payload
When a message arrives, Mailpipe sends a signed POST request to your endpoint with the following payload:
{
"id": "evt_01hx9abc123",
"event": "message.received",
"created_at": "2025-01-15T10:30:00.000Z",
"data": {
"id": "msg_01hx8yq3vdkj1p4nze7rbc56wf",
"mailbox_id": "mbx_01hx8yq3vdkj1p4nze7rbc56wf",
"mailbox_address": "support@example.com",
"from": "customer@example.com",
"to": ["support@example.com"],
"subject": "Need help with my order",
"textBody": "Hello, I have a question about order #12345...",
"htmlBody": "<p>Hello, I have a question...</p>",
"attachments": [],
"headers": {
"message-id": "<abc123@example.com>",
"date": "Mon, 15 Jan 2025 10:30:00 +0000"
},
"received_at": "2025-01-15T10:30:00.000Z"
}
}Verifying webhook signatures
Every webhook request includes an X-Mailpipe-Signature header. Verify this signature to confirm the request genuinely came from Mailpipe:
import crypto from 'crypto';
export function verifyWebhook(
payload: string, // raw request body as string
signature: string, // X-Mailpipe-Signature header value
secret: string // MAILPIPE_WEBHOOK_SECRET env var
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Next.js App Router example
export async function POST(req: Request) {
const payload = await req.text();
const sig = req.headers.get('x-mailpipe-signature') ?? '';
if (!verifyWebhook(payload, sig, process.env.MAILPIPE_WEBHOOK_SECRET!)) {
return new Response('Unauthorized', { status: 401 });
}
const event = JSON.parse(payload);
// Handle event.event === 'message.received' ...
return new Response('OK', { status: 200 });
}Your endpoint must return a 2xx response within 10 seconds. Failed deliveries are retried up to 5 times with exponential back-off. See the Webhooks guide for full retry semantics.
Message Storage
All inbound messages are stored in Mailpipe's Supabase-backed database and accessible via the REST API regardless of whether webhooks are configured.
Reading messages via API
# List the 20 most recent unread messages curl "https://api.mailpipe.dev/v1/messages?mailbox_id=mbx_01hx8&unread=true&limit=20" \ -H "Authorization: Bearer mp_live_your-api-key-here"
curl "https://api.mailpipe.dev/v1/messages/msg_01hx8yq3vdkj1p4nze7rbc56wf" \ -H "Authorization: Bearer mp_live_your-api-key-here"
const client = new MailpipeClient({ apiKey: process.env.MAILPIPE_API_KEY });
// List unread messages
const { data: messages } = await client.messages.list({
mailbox_id: 'mbx_01hx8yq3vdkj1p4nze7rbc56wf',
unread: true,
limit: 20,
});
// Fetch full message
const message = await client.messages.get('msg_01hx8yq3vdkj1p4nze7rbc56wf');
console.log(message.subject, message.textBody);
// Mark as read
await client.messages.update('msg_01hx8yq3vdkj1p4nze7rbc56wf', { is_read: true });Messages are stored for 90 days on the Free plan and 1 year on Pro and above. Attachments count toward your storage quota. See the Supabase integration guide to query message data directly from your own database client.
Polling vs. Webhooks
Mailpipe supports two patterns for consuming inbound messages. The right choice depends on your use case.
Polling
Periodically call GET /v1/messages to check for new messages. Simple to implement but introduces latency equal to your polling interval.
Webhooks
Mailpipe calls your endpoint the instant mail arrives. Real-time and efficient, but requires a publicly reachable HTTPS endpoint.
Recommendation
Use webhooks for production applications where low latency matters (e.g., customer support inboxes, automated reply systems). Use pollingfor scripts, batch processing, or development environments where you don't have a public endpoint. Many applications use both: webhooks for real-time processing and the polling API as a fallback to reconcile missed events.
Still have questions?
We can help with anything from setup to scaling.