How to Receive Email via Webhook
A complete guide to receiving inbound email as HTTP webhooks. Set up in minutes with code examples for Node.js, Python, and cURL.
How It Works
Mailhooks acts as a bridge between the email world and your application. When someone sends an email to your domain, Mailhooks receives it, parses it into structured JSON, and forwards it to your application via an HTTP POST webhook. Here's the flow:
Parsed to JSON
Mailhooks receives the raw MIME, parses headers, body, and attachments into a clean, consistent JSON structure.
Webhook sent
An HTTP POST request is sent to your endpoint with the JSON payload. Your app processes it like any other API request.
Add Your Domain
After signing up, navigate to the Domains section in your dashboard and click "Add Domain". Enter the domain you want to receive email on — for example, mail.yourdomain.com.
mail.yourdomain.com instead of your root domain to avoid conflicts with existing email services.Configure DNS Records
Mailhooks provides the DNS records you need to add to your domain. These tell other mail servers to route inbound email to Mailhooks. You'll typically need:
MX Record
Points inbound email to Mailhooks' mail servers. Add the provided MX record to your DNS configuration.
TXT Record (SPF)
Authorizes Mailhooks to receive email on your domain's behalf.
DNS changes typically propagate within 5-30 minutes. Once verified, you can start receiving email immediately.
Create a Webhook Endpoint
Your webhook endpoint is a URL on your server that receives HTTP POST requests from Mailhooks. It should accept JSON, verify the request, and return a 200 status quickly.
See the code examples below for complete implementations in Node.js, Python, and more.
Connect in Mailhooks
Go to the Webhooks section in your dashboard and create a new webhook. Enter your endpoint URL and select the events you want to receive (e.g., email.received).
For integrations like Notion, Discord, or n8n, you can use our built-in connectors instead of a custom webhook — no code required.
Send a Test Email
Send an email to any address at your domain. Mailhooks will receive it, parse it, and deliver it to your webhook. You should see the JSON payload arrive at your endpoint within seconds.
Example test addresses:
[email protected][email protected]- Any address at your domain will work — no configuration needed per address
Code Examples
Here are complete examples for receiving Mailhooks webhooks in popular languages and frameworks. Each example shows how to set up a webhook endpoint, verify the request, and process the email payload.
Node.js / Express
const express = require('express');
const app = express();
// Parse JSON bodies
app.use(express.json());
// Webhook endpoint for Mailhooks
app.post('/api/webhooks/mailhooks', async (req, res) => {
const { event, data } = req.body;
if (event === 'email.received') {
const { from, to, subject, text, html, attachments } = data;
console.log(`New email from ${from}`);
console.log(`Subject: ${subject}`);
console.log(`Body: ${text || '(HTML only)'}`);
// Process attachments
for (const attachment of attachments) {
console.log(`Attachment: ${attachment.filename} (${attachment.contentType})`);
// Download from attachment.url when needed
// const file = await fetch(attachment.url);
}
// Your business logic here:
// - Create a support ticket
// - Forward to Slack
// - Store in database
// - Trigger automation
}
// Always return 200 quickly
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});Prefer TypeScript? Use our official @mailhooks/sdk package for type-safe API access.
Python / Flask
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
@app.route('/api/webhooks/mailhooks', methods=['POST'])
def handle_mailhooks_webhook():
payload = request.json
event = payload.get('event')
data = payload.get('data', {})
if event == 'email.received':
from_addr = data.get('from')
subject = data.get('subject')
text_body = data.get('text', '(HTML only)')
attachments = data.get('attachments', [])
print(f"New email from {from_addr}")
print(f"Subject: {subject}")
print(f"Body: {text_body}")
# Process attachments
for attachment in attachments:
filename = attachment.get('filename')
content_type = attachment.get('contentType')
url = attachment.get('url')
print(f"Attachment: {filename} ({content_type})")
# Download when needed:
# response = requests.get(url)
# Your business logic here:
# - Create a support ticket
# - Forward to Slack
# - Store in database
# - Trigger automation
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=3000)cURL / REST API
You can also retrieve emails via the REST API without webhooks:
# List all received emails
curl -H "x-api-key: mh_your_api_key_here" \
https://api.mailhooks.dev/v1/emails
# Get a specific email
curl -H "x-api-key: mh_your_api_key_here" \
https://api.mailhooks.dev/v1/emails/msg_abc123
# Filter by sender
curl -H "x-api-key: mh_your_api_key_here" \
"https://api.mailhooks.dev/v1/[email protected]"
# Get email body only
curl -H "x-api-key: mh_your_api_key_here" \
https://api.mailhooks.dev/v1/emails/msg_abc123/bodyWebhook Payload
Every webhook delivery contains a consistent JSON payload with all email data structured and ready to use:
{
"event": "email.received",
"timestamp": "2025-01-15T10:30:00Z",
"data": {
"id": "msg_abc123",
"from": "[email protected]",
"fromName": "John Smith",
"to": "[email protected]",
"subject": "Question about my order",
"text": "Hi, I have a question about order #12345...",
"html": "Hi, I have a question about order #12345...
",
"headers": {
"message-id": "",
"date": "Wed, 15 Jan 2025 10:30:00 +0000",
"content-type": "multipart/mixed; boundary=..."
},
"attachments": [
{
"filename": "invoice.pdf",
"contentType": "application/pdf",
"size": 45678,
"url": "https://files.mailhooks.dev/..."
}
]
}
} Best Practices
Return 200 quickly
Process the webhook asynchronously. Return a 200 status as fast as possible — put the payload on a queue and process it in the background.
Verify webhook signatures
Use the webhook signing secret from your dashboard to verify that incoming requests are genuinely from Mailhooks. This prevents abuse and ensures data integrity.
Use idempotent handlers
Mailhooks may deliver the same webhook more than once in rare cases. Design your handler to be idempotent — use the email ID to deduplicate.
Download attachments on demand
Attachment URLs are signed and time-limited. Download them within 24 hours. Don't store the URLs — download the file and store it in your own system.
Common Use Cases
Once you're receiving email webhooks, here are some popular patterns: