Webhooks
Subscribe to email delivery events and receive real-time notifications.
Overview
MailSetu sends HTTP POST requests to your endpoint when email events occur. Supported events: • email.queued — Email added to send queue • email.scheduled — Scheduled send registered • email.sending — Handoff to SES started • email.delivered — Email accepted by the recipient's server • email.open — Recipient opened the email • email.click — Recipient clicked a link • email.bounce — Hard or soft bounce • email.complaint — Marked as spam • email.failed — Send failed after retries • email.canceled — Scheduled email was canceled
Create a webhook endpoint
Go to Dashboard → Webhooks → Add Endpoint. Add your HTTPS URL and select events to subscribe to.
Verify webhook signatures
Every webhook includes a X-MailSetu-Signature header. Verify it to ensure the request came from MailSetu.
import crypto from 'crypto'
export function verifyMailSetuSignature(
rawBody: string,
timestamp: string,
signature: string,
secret: string
): boolean {
const payload = `${timestamp}.${rawBody}`
const expected = 'v1=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
)
}
// In your webhook handler:
app.post('/webhooks/mailsetu', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-mailsetu-signature'] as string
const ts = req.headers['x-mailsetu-timestamp'] as string
const raw = req.body.toString()
if (!verifyMailSetuSignature(raw, ts, sig, process.env.WEBHOOK_SECRET!)) {
return res.status(401).send('Invalid signature')
}
const event = JSON.parse(raw)
console.log(event.type, event.data.emailId)
res.status(200).send('OK')
})Webhook payload example
{
"type": "email.delivered",
"data": {
"emailId": "email-xxxxxxxxxxxxxxxx",
"to": ["user@example.com"],
"from": "noreply@acme.co",
"subject": "Welcome!",
"status": "DELIVERED",
"timestamp": "2026-04-23T10:30:00.000Z"
}
}