Frameworks and agents · Updated 2026-09-22
Send email from Express
A POST route on an app you can mount anywhere, returning the message id or the code and fix of a refusal.
To send email from an Express app, add one POST route that calls AgentiSend and returns the message id. The app below is exported without calling listen, so it can be mounted, tested, or started from a separate entry point. It is executed against a real API on every build of this site's repository.
Install
pnpm add express agentisendEnvironment
| Variable | Required | What it is |
|---|---|---|
AGENTISEND_API_KEY | yes | A key with sending_access. |
MAIL_FROM | yes | The From address, on a domain you have verified. |
AGENTISEND_BASE_URL | no | Defaults to https://api.agentisend.com. |
The route
/**
* Express — a POST route that sends a transactional email.
*
* The app is exported without calling `listen`, so it can be mounted, tested,
* or started from a separate entry point.
*/
import express, { type Express } from 'express';
import { AgentiSend, AgentiSendError } from 'agentisend';
const agentisend = new AgentiSend();
function mailFrom(): string {
const from = process.env.MAIL_FROM;
if (!from) throw new Error('Set MAIL_FROM to an address on a domain you have verified.');
return from;
}
export const app: Express = express();
app.use(express.json());
app.post('/send', (req, res) => {
void (async () => {
const { email, subject } = req.body as { email?: string; subject?: string };
if (!email) {
res.status(400).json({ error: 'email is required' });
return;
}
try {
const { id } = await agentisend.emails.send(
{
from: mailFrom(),
to: email,
subject: subject ?? 'Your order shipped',
text: 'Tracking details are in your account.',
},
{ idempotencyKey: `shipped/${email}` },
);
res.json({ id });
} catch (err) {
if (err instanceof AgentiSendError) {
res.status(err.status).json({ code: err.code, fix: err.fix });
return;
}
res.status(500).json({ error: 'send failed' });
}
})();
});
export default app;Start it
import app from './server';
app.listen(3000);curl -X POST localhost:3000/send \
-H 'content-type: application/json' \
-d '{"email":"you@example.com"}'What comes back when it goes wrong
Every refused request carries code, message, fix and docs_url. The route answers with the same status and forwards code and fix. The error catalogue lists every code.