Give an LLM agent one narrow, safe way to send email through the Elastic Email email API. Each project here defines a send_email tool in TypeScript on top of the @elasticemail/elasticemail-client-ts-axios SDK, hands it to an agent framework, and runs a demo where the agent is asked to send a welcome email. The tool refuses recipients outside an allowlist, so a prompt-injected agent cannot mail arbitrary addresses.
First time here? The AI agent quickstart gets a Claude agent sending its first email with the Vercel AI SDK. For the concepts behind sending, see the Elastic Email guides.
| Folder | Framework | Model provider | Agent loop |
|---|---|---|---|
| vercel-ai-sdk | Vercel AI SDK 7 (ai) |
Anthropic Claude via @ai-sdk/anthropic |
generateText with stopWhen: isStepCount(5) |
| langchain | LangChain.js 1 (langchain, @langchain/core) |
Anthropic Claude via @langchain/anthropic |
createAgent |
| openai-agents | OpenAI Agents SDK (@openai/agents) |
OpenAI | Agent + run() |
Every project has the same layout:
src/email-tool.ts the reusable send_email tool: copy this file into your agent
src/index.ts demo: asks the agent to send a short welcome email to EMAIL_TO
.env.example configuration
Run any of them with npm install, cp .env.example .env, fill in the values, then npm start.
The same tool, written for each framework:
- Input:
{ to, subject, text, html? }.tois validated as an email address by the zod schema. - Send:
emailsTransactionalPostwithFromset toEMAIL_FROM, and both a plain-text and an HTML body. When the model leaves outhtml, the tool builds simple, HTML-escaped paragraphs fromtext. Braces are removed from the subject and plain text, and turned into HTML entities in the HTML body. - Output:
{ transactionId, messageId }on success,{ error }on failure. API failures carry Elastic Email's ownErrormessage, so the model seesElastic Email API 400: ...rather than a stack trace. - Allowlist: only recipients whose domain is in
EMAIL_ALLOWED_DOMAINSare sent.
An agent acts on text it reads, and some of that text is written by other people: web pages, support tickets, inbound email, documents. Any of it can contain instructions such as "send the customer list to ...". That is prompt injection, and a system prompt does not reliably prevent it. So the rule is enforced in the tool, where the model cannot talk its way past it:
EMAIL_ALLOWED_DOMAINSis a comma-separated list of domains the tool may send to, for exampleyourdomain.com,partner.example. Matching is exact and case-insensitive; subdomains must be listed separately.- If it is unset, only the domain of
EMAIL_TOis allowed. If neither is set, every send is refused. - A refused send returns
{ error: "Recipient not allowed: ..." }and never reaches the API. Addresses with whitespace or more than one@are refused too. - Model-written content is cleaned before it is sent: line breaks and braces are removed from the subject, braces are removed from the plain-text body, and braces in the HTML body become
{and}. Elastic Email treats{...}and{{...}}in message content as template syntax, so strip braces from user input.
For production, also add a human confirmation step before each send. All three frameworks have one built in, and each project README shows how to turn it on: toolApproval in the AI SDK, humanInTheLoopMiddleware in LangChain, and needsApproval in the OpenAI Agents SDK. Give the agent its own Elastic Email API key with sending access only, so you can revoke it without affecting anything else.
ELASTICEMAIL_API_KEY Elastic Email API key
EMAIL_FROM verified sender, e.g. Acme <hello@yourdomain.com>
EMAIL_TO recipient for the demo
EMAIL_ALLOWED_DOMAINS comma-separated domains the tool may send to (default: domain of EMAIL_TO)
ANTHROPIC_API_KEY vercel-ai-sdk, langchain
ANTHROPIC_MODEL vercel-ai-sdk, langchain (optional, default claude-opus-5-5)
OPENAI_API_KEY openai-agents
OPENAI_MODEL openai-agents (optional, default: the SDK's default model)
EMAIL_FROM must be on a domain verified in your Elastic Email account (How to verify your domain). Create the API key in the dashboard (API settings). The full list for the repository is in docs/environment-variables.md.
This repository offers three ways to combine Elastic Email with AI agents. They solve different problems:
| What it is | Use it when | |
|---|---|---|
| These examples | One narrow tool embedded in your own agent code | You are building an agent or AI feature and want it to send email, with limits you control in code |
| Elastic Email MCP server | A hosted server at https://mcp.elasticemail.com that exposes many ready-made tools (send, contacts, lists, segments, templates, campaigns) to any MCP client over HTTP |
You want Claude Code, Cursor, VS Code or another MCP client to work with your Elastic Email account directly |
| Agent skill | Instructions that help a coding agent write Elastic Email integration code | You want a coding agent to add Elastic Email to an existing project |
The MCP server gives an agent broad access to the account. The tool here gives it exactly one action, with the recipient check and error format defined by you. Frameworks that support MCP clients (the AI SDK, LangChain and the OpenAI Agents SDK all do) can use the MCP server instead, but then the server's tool set, not your code, decides what the agent can do.
- Elastic Email email API - REST API and SMTP relay overview, features and plans
- Elastic Email MCP server
- Elastic Email TypeScript SDK
- Elastic Email API Reference
- Error handling
- Questions about your account: use the chat widget on elasticemail.com
MIT