Recipe: Send email from agent frameworks
Wrap Notify in a LangChain, CrewAI, or Vercel AI SDK tool — one fetch to POST /api/email/send.
Use this when you’re building an agent in code (LangChain / LangGraph, CrewAI, Vercel AI SDK) and the model should call a send_email tool. Still transactional, not newsletters.
The framework only needs a tool that fetches Notify. Put NOTIFY_API_KEY in server env — never in the model prompt or client bundle.
Prerequisites
- API key (prefer a domain-locked sending_access key)
- Verified domain for production custom
from - Node or Python runtime where your agent tools run
Shared send helper (TypeScript)
export async function sendWithNotify(input: {
to: string;
subject: string;
html: string;
from?: string;
}) {
const res = await fetch('https://notify.cx/api/email/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NOTIFY_API_KEY!
},
body: JSON.stringify({
to: input.to,
from: input.from ?? 'noreply@your-verified-domain.com',
subject: input.subject,
html: input.html
})
});
const data = await res.json();
if (!res.ok) throw new Error(JSON.stringify(data));
return data;
}
html is preferred; message and text also work.
Vercel AI SDK
import { tool } from 'ai';
import { z } from 'zod';
import { sendWithNotify } from './notify';
export const sendEmailTool = tool({
description:
'Send a transactional email via Notify (password reset, receipt, notice). Not for newsletters.',
inputSchema: z.object({
to: z.string().email(),
subject: z.string(),
html: z.string()
}),
execute: async ({ to, subject, html }) => sendWithNotify({ to, subject, html })
});
Pass sendEmailTool in your tools map when calling generateText / streamText.
LangChain / LangGraph (JS)
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import { sendWithNotify } from './notify';
export const sendEmailTool = tool(
async ({ to, subject, html }) => {
const data = await sendWithNotify({ to, subject, html });
return JSON.stringify(data);
},
{
name: 'send_email',
description:
'Send a transactional email via Notify. Use for receipts, resets, notices — not newsletters.',
schema: z.object({
to: z.string().email(),
subject: z.string(),
html: z.string()
})
}
);
Bind the tool to your agent / graph the same way you bind any other tool. Python LangChain is the same idea: an @tool that httpx/requests POSTs to the same URL with x-api-key.
CrewAI
Expose a CrewAI tool (or a plain Python function registered as a tool) that POSTs to https://notify.cx/api/email/send with headers Content-Type: application/json and x-api-key: $NOTIFY_API_KEY, and a JSON body of to / from / subject / html. Keep the key in env; describe the tool as transactional-only so the agent doesn’t treat it as a blast mailer.
Guardrails
- Run tools on the server (or a trusted worker), not in the browser.
- Prefer asking the user (or a human approval step) before send in high-risk agents.
- Production custom
fromneeds a verified domain.
Sandbox vs production
Use sandbox vs production or POST /api/email/send/test until the domain is verified.