Skip to content

Documentation

Receive webhooks in Express.

Read the raw body, verify the signature, return a 2xx.

Before you start

You need a verified sending domain (see Domains) and an API key (under API keys in the dashboard; it is shown once). Keep the key in an environment variable on your server, never in code that runs in a browser or an app.

Install

Add the client library, which includes the verification helper.

Terminal
npm install mailtruss express

The handler

Read the raw request body, as express.json() would re-serialise it and break the signature. verifyWebhook checks the signature and the timestamp and returns the parsed event. Set MAILTRUSS_WEBHOOK_SECRET to the endpoint's signing secret.

server.js
import express from "express";
import { verifyWebhook } from "mailtruss";
​
const app = express();
​
// Verify the signature over the RAW body: express.json() would re-serialise it
// and break the signature.
app.post("/webhooks/mailtruss", express.raw({ type: "application/json" }), async (req, res) => {
try {
const secret = process.env.MAILTRUSS_WEBHOOK_SECRET;
const event = await verifyWebhook(req.body.toString("utf8"), req.headers, secret);
if (event.type === "email.bounced") console.log("bounced:", event.data.email_id);
res.sendStatus(200); // any 2xx within 10 seconds counts as delivered
} catch {
res.sendStatus(400);
}
});
​
export default app;

Respond quickly

Return any 2xx within 10 seconds. Anything else is retried with backoff for a day, and each delivery can repeat, so use the webhook-id header to de-duplicate. The full list of events and the retry schedule are on the Webhooks page.

Try it without sending real mail

Send to delivered@mailtruss.test first. It works before any domain is verified and reaches no real mailbox, so you can check your code and see the recorded timeline. Then try bounced@mailtruss.test to see what a bounce looks like. All the test addresses are listed under Sending.

See what happened

Open the message under Emails in the dashboard: it shows the recorded timeline, what each event proves, and a diagnosis if something went wrong. Or fetch it with GET /api/v1/emails/:id/events. To be told as it happens, add a webhook.

If it fails

API requests answer with an error name and message. The common ones:

  • 403 invalid_api_key or 401 missing_api_key: the key is wrong, revoked or not sent. Send it as Authorization: Bearer ms_live_….
  • 403 domain_not_verified: the from address is on a domain that is not verified. Publish the DNS records and re-check.
  • 422 validation_error: fix the field the message names. Nothing was sent and no quota was used.
  • 429 rate_limit_exceeded: back off for the Retry-After header. See rate limits.

Problems that happen after a message is accepted (bounces, complaints) are explained under delivery errors.

Other guides

Last updated

Something wrong or unclear on this page?

Report an issue