ElevenLabs transactional email is the small but essential feature that turns a promising AI-built app into something users can actually trust. Your voice agent, dashboard, or workflow can be impressive—but when a user signs up and never receives a welcome email, verification link, or password reset, the experience breaks immediately.
This guide shows a practical way to add Volanea to an app you are building with ElevenLabs: authenticate a sending domain, keep the email credential on the server, create one reusable mail function, and call it from the events that matter. You will also get a prompt you can give an AI coding assistant, plus the TypeScript code that prompt should produce.
What ElevenLabs transactional email means in practice
Transactional email is email triggered by an event in your product rather than a promotional campaign. A user creates an account, requests a password reset, receives an invitation, completes an order, or needs to confirm an email address. The message exists to complete a task the user initiated or to communicate an operational change.
For an app built around ElevenLabs, those events may happen in familiar places:
- A new customer creates an account before trying a voice experience.
- A user verifies their email before accessing saved conversations or generated content.
- A team owner invites a colleague to a shared workspace.
- A customer asks a voice agent to send a recap, receipt, or requested resource.
- An administrator changes an account setting and needs a security notification.
- A user loses access and requests a password-reset link.
The important distinction is that ElevenLabs can provide voice, conversational-agent, and developer tooling capabilities, while your app still needs a reliable application backend for account state, permissions, payments, and messages. Email belongs at that backend boundary.
A voice agent should not hold an unrestricted email-provider secret. Neither should browser-side JavaScript. Instead, your application should decide that a verified event occurred, invoke a server-side function, and let that function send the message through an authenticated email API.
That architecture may sound less magical than asking an agent to “send an email,” but it is what prevents a generated interface from exposing a credential, allowing arbitrary recipients, or turning a retry into duplicate customer mail.
The thin integration layer: honest expectations
The overlap between ElevenLabs app building and transactional email infrastructure is still emerging. There is no need to pretend that a native, one-click Volanea integration is required for this workflow.
The dependable path is simpler: use Volanea as your application’s email delivery layer through its REST API or SMTP credentials, and let your app call it from trusted server code. Volanea’s REST send endpoint is POST /v1/send, authenticated with a secret key, and supports a single recipient or up to 50 recipients in one send request. It also supports an Idempotency-Key header for retry-safe sends.
That means you have two complementary patterns:
- Your app sends email after an application event. This is the default for welcome emails, account verification, password resets, and invitations.
- An ElevenLabs conversational agent invokes a controlled application tool. The tool calls your backend, which validates the request and decides whether to send an email.
The second option is useful when a voice agent needs to perform an action during a conversation, such as sending a meeting summary to the authenticated caller. But it should be constrained. The agent supplies structured intent; your backend enforces identity, recipient rules, allowed message types, and approval requirements.
ElevenLabs Agents supports multiple ways to connect external actions, including webhook tools, client tools, code tools, and MCP tools. MCP can be a useful connector for agent-accessible tools, but it does not remove the need for security design. Treat every email-sending action as a real-world side effect, not as harmless generated text.
The fastest dependable setup
Before asking ElevenLabs or another coding assistant to add email, do a short amount of human setup. This keeps the agent focused on your application code rather than guessing about credentials, DNS, or sender identity.
1. Create and protect an API key
Create a Volanea secret API key and store it as an environment variable in the hosting environment for your backend. Use a test key while you are building if you want to inspect rendering and logs without delivering production mail.
Do not paste the key into:
- Client-side source code.
- A public repository.
- A browser-exposed environment variable such as
NEXT_PUBLIC_*. - An ElevenLabs agent prompt.
- A tool description visible to users.
- A webhook URL query string.
Your server route or server function should be the only code that reads VOLANEA_API_KEY.
2. Verify the domain you will send from
Use a domain you control and add it in the Volanea dashboard. The domain setup process provides the DNS records needed for authentication; copy the values exactly into your DNS host rather than inventing SPF, DKIM, or DMARC records from memory.
A practical pattern is to use a sending subdomain such as mail.example.com or notify.example.com while keeping your main website on example.com. This isolates operational email configuration and makes it easier to reason about the mail stream later.
Verification is not an optional polish step. It is part of making your sender recognizable to mailbox providers and recipients. A polished email template cannot compensate for a sender domain that is not authenticated.
3. Start with one message type
Do not begin by building ten templates, an agent-controlled composer, and a campaign workflow. Start with the event where failure is most visible: usually a welcome email or verification email.
The first production-ready implementation needs only these pieces:
- A verified sender address.
- A server-only API key.
- A recipient address from trusted account data.
- A subject line.
- An HTML version and readable plain-text version.
- A stable event ID for retries.
- Logging that lets you correlate an application event with a mail request.
Once that works, the same sender module can power invitations, password resets, receipts, and agent-generated summaries.
For endpoint details, current fields, and implementation guides across frameworks, keep the email API reference and setup guides open while your agent writes the integration.
A prompt to give your coding assistant
AI coding works best when the prompt describes both the desired feature and the constraints that keep the feature safe. “Add a welcome email” is often too vague: it leaves the model to guess where secrets live, how a user is represented, whether mail is sent from the browser, and what should happen on a retry.
Use a prompt like this, then adapt file names and framework terminology to your project.
Add a transactional welcome-email integration using Volanea.
This app uses TypeScript and has server-side code. Create a server-only module
called lib/email.ts with a sendWelcomeEmail function. It must send a POST request
to https://api.volanea.com/v1/send using Authorization: Bearer ${VOLANEA_API_KEY}.
Requirements:
- Read VOLANEA_API_KEY and EMAIL_FROM from server environment variables only.
- Never expose either value to browser code or return them in API responses.
- Accept a trusted user object with id, email, and optional name, plus a stable eventId.
- Send to the user’s stored email address, not an arbitrary client-supplied address.
- Include subject, HTML, and plain-text content.
- Escape the user name before inserting it into HTML.
- Send Idempotency-Key using the stable eventId so retried sign-up jobs do not
create another welcome message.
- Throw a useful server-side error if Volanea returns a non-OK response, but do
not expose the provider response directly to the client.
- Add an example showing how to call sendWelcomeEmail immediately after a new
user record has been successfully created.
- Do not send email from a React component, browser event handler, or public API
route that lacks authentication.
This prompt is deliberately specific about the trust boundary. Your coding agent can generate functions, but it cannot determine which client input is trustworthy without understanding your authentication and database model. The prompt makes the correct default explicit: the recipient comes from the newly created account record, not from a form field forwarded directly to an email provider.
The resulting Volanea welcome-email code
Below is a framework-neutral TypeScript module. It uses native fetch, so it can work in modern Node runtimes and many serverless environments. If your framework has a server-only marker or convention, apply it to this file as well.
// lib/email.ts
type WelcomeRecipient = {
id: string;
email: string;
name?: string | null;
};
function escapeHtml(value: string): string {
return value
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
export async function sendWelcomeEmail(
user: WelcomeRecipient,
eventId: string,
): Promise<void> {
const apiKey = process.env.VOLANEA_API_KEY;
const fromEmail = process.env.EMAIL_FROM;
if (!apiKey) {
throw new Error("VOLANEA_API_KEY is not configured");
}
if (!fromEmail) {
throw new Error("EMAIL_FROM is not configured");
}
const firstName = user.name?.trim() || "there";
const safeName = escapeHtml(firstName);
const appUrl = process.env.APP_URL || "https://example.com";
const response = await fetch("https://api.volanea.com/v1/send", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": `welcome:${eventId}`,
},
body: JSON.stringify({
fromEmail,
to: user.email,
subject: "Welcome — your account is ready",
text: [
`Hi ${firstName},`,
"",
"Welcome! Your account is ready to use.",
`Open your dashboard: ${appUrl}/dashboard`,
"",
"If you did not create this account, you can ignore this email.",
].join("\n"),
html: `
<!doctype html>
<html lang="en">
<body style="margin:0;background:#f6f7f9;font-family:Arial,sans-serif;color:#1f2937;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding:32px 16px;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width:600px;background:#ffffff;border-radius:12px;">
<tr>
<td style="padding:40px 32px;">
<h1 style="margin:0 0 16px;font-size:28px;line-height:1.2;">Welcome, ${safeName}</h1>
<p style="margin:0 0 20px;font-size:16px;line-height:1.6;">
Your account is ready. You can now open your dashboard and get started.
</p>
<p style="margin:0 0 28px;">
<a href="${appUrl}/dashboard" style="display:inline-block;background:#111827;color:#ffffff;padding:12px 18px;border-radius:8px;text-decoration:none;">
Open your dashboard
</a>
</p>
<p style="margin:0;font-size:14px;line-height:1.5;color:#6b7280;">
If you did not create this account, you can safely ignore this email.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
`,
}),
});
if (!response.ok) {
const requestId = response.headers.get("x-request-id");
console.error("Volanea welcome email failed", {
status: response.status,
requestId,
userId: user.id,
eventId,
});
throw new Error("Unable to send welcome email");
}
}
This code does more than demonstrate an HTTP request. It addresses the issues that commonly appear after a generated prototype gets real users.
First, it reads secrets only on the server. Second, it uses a trusted account email rather than accepting an email address directly from a public browser request. Third, it includes both HTML and text content. Fourth, it escapes the display name before including it in HTML. Finally, it attaches a stable idempotency key tied to the logical welcome event.
The eventId should not be a new random UUID every time your background job retries. Store an event ID when the account event is created, then reuse it for every retry of that same event. A retry with a different idempotency key looks like a new send.
Call the mail function after account creation
Where you call sendWelcomeEmail depends on your architecture, but the sequencing matters more than the framework. Create the user record first. Only after the database transaction succeeds should you enqueue or trigger the email.
Here is a simplified example:
import { sendWelcomeEmail } from "./lib/email";
export async function registerUser(input: {
email: string;
name?: string;
passwordHash: string;
}) {
const user = await db.user.create({
data: {
email: input.email,
name: input.name,
passwordHash: input.passwordHash,
},
});
const event = await db.outboxEvent.create({
data: {
type: "user.welcome_email_requested",
userId: user.id,
},
});
await sendWelcomeEmail(
{
id: user.id,
email: user.email,
name: user.name,
},
event.id,
);
return user;
}
For a small application, sending immediately after creation may be appropriate. For a larger or more failure-sensitive system, use the outbox event as a durable handoff to a background worker. The worker can retry transient network failures without holding up the sign-up response.
The second-order benefit is important: you can answer operational questions later. Did the user account exist? Was the welcome event recorded? Did your worker attempt the send? Did Volanea accept it? Was it delivered, bounced, or suppressed? Those questions are much harder to answer if an email call is embedded in a UI component or mixed into a conversational-agent prompt.
Password resets need a different security model
A welcome email is informational. A password reset is security-sensitive. Do not generate a reset URL in a voice-agent tool call or let an agent decide which user should receive one based solely on conversational text.
A robust password-reset flow generally works like this:
- The user enters an email address in a reset form.
- Your backend responds with the same neutral message whether or not that account exists, reducing account-enumeration risk.
- If the account exists, your backend creates a random, short-lived, single-use reset token.
- Store only a secure representation of that token according to your authentication design.
- Send a reset link to the account’s known email address.
- When the user follows the link, verify the token, expiration, and single-use status before allowing a password change.
Volanea delivers the message; it should not be the source of authorization logic. Your application owns token generation, expiry, validation, and audit history.
The reset email itself should be direct. State why the recipient received it, include a clear button and visible fallback URL, state the expiration window, and tell the recipient what to do if they did not request it. Avoid putting sensitive information in the subject line.
Let an ElevenLabs agent request email, not freely compose it
An agent may need to take an email-related action during a conversation. For example, a customer says, “Email me a summary of this call,” or “Send the setup instructions to my work address.” This can be a good product interaction—but only if the tool boundary is strict.
A safer design is a backend action such as send_conversation_summary with narrow inputs:
{
"conversationId": "conv_123",
"recipientScope": "authenticated_user",
"summaryFormat": "standard"
}
Notice what is absent: arbitrary sender selection, arbitrary raw HTML, account IDs supplied by a stranger, and unlimited recipient lists. The backend can look up the authenticated user, verify that they are authorized to access the conversation, generate or retrieve the approved summary, and send only to an eligible address.
For higher-risk scenarios, insert confirmation. The agent can say, “I can send that summary to alex@example.com. Would you like me to do that?” Your application records the confirmation before calling the mail endpoint.
This is the right way to think about webhook tools and MCP-based tools too. A tool connection can make an agent capable of requesting an action, but the receiving service remains responsible for authorization, validation, logging, rate limits, and duplicate prevention. Do not place a broadly capable Volanea secret in a conversational prompt and hope the model always uses it correctly.
Use templates when messages become product assets
Inline HTML is ideal for proving the first flow. Once the message becomes part of your customer experience, move repeated content into a reviewed template workflow.
Volanea supports reusable templates identified by templateId, with variables for personalization. Templates are valuable when several application routes need the same message or when non-engineering teammates need to review copy without hunting through server code.
Templates improve more than visual consistency. They reduce the chance that a password-reset route and an invitation route drift into using conflicting branding, missing plain-text alternatives, or different footer language. They also make an audit of customer-facing copy easier.
Keep dynamic values narrow and intentional. A first name, organization name, reset URL, invoice number, or appointment time is reasonable. Passing an unreviewed, model-generated block of HTML into a critical account email is a different risk category.
As your sending volume grows, review the transactional email pricing alongside the operational needs of your application: message volume, test and production environments, event visibility, and the cost of the email flows you make part of the product.
Deliverability is part of the feature
A successful API response means the platform accepted your request. It does not guarantee that the recipient has read the email, that it landed in the inbox, or that the address was valid.
Treat deliverability as an ongoing product concern. That means authenticating the sender domain, using clear from-addresses, keeping transactional streams focused on expected messages, processing bounces and complaints, and avoiding surprise mail.
For an AI-built app, this matters even more because generated products can scale user actions quickly. A bug in a conventional form might affect a handful of requests. A loosely scoped agent tool could initiate unwanted sends at conversational scale.
Use these operating rules:
- Send critical account mail from a verified domain.
- Include a plain-text alternative alongside HTML.
- Use recipient data from your database for account events.
- Do not turn one triggered email into a hidden marketing sequence.
- Keep welcome, reset, invitation, and receipt flows separately identifiable in your logs.
- Add rate limits around public flows such as password resets.
- Monitor failures and suppressions rather than retrying every failure forever.
- Validate addresses at signup when appropriate, especially before sending high-value workflows.
A free address check can be useful before onboarding a new contact, but it is not a substitute for consent, sender authentication, or bounce handling. Email validation tells you something about deliverability risk; it does not prove that you are entitled to contact the address.
Test the complete path before launch
The best email integration test is not a unit test that checks whether fetch was called. It is an end-to-end test that starts with an actual event in your app and ends with a clear record of the message outcome.
Build a small release checklist:
- Create a test user with an inbox you control.
- Trigger the application event once.
- Confirm that your application recorded one event and one send attempt.
- Verify the sender address, display name, subject, text version, HTML version, and links.
- Retry the exact same event and confirm that idempotency prevents a second logical send.
- Test a failed request by temporarily using a controlled invalid configuration in a safe environment.
- Confirm that errors are logged privately and do not leak secrets or provider details to the browser.
- Test on a mobile mail client as well as a desktop inbox.
If your app is voice-first, add conversation-specific tests. Ask the agent to request a summary, decline the confirmation, then approve it. Check that no email leaves before approval, that it reaches only the eligible recipient, and that the logged conversation ID maps to the mail event.
What to ask your coding agent to improve next
After the welcome email works, the next tasks should reinforce reliability rather than add novelty for its own sake.
Ask your assistant to add these features one at a time:
- A password-reset email that uses a short-lived, single-use token generated by your backend.
- An email-verification flow that gates sensitive account features until confirmation.
- An invitation email tied to workspace membership and an expiration date.
- A server-side event table or outbox worker for durable retries.
- Webhook processing for delivery, bounce, complaint, and suppression events.
- Reviewed templates for recurring account messages.
- An internal admin screen that can show the history of an email event without exposing raw API keys.
This order keeps the product grounded. You are not merely making the app look complete; you are establishing accountable behavior around the parts users depend on when they cannot log in, need an invitation, or expect a record of an action.
Build quickly, keep the sending boundary boring
ElevenLabs can help you create compelling voice and agent experiences. A coding assistant can help you scaffold routes, write types, render templates, and connect events. But transactional email should remain intentionally unexciting: a verified sender, a protected secret, a trusted recipient, a documented API call, an idempotency key, and observable outcomes.
That boring boundary is what lets you move quickly without creating an invisible reliability problem. Start with one welcome email. Put the Volanea request on the server. Test it with a real inbox. Then reuse the same pattern for verification, password resets, invitations, receipts, and carefully controlled agent-requested messages.
FAQ
Does ElevenLabs have a native Volanea plugin for transactional email?
You do not need a native plugin to add transactional email. The practical approach is to call Volanea from your application’s server-side code after trusted events such as account creation or a reset request. For agent actions, connect the agent to a tightly scoped backend tool rather than giving it unrestricted email credentials.
Can an ElevenLabs voice agent send an email during a conversation?
Yes, through a controlled application action such as a webhook tool or MCP-accessible tool. The tool should authenticate the user, restrict recipient choices, validate the requested action, use approved templates or content rules, and require confirmation where appropriate.
Should I call the Volanea API from the browser?
No. Keep the Volanea secret key in server-side environment variables and call the API from a server route, server function, background worker, or other trusted backend environment. Browser code can request an action from your backend, but it should never receive the provider credential.
Why use an idempotency key when sending a welcome email?
Networks and background jobs retry. Without a stable idempotency key, a timeout after a successful send can cause your application to send the welcome message again. Use one stable event ID for the logical event and reuse it across retries.
What is the first transactional email I should add?
Start with the message tied to your most important account action: usually a welcome email, email verification, or password reset. Build it end to end, test it with a real inbox, and then reuse the same secure server-side pattern for the next message type.