Sending customer email from a CRM should not require copying contact data into a separate campaign tool or exposing an email API key in a browser. This guide shows how to send email from Zoho with Volanea when a Zoho CRM deal reaches a meaningful business event, such as becoming Closed Won.
Volanea does not provide a native Zoho Marketplace extension or an installable Zoho app. The practical integration is a server-to-server workflow: Zoho CRM triggers an outbound webhook, your middleware validates and normalizes that event, and the middleware calls Volanea’s REST email API. This route is flexible, keeps credentials out of client-visible configuration, and gives you a reliable place to prevent duplicate sends.
This example uses Zoho CRM, since “Zoho” is a family of products rather than one application. The same design applies to Zoho Creator, Zoho Forms, and Zoho Flow, but their trigger names and payloads differ. Do not copy CRM merge fields into another Zoho product without adapting them.
What the Zoho-to-Volanea integration looks like
The basic flow has three hops:
- A Zoho CRM workflow rule detects a qualifying record action.
- Zoho CRM sends a JSON webhook to an HTTPS endpoint you control.
- That endpoint authenticates the request, checks whether the event has already been handled, and calls Volanea to deliver the email.
For this guide, the concrete trigger is a Zoho CRM Workflow Rule configured for the Deals module. It runs On a record action, specifically when a record is edited and its Stage meets the rule criteria of Closed Won. The workflow’s Instant Action is a Webhook.
That event is useful because it happens after a sales outcome, not merely when a person is added to the CRM. A new contact may not have consented to receive onboarding messages, may be a duplicate, or may not be a customer. A Closed Won deal is often the better business signal for a receipt, welcome email, implementation handoff, or account-provisioning notification.
The integration is not limited to deals. You can build separate workflow rules for records created in Leads, Contacts, Cases, or a custom module. The important design principle is to make the event explicit: identify the module, the record action, the criteria, the intended recipient, and whether the resulting message is transactional or marketing.
Why use a middleware endpoint instead of calling the email API from a browser
A webhook relay is more than a technical workaround. It is the boundary that separates CRM automation from email-delivery credentials and delivery policy.
Zoho CRM can issue outbound webhooks, but the webhook action is not a full application runtime. It cannot safely own every concern that production email delivery needs: signing inbound requests, storing a delivery idempotency key, rendering complex templates, enriching customer data, applying consent rules, and interpreting an email provider response.
Your middleware can be a small serverless endpoint in Cloudflare Workers, AWS Lambda, Vercel Functions, Netlify Functions, or your existing application. It should do four jobs before it sends anything:
- Verify that the request came through the integration path you expect.
- Validate required fields and normalize input such as email addresses and names.
- Deduplicate repeat events using a stable event or record key.
- Submit a properly structured Volanea API request and record the result.
This architecture also means changing an email subject line, adding a customer attribute, or switching an event from a plain-text message to an HTML template does not require exposing a new secret or rebuilding a client-side integration.
For teams deciding how much infrastructure to own, the email-sending part is usually straightforward; the surrounding controls are where production quality comes from. Review the email API reference and setup guides before you create the relay so the request format, sender identity, and API credentials match your Volanea account.
Configure the Zoho CRM workflow trigger
In Zoho CRM, create a workflow rule for the Deals module. The exact screens can vary as Zoho updates its administration interface, but the workflow concepts are stable: module, trigger timing, criteria, and instant action.
Use the following configuration as a starting point:
| Workflow setting | Recommended value |
|---|---|
| Module | Deals |
| Execute rule | On a record action |
| Record action | Edit |
| Rule criteria | Stage is Closed Won |
| Instant action | Webhook |
| HTTP method | POST |
| Content type | JSON / raw JSON body |
| Destination | Your HTTPS middleware endpoint |
Avoid a rule that fires on every edit to a deal that is already Closed Won unless that is deliberate. In many CRM workflow setups, a record can continue to be edited after its stage changes: a rep may correct the amount, add a note, or update a forecast field. If each edit meets the criteria, each edit may generate a webhook.
A safer rule design is to use a dedicated field such as Welcome Email Status, Provisioning Email Sent, or Lifecycle Event. Your rule can require both Stage = Closed Won and Welcome Email Status is empty. After a successful send, update that field through your application or a separate CRM action. This makes the business state visible to sales and support teams rather than hiding it only in application logs.
Choose fields that exist on the deal
Zoho CRM merge fields resolve most predictably when you use fields from the module that owns the workflow. For that reason, this example assumes the Deals module includes these fields:
Deal NameDeal OwnerAmountStageCustomer Email— a custom email field on the dealCustomer First Name— a custom text field on the dealWelcome Email Status— a custom picklist or checkbox used to prevent repeat sends
You may prefer to look up a related Contact record. That is workable, but build and test the lookup carefully: relationships can be empty, a deal can point to a business account instead of an individual contact, and not every record layout exposes the same related fields. Putting the operational recipient email on the Deal record makes the webhook payload easier to reason about.
Define the actual Zoho webhook payload
In the Webhook instant action, choose a raw JSON request body and configure merge fields from the Deals module. Zoho CRM substitutes those merge values when it runs the workflow. The payload below is the JSON your endpoint should expect after those values are resolved.
{
"event": "deal.closed_won",
"event_version": 1,
"deal_id": "5725767000001234001",
"deal_name": "Northwind annual plan",
"stage": "Closed Won",
"amount": "12000",
"customer_email": "ada@example.com",
"customer_first_name": "Ada",
"owner_email": "rep@example.com",
"occurred_at": "2026-10-16T14:32:18Z"
}
The body you enter in Zoho should use the merge-field syntax provided by the webhook editor for your CRM account. In other words, use the editor’s field picker rather than typing field references from memory. A representative raw JSON body looks like this:
{
"event": "deal.closed_won",
"event_version": 1,
"deal_id": "${Deals.Deal Id}",
"deal_name": "${Deals.Deal Name}",
"stage": "${Deals.Stage}",
"amount": "${Deals.Amount}",
"customer_email": "${Deals.Customer Email}",
"customer_first_name": "${Deals.Customer First Name}",
"owner_email": "${Deals.Deal Owner.Email}",
"occurred_at": "${SYSTEM.TIME}"
}
Treat this as a payload contract between Zoho and your service. Version it with event_version, and do not casually rename fields after the workflow goes live. A downstream email can fail silently in a business sense even when the HTTP request succeeds: for example, the relay may receive customer_email as an empty value and skip a welcome message.
Do not put the Volanea API key in this JSON body. A webhook body is data, not a secret store. It can be visible in webhook setup screens, request logs, error-monitoring tools, and support exports.
Map the Zoho event to a Volanea REST email request
The following example is an Express-style Node.js endpoint. It accepts the Zoho CRM payload, validates the important fields, constructs a message, and sends it through Volanea’s REST API. Set VOLANEA_API_KEY and VOLANEA_FROM_EMAIL as server-side environment variables in your hosting provider.
import express from "express";
const app = express();
app.use(express.json({ type: "application/json" }));
const VOLANEA_API_URL = "https://api.volanea.com/v1/emails";
app.post("/webhooks/zoho/deal-closed-won", async (req, res) => {
const event = req.body;
// Field mapping from the Zoho CRM raw JSON webhook body.
const dealId = String(event.deal_id || "");
const recipientEmail = String(event.customer_email || "").trim();
const firstName = String(event.customer_first_name || "there").trim();
const dealName = String(event.deal_name || "your purchase").trim();
const amount = String(event.amount || "").trim();
if (event.event !== "deal.closed_won") {
return res.status(400).json({ error: "Unexpected event type" });
}
if (!dealId || !recipientEmail.includes("@")) {
return res.status(422).json({ error: "Missing deal_id or customer_email" });
}
// Store and check this key in Redis, a database, or your job queue before send.
// If it already exists, return 200 without creating another email.
const idempotencyKey = `zoho:deal.closed_won:${dealId}`;
const volaneaPayload = {
from: process.env.VOLANEA_FROM_EMAIL,
to: [{ email: recipientEmail, name: firstName }],
subject: `Welcome — ${dealName}`,
html: `
<p>Hi ${escapeHtml(firstName)},</p>
<p>Thank you for choosing us for <strong>${escapeHtml(dealName)}</strong>.</p>
${amount ? `<p>Your recorded purchase amount is ${escapeHtml(amount)}.</p>` : ""}
<p>We’ll send the next steps shortly.</p>
`,
text: `Hi ${firstName},\n\nThank you for choosing us for ${dealName}. We’ll send the next steps shortly.`,
tags: ["zoho-crm", "deal-closed-won"],
metadata: {
zoho_deal_id: dealId,
zoho_event_version: event.event_version || 1,
source: "zoho_crm_webhook"
}
};
const response = await fetch(VOLANEA_API_URL, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey
},
body: JSON.stringify(volaneaPayload)
});
const responseBody = await response.text();
if (!response.ok) {
console.error("Volanea send failed", response.status, responseBody);
return res.status(502).json({ error: "Email provider rejected the request" });
}
return res.status(200).json({ accepted: true, idempotencyKey });
});
function escapeHtml(value) {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
The mapping is direct: customer_email becomes the Volanea recipient email, customer_first_name becomes the recipient name and greeting, deal_name informs the subject and body, and deal_id becomes metadata and the deduplication key. Metadata is especially valuable when support needs to answer a question such as, “Did the customer get the post-sale email for this deal?”
Before deploying, verify the current endpoint, supported message properties, and authentication format in Volanea’s API documentation. API versions and optional fields evolve; copying an old payload from a blog post is a common source of avoidable failures.
Keep the Volanea API key server-side
The Volanea API key belongs in the environment or secret manager attached to the middleware deployment. Examples include a Vercel encrypted environment variable, an AWS Secrets Manager secret loaded by Lambda, a Cloudflare Worker secret, or a container-platform secret.
It should not be placed in:
- A Zoho CRM custom field.
- The raw JSON webhook body.
- A public Zoho page, Zoho Creator client script, or browser JavaScript bundle.
- A query string, where reverse proxies and logs frequently retain it.
- A shared spreadsheet or an email-template field.
Zoho CRM itself can be configured to call external services through automation and custom functions. If you use a Zoho CRM custom function rather than the webhook relay, store the API credential only in a restricted server-side Zoho configuration available to administrators and the function runtime, not in a client-facing setting. However, a dedicated middleware secret is generally easier to rotate, audit, and scope.
The inbound webhook needs protection too. A random unguessable URL is not sufficient authentication. Use one or more of these controls:
- Put a high-entropy shared secret in an HTTP header if your Zoho webhook configuration supports the header you need.
- Use a dedicated path token as a secondary control, never as the only control.
- Restrict access at the edge where feasible and log rejected requests.
- Validate the expected event shape and reject unexpected module events.
- Return only non-sensitive error details to Zoho; preserve diagnostic detail in private logs.
Rotating the Volanea key should not require editing Zoho workflow definitions. Update the secret in the middleware environment, deploy or restart according to your platform, and test with a controlled CRM record.
Design the email as a transactional message, not a CRM mail merge
The technical integration decides how a message is sent; it does not automatically decide whether it should be sent. A Closed Won email is typically transactional or operational when it confirms a purchase, starts onboarding, or provides information necessary to use a service. It may become marketing if it promotes optional products, includes broad announcements, or is sent to contacts who did not expect it.
Keep the first event-driven message focused. State what happened, what the recipient should do next, how to contact support, and any time-sensitive details. If you later want to add recurring promotions, place those in a consent-aware campaign workflow rather than quietly expanding a transactional template.
Sender identity matters as much as content. Configure a domain you control and complete the relevant DNS authentication in Volanea before using it in production. A polished CRM workflow cannot compensate for an unverified sender domain, poor list hygiene, or a From address that recipients do not recognize.
You should also validate recipient input before enqueueing the send. An empty or malformed Customer Email field is expected in real CRM data. A pre-send validation policy can reject obviously invalid addresses, flag them for sales operations, and avoid recording an email attempt as a successful customer touchpoint. For individual-address checks outside the workflow, use the email address verification tool.
When this breaks: failures specific to the Zoho webhook hop
Every integration eventually receives incomplete data, repeats an event, or encounters a timeout. Treat these outcomes as normal operational cases rather than exceptional surprises.
Zoho retries can create duplicate sends
A webhook can be retried when Zoho does not receive a successful response, when a network connection breaks after your server accepted the request, or when your endpoint responds too slowly. The difficult scenario is an ambiguous failure: your middleware sends the email, but the HTTP response never reaches Zoho. Zoho may try again even though the recipient has already received the message.
Solve this with idempotency in your middleware, not with hope. Use a stable key such as zoho:deal.closed_won:<deal_id> when only one welcome email should ever be sent for a deal. Store the key before or atomically with queueing the message. If the same webhook arrives again, return a successful response without making another provider request.
If legitimate repeat emails are possible, include a distinct business event identifier or incrementing state in the key. Do not use the current timestamp as the only identity; it makes every retry look new.
Webhook timeouts can hide an accepted email
Do not make the webhook request wait for slow rendering, several database lookups, or an email provider response if you can avoid it. A better pattern is to validate the webhook, save a job with its idempotency key, return a fast 2xx response, and let a worker send the Volanea request.
This asynchronous model gives you a durable audit trail and a retry policy you own. If Volanea returns a temporary failure, retry the queued job with bounded exponential backoff. If it returns a permanent validation error, mark the job failed and surface it for operations rather than retrying indefinitely.
Fields may be absent because of layouts, permissions, or plan capabilities
Zoho CRM field availability depends on module layouts, user permissions, editions, and how the CRM is configured. A custom field may be unavailable to the workflow owner, blank on older records, or absent from a sandbox test record. Related-record data can also be empty even when a salesperson expects it to exist.
Your relay should distinguish between required and optional values. In this example, deal_id and customer_email are required; customer_first_name and amount are optional. Return a clear 422-level application error or record a dead-letter job for missing required data, then fix the CRM data or workflow criteria. Never substitute an owner’s email for a missing customer email merely to make the request succeed.
HTML and merge values can create unsafe or broken output
CRM data is user-entered data. Names and deal titles can contain ampersands, quotation marks, angle brackets, or pasted markup. Escape dynamic text before inserting it into HTML, as the example does. For more elaborate email layouts, use a template system that HTML-escapes variables by default.
Finally, test with names containing apostrophes, non-Latin characters, long company names, empty values, and a realistic amount format. The test record that uses “Ada” and a clean email address is necessary, but not sufficient.
Testing and observing the complete workflow
Start in a Zoho CRM sandbox or with a clearly labeled internal test deal. Send to a mailbox you control and use a sender domain configured for testing. Verify not only that a request returns 200, but that the message is accepted, delivered, and renders correctly in a real inbox.
Use this pre-production checklist:
- Create a deal that lacks
Customer Emailand confirm the relay does not send. - Change a qualifying deal’s Stage to Closed Won and confirm exactly one job is created.
- Edit the same Closed Won deal again and confirm the idempotency policy blocks an unwanted resend.
- Replay the same webhook payload and verify the endpoint returns success without a second message.
- Force a provider error in a non-production environment and confirm the job is retained for investigation or retry.
- Inspect the final email headers and rendered content in desktop and mobile clients.
Log the Zoho deal ID, the idempotency key, the recipient domain, the provider response status, and the returned message identifier. Avoid logging full message bodies or API keys. Those records let support trace the lifecycle from CRM action to email outcome without collecting more personal data than necessary.
Alternatives: Zoho custom functions and automation platforms
A CRM webhook plus middleware is usually the clearest production design, but it is not the only route.
A Zoho CRM custom function can run Deluge code as a workflow instant action and make an outbound HTTP request with invokeurl. This can reduce infrastructure for a small internal workflow, but it concentrates email logic inside CRM automation, where secret rotation, idempotency storage, and release testing may be less convenient. Use it when the email is simple and your team already governs Deluge functions well.
Zoho Flow can connect events and services through a visual automation builder. It can be useful for prototypes and lower-volume operations, especially if the relay is exposed as a clean internal webhook endpoint. Still, preserve the same principles: the Volanea API key stays in a restricted connection or server-side secret, the event is deduplicated, and failed steps have an owner.
Zapier or Make can also act as middleware when your team needs a low-code route. They are suitable for early validation, but examine task costs, rate limits, replay behavior, data retention, and the ability to set idempotency headers before relying on them for high-value transactional messages. As volume grows, a purpose-built endpoint is often less opaque and easier to monitor.
Practical rollout recommendations
Begin with one high-confidence message and one controlled trigger. A post-sale welcome email is a better first workflow than an entire lifecycle program because the audience, event, and expected content are easier to define.
Write down the ownership model before launch. Sales operations owns the quality of the CRM fields. Engineering owns the relay and secrets. Marketing or lifecycle teams own copy and consent policy. Support needs a way to determine whether the workflow ran and whether Volanea accepted the email. Without that division of responsibility, routine data issues can become long investigations.
Also decide what “sent” means in your CRM. A webhook received is not the same as an email accepted by Volanea; accepted is not the same as delivered; delivered is not the same as read. If you update Welcome Email Status, make its values precise, such as Queued, Accepted, Failed, and Suppressed, rather than a vague boolean that loses useful context.
Conclusion
To send email from Zoho with Volanea reliably, use a Zoho CRM Workflow Rule as the business trigger and an authenticated middleware endpoint as the delivery boundary. Configure a precise event such as a Deal edited to Closed Won, send a versioned JSON payload, map only validated fields into the Volanea request, and make idempotency part of the design from day one.
The result is more dependable than a browser-based shortcut or an undocumented marketplace connector: CRM users get an automation tied to the records they already manage, while your application retains control over credentials, retries, deliverability policy, and operational visibility.
FAQ
Does Volanea have a native Zoho CRM app?
No. Volanea does not ship a native Zoho Marketplace app or plugin for this workflow. Use Zoho CRM’s webhook or custom-function automation capabilities with a secure server-side relay.
What Zoho CRM event should trigger the email?
For a post-sale message, use a Workflow Rule on the Deals module that runs on a record edit when Stage meets your Closed Won criteria. Add a dedicated sent-status field if later edits could otherwise retrigger the workflow.
Where should the Volanea API key be stored?
Store it as an encrypted server-side environment secret in the middleware that receives the Zoho webhook. Do not include it in CRM fields, raw webhook JSON, browser code, or query parameters.
How do I stop duplicate emails after a Zoho retry?
Create an idempotency key from the stable business event, such as the deal ID plus event type. Persist that key before sending or queueing the email, and treat repeated requests with the same key as already handled.
Can I use Zoho Flow, Zapier, or Make instead of custom middleware?
Yes, particularly for a prototype or low-volume workflow. Ensure the tool can protect the API key, handle failures, and prevent duplicate actions. For critical transactional email, a small dedicated relay generally provides stronger control and observability.