Integration
Send emails from Express with Postkit
Send transactional emails from Express.js middleware and route handlers. A single POST endpoint is all you need.
1. Set your API key
# .env POSTKIT_API_KEY=pk_live_...
2. Send an email
typescript
// routes/email.js
import express from "express";
const router = express.Router();
router.post("/send", async (req, res) => {
const { to, name } = req.body;
const response = await fetch("https://api.postkit.eu/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POSTKIT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "hello@yourapp.eu",
to,
subject: "Welcome aboard!",
html: `<h1>Welcome, ${name}!</h1>`,
}),
});
const data = await response.json();
res.json(data);
});
export default router;3. Handle webhooks
Postkit sends delivery events (sent, delivered, bounced, opened, clicked) via HMAC-SHA256 signed webhooks following the Standard Webhooks specification.
typescript
// routes/webhooks.js
import express from "express";
import crypto from "crypto";
const router = express.Router();
router.post(
"/postkit",
express.raw({ type: "application/json" }),
(req, res) => {
const body = req.body.toString();
const signature = req.headers["webhook-signature"] ?? "";
const timestamp = req.headers["webhook-timestamp"] ?? "";
const msgId = req.headers["webhook-id"] ?? "";
const secret = Buffer.from(
process.env.POSTKIT_WEBHOOK_SECRET.replace("whsec_", ""),
"base64"
);
const content = `${msgId}.${timestamp}.${body}`;
const expected = crypto
.createHmac("sha256", secret)
.update(content)
.digest("base64");
const valid = signature.split(" ").some((sig) => {
const val = sig.replace(/^v1,/, "");
return crypto.timingSafeEqual(
Buffer.from(val, "base64"),
Buffer.from(expected, "base64")
);
});
if (!valid) return res.status(401).json({ error: "Invalid signature" });
const event = JSON.parse(body);
console.log("Postkit event:", event.type);
res.json({ received: true });
}
);
export default router;