Real-world examples for building with the Elastic Email API, SMTP, webhooks and AI coding agents.
Quick Start · SMTP · AI Agents · API Docs · Get an API Key · Verify Your Domain
Production-shaped code samples for the Elastic Email email API and SMTP relay, in 24 languages, frameworks and serverless platforms. Every stack implements the same use cases through the official SDKs and REST API v4, so what you learn in one maps directly to the others.
import { Configuration, EmailsApi, } from "@elasticemail/elasticemail-client-ts-axios"; const emailsApi = new EmailsApi( new Configuration({ apiKey: process.env.ELASTICEMAIL_API_KEY, }) ); await emailsApi.emailsTransactionalPost({ Recipients: { To: ["you@yourdomain.com"] }, Content: { From: process.env.EMAIL_FROM!, // must be on a domain verified in Elastic Email Subject: "Hello from Elastic Email", Body: [ { ContentType: "HTML", Content: "<p>Hello!</p>" }, { ContentType: "PlainText", Content: "Hello!" }, ], }, });
Start building
Pick your stack and send your first email in about five minutes.
| Stack | Quick start |
|---|---|
| Next.js | Quick start |
| Express | Quick start |
| Python | Quick start |
| PHP | Quick start |
| Laravel | Quick start |
| .NET | Quick start |
| Go | Quick start |
| Java | Quick start |
Something else? Ruby, Rust, Elixir, Kotlin, plain Node.js, NestJS, Fastify, Hono, Bun, the full-stack JavaScript frameworks, serverless platforms, SMTP, email templates, AI agents and background jobs are all in All stacks.
What is included
- Transactional and bulk email
- Templates and merge variables, plus React Email and MJML
- Attachments and inline images
- Contacts and lists
- Webhooks
- Inbound email
- SMTP examples
- Serverless examples
- Background jobs with retries: BullMQ, Inngest, Trigger.dev
- Email tools for AI agents: Vercel AI SDK, LangChain, OpenAI Agents SDK
- Claude Code and AI agent support
- MCP integration
Every example runs on the free plan - see plans and pricing.
Using with AI agents
The repository includes support for Claude Code, agent skills, MCP and LLM-readable documentation.
npx skills add ElasticEmail/elasticemail-examples
These examples are laid out so a coding agent can find the right file and copy working code into your project instead of guessing at the API.
| File | For |
|---|---|
AGENTS.md |
Agents working in this repo: layout, conventions, the webhook and sender-domain rules that are easy to get wrong. Claude Code reads it through CLAUDE.md. |
skills/elasticemail/SKILL.md |
An Agent Skill that adds Elastic Email to an existing project: detect the stack, copy the matching example, set env vars. |
examples.json |
Machine-readable map from each use case to its source files, for every stack. |
llms.txt / llms-full.txt |
Index of every guide and quickstart, and the same content in one file. |
Install the skill in Claude Code:
/plugin marketplace add ElasticEmail/elasticemail-examples /plugin install elasticemail@elasticemail
For other agents that support skills, copy skills/elasticemail/ into the agent's skills folder
(for example .cursor/skills/ or ~/.codex/skills/), or use the npx skills add command above.
Give the agent API access with the Elastic Email MCP server.
It sends email and manages contacts, lists, segments, templates, domains, suppressions and campaigns.
It is hosted at https://mcp.elasticemail.com, nothing to install; it takes your API key in the
X-Auth-Token header:
# Claude Code claude mcp add --transport http elasticemail https://mcp.elasticemail.com --header "X-Auth-Token: $ELASTICEMAIL_API_KEY"
// Cursor: ~/.cursor/mcp.json { "mcpServers": { "elasticemail": { "url": "https://mcp.elasticemail.com", "headers": { "X-Auth-Token": "<api key>" } } } } // VS Code: .vscode/mcp.json { "servers": { "elasticemail": { "type": "http", "url": "https://mcp.elasticemail.com", "headers": { "X-Auth-Token": "<api key>" } } } }
The full tool list and setup docs are at elasticemail.com/mcp.
All stacks
Each quickstart is five minutes from nothing to a delivered email; the folder it links to covers every example and route for that language.
JavaScript and TypeScript stacks use @elasticemail/elasticemail-client-ts-axios. Other languages use the matching Elastic Email SDK. Elixir calls the REST API directly with Req.
All stacks are pinned to the 4.4 SDK line and target REST API v4.
Send with SMTP
Some tools only let you enter an SMTP server: Auth0, Supabase Auth, Keycloak, WordPress, Ghost, Grafana. Some apps
already send through their framework's mailer. For both, smtp-elasticemail-examples/
shows how to point them at smtp.elasticemail.com, with no SDK involved. The
SMTP quickstart sends a first message with curl.
| Platforms | Code |
|---|---|
| Auth: Auth0, Supabase, Keycloak, Firebase Auth, Appwrite, PocketBase CMS: WordPress, Ghost, Strapi, Directus, Payload, Liferay Self-hosted: GitLab, Grafana, Nextcloud, Discourse, Metabase, Retool Automation: n8n, Zapier, Customer.io |
Node.js, Nodemailer, NextAuth, PHPMailer, Laravel, Django, Rails |
SMTP uses its own credentials (Settings > SMTP in the dashboard), not the API key.
Examples Included
Every language and framework stack covers the sending, webhook, inbound, contacts, double opt-in and
domain examples. The full-stack framework apps (Next.js, Remix, Nuxt, SvelteKit, Astro, RedwoodJS,
TanStack Start, Laravel) skip some account-level ones, and the serverless folders focus on send and webhooks.
examples.json lists exactly which files cover which use case in each stack.
Sending
- Basic Send - HTML and plain text transactional email
- Batch Send - One bulk call with per-recipient merge fields
- With Attachments - Base64 file attachments
- With CID Attachments - Inline images referenced by Content-ID
- With Templates - Hosted templates with merge variables (created on first run)
- Scheduled Send - Delayed delivery with
TimeOffset - Prevent Threading - Unique
X-Entity-Ref-IDheader per message - Email Status - Look up a transaction and view a sent message
Receiving
- Webhooks - Create webhooks and handle Sent, Opened, Clicked, Error, AbuseReport and Unsubscribed events
- Inbound - Inbound routes that push parsed email to your endpoint
Contacts and lists
- Contacts - Lists, contact CRUD, custom fields
- Double Opt-in - Confirmation link with an HMAC token, or confirmation through the Clicked event
- Suppressions - Unsubscribe, bounce and complaint lists
Account
- Domains - Add a sending domain and read SPF, DKIM, MX, DMARC and tracking status
- Statistics - Account-level delivery statistics
- Email Verification - Single address verification
- Sub-accounts - List sub-accounts, and optionally create one and assign credits
Guides
Language-neutral explanations of the concepts every example uses. Start with the quickstart for your stack, come here when you need the detail.
| Guide | What it covers |
|---|---|
| Environment variables | Every variable, where it is used, what breaks without it |
| Sending email | Transactional vs bulk, merge fields, scheduling, threading, delivery lookup |
| Attachments | File attachments and inline (CID) images |
| Templates | Hosted templates, merge values, creating one from code |
| Contacts and lists | Lists, contact CRUD, statuses, custom fields |
| Double opt-in | Both confirmation flows, and when to pick which |
| Webhooks | Events, their parameters, the token scheme, handler design |
| Inbound email | Routes, MX setup, the parsed fields you receive |
| Suppressions | Unsubscribes, bounces, complaints |
| Domains and deliverability | SPF, DKIM, MX, DMARC, tracking, warm-up |
| Account | Statistics, email verification, sub-accounts |
| Error handling | The error body, and how each SDK surfaces it |
| API map | Use case to SDK method, in every language here |
| Troubleshooting | Symptom to cause, for the failures that actually happen |
Getting Started
-
Get an API key from app.elasticemail.com. Copy it straight away - it is shown once. API settings covers creating and managing keys.
-
Verify a sender domain in the Elastic Email dashboard. Examples send from
EMAIL_FROM, which must belong to a verified domain. Publishing the SPF and DKIM records takes a few minutes - How to verify your domain walks through it. -
Clone this repository:
git clone https://github.com/ElasticEmail/elasticemail-examples.git
-
Choose your stack and follow its README
-
Copy
.env.exampleto.envand fill inELASTICEMAIL_API_KEY,EMAIL_FROMandEMAIL_TO -
Run the examples
Retrying a send safely
A send that times out may still have gone through. Every basic send in this repository passes an
Idempotency-Key header (SDKs 4.4.0+): retrying with the same key and the same body within 24 hours
returns the first response (same TransactionID, Idempotency-Replayed: true) instead of sending
a second copy. The server apps' POST /send routes forward an Idempotency-Key from their own
clients and generate one when there is none, and the queue examples
derive the key from the job id so every retry of a job reuses it. See
Retrying safely.
Notes on webhooks and inbound
Webhooks can be signed. The examples create webhooks with EnableSigning: true and DeliveryMethod: "PostJson"
(SDKs 4.3.0+), store the SigningSecret returned once by the create call as ELASTICEMAIL_WEBHOOK_SECRET, and
verify the HMAC-SHA256 X-ElasticEmail-Signature header on every request against the raw JSON body. Webhooks
created without signing (the default, and all older ones) arrive as unsigned GET requests with the details in the
query string (status, to, transaction, messageid, category, target); when
ELASTICEMAIL_WEBHOOK_SECRET is empty the handlers fall back to a shared ?token=ELASTICEMAIL_WEBHOOK_TOKEN secret
checked with a constant-time compare. See docs/webhooks.md. Inbound email is different: it is
not signed and arrives as a POST with form fields (from_email, subject, body_text, body_html,
att1_name, att1_content, ...), protected with the ?token= check.
When you save a webhook, Elastic Email sends one test event to the URL and saves the webhook only if it gets a
2xx response (a new signed webhook also accepts 401/403), so the URL has to be publicly reachable at that moment. During local development, run a tunnel
such as ngrok and set PUBLIC_URL accordingly. The test event carries sample values (to=test@test.com,
messageid=abc1234). The handlers accept it like any other event; in your own app, skip it before it reaches
your data.
Full detail: Webhooks and Inbound email.
Resources
- Elastic Email email API - REST API and SMTP relay overview, features and plans
- Elastic Email Developers
- REST API Reference
- API Libraries
- Elastic Email CLI
- Elastic Email MCP server
- Dashboard
Contributing
Found a problem or want to add a stack? Open an issue or send a pull request. CONTRIBUTING.md covers the conventions and how to add a stack. To report a security issue, see SECURITY.md. Not sure where a question belongs? See SUPPORT.md. Participation is governed by the Code of Conduct.
License
MIT