CallRail can capture the moment a prospect submits a tracked form, and Volanea can turn that event into a fast, personalized transactional message. This guide shows how to send email from CallRail without pretending there is a native CallRail marketplace app: the connection is a CallRail webhook, your server-side middleware, and the Volanea REST API.
There is an important architectural detail up front. CallRail can POST webhook data to an endpoint you control, but it is not a general-purpose HTTP client where you should place a third-party email API key. Your middleware receives the CallRail event, validates and maps it, then calls Volanea with the secret key held safely in server-side environment variables.
What this CallRail-to-Volanea integration does
The pattern in this guide is designed for a common lead-response workflow:
- A visitor submits a form that CallRail tracks.
- CallRail creates a Form Submission record and sends a webhook event to your endpoint.
- Your endpoint extracts the recognized form fields and attribution context.
- Your code sends a transactional email through Volanea.
- The endpoint returns a successful response to CallRail only after the event has been safely accepted for processing.
That first email might be a prospect confirmation, a request-received message, a booking link, or an internal alert to the sales team. The same approach can be adapted for CallRail’s call and text-message webhook events, but form submissions are the cleanest place to start because they commonly include an email field in form_data.
This is not a native CallRail app, marketplace listing, or one-click plugin. It is a direct integration built on CallRail Webhooks, which CallRail describes as HTTP POST notifications sent to a URL you choose after events such as a new call, form, or text message. CallRail supports webhook events for calls, text messages, and form submissions, while Form Submission is specifically applicable to accounts using Form Tracking.
The concrete CallRail trigger: Form Submission
For this implementation, the trigger is Form Submission. In CallRail terminology, that is the webhook event emitted when a tracked form submission is received.
A Form Submission event is the right trigger when your website uses a lead form containing an email address, such as:
- A “request an estimate” form.
- A consultation or demo request form.
- A contact-us form.
- A service-area or appointment inquiry form.
- A lead form associated with a paid campaign that CallRail tracks.
CallRail’s published webhook field list for form submissions includes an identifier, company identifier, form_data, form and landing-page URLs, referrer details, submission time, first-form status, and attribution fields such as source, keywords, campaign, medium, and UTM values. The individual keys inside form_data come from your actual web form, so an email input might be named email, Email, work_email, or something else entirely.
That variability is why a production integration should not blindly assume that form_data.email always exists. Instead, define a small allowlist of acceptable field names and reject or route incomplete submissions for review.
Why not send straight from the CallRail webhook to Volanea?
Volanea’s send endpoint needs a Volanea secret key. Putting that key into browser JavaScript, a public form, a URL parameter, or a client-visible automation configuration would expose authority to send from your domain.
CallRail’s webhook is intended to send data out to your endpoint. Your endpoint is the boundary where you can do the work that a webhook configuration cannot safely do:
- Keep the Volanea secret key out of CallRail payloads and front-end code.
- Validate the incoming event before sending any email.
- Normalize differently named form fields.
- Escape user-provided text before placing it in HTML.
- Apply business rules, such as only emailing opted-in leads.
- prevent duplicate sends when a delivery is retried.
- Store an audit record that connects a CallRail submission to a Volanea message result.
For a small implementation, that middleware can be an Express route, a serverless function, a Cloudflare Worker, or an endpoint in an existing application. The architecture matters more than the hosting choice.
What CallRail sends for a form submission
CallRail sends webhook data as JSON. The exact content depends on the fields CallRail recognizes on the tracked form and the attribution available for that visitor, so treat fields other than the documented core fields as optional.
A representative Form Submission payload has this shape:
{
"id": "FMS1234567890",
"company_id": "C-abc123",
"form_data": {
"first_name": "Maya",
"last_name": "Lopez",
"email": "maya@example.com",
"phone": "+1 404 555 0143",
"message": "I would like an estimate for roof repair."
},
"form_url": "https://www.example.com/request-estimate",
"landing_page_url": "https://www.example.com/roof-repair?utm_source=google&utm_campaign=spring",
"referrer": "https://www.google.com/",
"submitted_at": "2026-10-01T15:12:44Z",
"referring_url": "https://www.google.com/",
"first_form": true,
"source": "google",
"keywords": "roof repair near me",
"campaign": "spring",
"medium": "cpc",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "spring"
}
Do not copy this example into production and assume every field will be present. form_data reflects the form you operate. A form may use full_name rather than separate first and last names; it may use email_address; or it may contain no email field at all. Attribution fields can also be absent when CallRail has no matching source data.
The stable design is to treat the CallRail record ID as the event identity, select only fields you need, and provide neutral fallbacks for optional content.
Map the data deliberately
For a confirmation email to the lead, a practical mapping is:
| CallRail value | Volanea email use | Rule |
|---|---|---|
id | Idempotency-Key value | Required for one email per submission |
form_data.email or equivalent | to | Validate before sending |
form_data.first_name or form_data.name | Greeting | Escape before HTML output |
form_data.message | Optional email summary | Escape and truncate |
form_url | Context for your team | Do not expose unless useful |
utm_source, utm_medium, utm_campaign | Internal reporting or template variables | Treat as optional |
submitted_at | Audit log | Store with the event result |
For an internal sales notification, the recipient can instead be a fixed team inbox such as leads@example.com, while the visitor’s email is included as content or Reply-To. Do not automatically use an untrusted form value as Reply-To without first validating it as an email address.
Prerequisites before you configure the webhook
Before connecting CallRail to Volanea, prepare the sending side and the receiver.
1. Verify the Volanea sending domain
Use a From address on a domain you have verified in Volanea. A sending platform should not accept arbitrary sender domains, and Volanea rejects mail from an unverified From domain. For example, if you own example.com, a suitable From address could be hello@example.com or leads@example.com after the domain is verified.
Use a recognizable sender name and address. A confirmation from Example Roofing <leads@example.com> is clearer than a generic no-reply address, especially when the visitor expects a follow-up from a local service business.
2. Create a Volanea secret key
Create a Volanea secret key for this integration and keep it in your hosting provider’s secret manager or environment-variable configuration. Use a name such as VOLANEA_API_KEY.
Do not paste the Volanea key into:
- Client-side JavaScript.
- A public repository.
- A CallRail form field.
- A CallRail webhook URL.
- A log line.
- A browser-visible automation step.
- An email template or landing-page source file.
The key does not live on the CallRail side of this integration. It lives only in the server-side middleware that receives CallRail’s POST request. CallRail only needs the HTTPS URL of that receiver.
3. Deploy a public HTTPS webhook endpoint
Your endpoint must be reachable from CallRail over HTTPS. For example:
https://integrations.example.com/webhooks/callrail/form-submission
Do not use a local development address in the CallRail configuration. During development, use a secure tunnel if necessary, then replace it with the production endpoint before turning on real lead emails.
4. Decide the consent rule before writing code
A form submission is not automatically permission to enroll someone in promotional marketing. This guide is for a transactional or requested-response message: confirmation that the inquiry was received, a requested appointment follow-up, or essential service communication.
If you want to add a submitter to a marketing campaign, collect and store a clear consent signal from the form, pass it through CallRail if it is recognized, and keep that consent decision separate from this immediate confirmation flow.
For the REST endpoint, authentication, and send-object options, use the Volanea email API reference as the source of truth when you deploy.
Configure CallRail to deliver the event
In the appropriate CallRail company, configure a webhook for the Form Submission event and set its destination to the HTTPS endpoint you deployed.
The precise placement of webhook controls can vary as CallRail updates its application, so follow the current Webhooks area for the company that owns the tracked form. The configuration principle is straightforward:
- Choose the correct CallRail company.
- Add your server-side HTTPS endpoint as the webhook destination.
- Subscribe to the Form Submission event.
- Save the webhook configuration.
- Submit a real test form through the tracked page.
- Inspect the received JSON before enabling automated sends for all traffic.
CallRail distinguishes company-level webhook keys from user-level API keys. If your account provides a CallRail webhook key or verification mechanism, keep that credential in your middleware’s server-side secrets too. Never confuse it with the Volanea API key: the CallRail credential verifies an inbound event, while the Volanea secret authorizes the outbound email request.
Use an endpoint-specific secret as a practical access control
Do not assume that an obscure URL is sufficient authentication. If your CallRail configuration accepts a destination URL containing a query value, use a long random receiver token, for example:
https://integrations.example.com/webhooks/callrail/form-submission?token=LONG_RANDOM_VALUE
Store the matching value as CALLRAIL_RECEIVER_TOKEN in the server environment. This is not a replacement for any official CallRail webhook verification option available to your account. It is an additional receiver-specific check that lets your application reject casual unsolicited POSTs before it does any email work.
Avoid placing the Volanea key in that query string. URLs commonly appear in logs, browser history, proxy tooling, configuration exports, and support screenshots.
Working Node.js code: CallRail payload to Volanea email
The following Express route receives a CallRail Form Submission webhook, validates the endpoint token, pulls common email and name field variants from form_data, escapes user-controlled values, and calls POST https://api.volanea.com/v1/send.
It uses the CallRail submission id as the stable part of the Volanea Idempotency-Key. That makes a retry of the same logical event safe: the same CallRail submission should not create a second confirmation email merely because a network response was lost.
import express from "express";
const app = express();
app.use(express.json({ limit: "1mb" }));
const {
CALLRAIL_RECEIVER_TOKEN,
VOLANEA_API_KEY,
VOLANEA_FROM = "Example Company <leads@example.com>",
PORT = "3000"
} = process.env;
if (!CALLRAIL_RECEIVER_TOKEN || !VOLANEA_API_KEY) {
throw new Error("Missing CALLRAIL_RECEIVER_TOKEN or VOLANEA_API_KEY");
}
function firstNonEmpty(...values) {
return values.find((value) =>
typeof value === "string" && value.trim().length > 0
)?.trim();
}
function isEmail(value) {
return typeof value === "string" &&
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
}
function escapeHtml(value = "") {
return String(value)
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
app.post("/webhooks/callrail/form-submission", async (req, res) => {
// Keep the Volanea secret out of CallRail. CallRail only knows this receiver URL.
if (req.query.token !== CALLRAIL_RECEIVER_TOKEN) {
return res.status(401).json({ error: "Unauthorized webhook" });
}
const event = req.body;
const fields = event.form_data && typeof event.form_data === "object"
? event.form_data
: {};
// Map the actual names used by your tracked form. Add variants only when needed.
const recipient = firstNonEmpty(
fields.email,
fields.email_address,
fields.work_email,
fields.Email
);
const firstName = firstNonEmpty(
fields.first_name,
fields.firstname,
fields.name,
fields.full_name,
"there"
);
const message = firstNonEmpty(
fields.message,
fields.comments,
fields.details,
""
);
// A CallRail Form Submission needs an event ID for durable deduplication.
if (!event.id) {
return res.status(400).json({ error: "Missing CallRail form submission id" });
}
// Not every tracked form has an email field. Acknowledge it without sending.
if (!isEmail(recipient)) {
console.info("CallRail form submission skipped: no valid email", {
callrailSubmissionId: event.id,
formUrl: event.form_url
});
return res.status(202).json({ skipped: "no_valid_email" });
}
const safeName = escapeHtml(firstName);
const safeMessage = escapeHtml(message).slice(0, 3000);
const safeCampaign = escapeHtml(event.utm_campaign || event.campaign || "");
const subject = "We received your request";
const html = `
<p>Hi ${safeName},</p>
<p>Thanks for contacting Example Company. We received your request and will follow up shortly.</p>
${safeMessage ? `<p><strong>Your message:</strong><br>${safeMessage}</p>` : ""}
${safeCampaign ? `<p style="color:#666;font-size:12px">Reference: ${safeCampaign}</p>` : ""}
`;
const text = [
`Hi ${firstName},`,
"",
"Thanks for contacting Example Company. We received your request and will follow up shortly.",
message ? `\nYour message:\n${message}` : ""
].join("\n");
try {
const response = await fetch("https://api.volanea.com/v1/send", {
method: "POST",
headers: {
"Authorization": `Bearer ${VOLANEA_API_KEY}`,
"Content-Type": "application/json",
// Reuse this exact key if this same CallRail event is retried.
"Idempotency-Key": `callrail-form-submission:${event.id}`
},
body: JSON.stringify({
from: VOLANEA_FROM,
to: recipient,
subject,
html,
text
})
});
const result = await response.json().catch(() => ({}));
if (!response.ok) {
console.error("Volanea send failed", {
callrailSubmissionId: event.id,
status: response.status,
result
});
return res.status(502).json({ error: "Email provider request failed" });
}
console.info("CallRail confirmation accepted by Volanea", {
callrailSubmissionId: event.id,
recipient,
volaneaResult: result
});
return res.status(200).json({ accepted: true });
} catch (error) {
console.error("Webhook processing error", {
callrailSubmissionId: event.id,
message: error instanceof Error ? error.message : String(error)
});
return res.status(500).json({ error: "Temporary processing failure" });
}
});
app.listen(Number(PORT), () => {
console.log(`Listening on port ${PORT}`);
});
Install Express with npm install express, set the environment variables in your deployment platform, and use Node.js with built-in fetch support. If your runtime does not include fetch, use its supported HTTP client rather than moving the Volanea call to the browser.
Field mapping in the code
The key mapping lines are deliberately visible:
const recipient = firstNonEmpty(
fields.email,
fields.email_address,
fields.work_email,
fields.Email
);
That is where CallRail’s form_data becomes Volanea’s to field. If your form uses your-email, contact_email, or another custom name, add it there after inspecting a test event.
This line creates the deduplication identity:
"Idempotency-Key": `callrail-form-submission:${event.id}`
And this JSON becomes the Volanea email request:
{
from: VOLANEA_FROM,
to: recipient,
subject,
html,
text
}
Volanea supports safe retries for POST /v1/send through the Idempotency-Key header. Use one key per intended email, not one key per recipient forever. Here, the intended action is specifically “send the confirmation associated with this CallRail Form Submission record.”
Test the full path before enabling live follow-up
A successful HTTP request is not the same as a good customer experience. Test the entire chain with a real tracked form submission.
Test checklist
- Submit the form from a browser session that CallRail tracks.
- Confirm that CallRail records a Form Submission.
- Inspect your middleware logs for the received payload and its
id. - Confirm the mapped recipient is the expected test address.
- Confirm Volanea accepts the email request.
- Check the delivered message for sender identity, subject, HTML rendering, plain-text fallback, and links.
- Submit the same test only once more after changing a form field to make sure the integration reflects intentional new events.
- Replay the same webhook payload with the same
idin a non-production test environment and confirm idempotency prevents a duplicate send.
Log identifiers, statuses, and safe metadata, but not the Volanea secret key. Be equally cautious with full form bodies: inquiry details can contain personal data. For most operational logs, the CallRail submission ID, a masked recipient, outcome, and timestamp are enough.
When this breaks: CallRail webhook and email failure modes
Every event-driven email flow needs an explicit failure model. The difficult cases are not syntax errors; they are partial successes, late data, retried requests, missing form fields, and ambiguous network outcomes.
CallRail retries can cause duplicate email attempts
A webhook sender may retry when it cannot confirm that your endpoint received the request. The risky scenario is this:
- CallRail POSTs a Form Submission event.
- Your middleware calls Volanea successfully.
- The connection between CallRail and your middleware fails before CallRail receives your
200response. - CallRail sends the same event again.
Without idempotency, the customer could receive two confirmations. The Idempotency-Key in the example solves the downstream half of that problem by tying the Volanea send attempt to event.id.
Keep the key deterministic. Do not generate a fresh random UUID inside the webhook handler for every incoming request; that would make a retry look like a new email. If you later add a second distinct email for the same submission, such as an internal alert, use a purpose suffix:
callrail-form-submission:FMS1234567890:customer-confirmation
callrail-form-submission:FMS1234567890:internal-sales-alert
Webhook timeouts create ambiguous outcomes
A timeout does not prove that the send failed. Your middleware may have sent the email but failed to return its response in time, or the response may have been lost after the message was accepted.
Keep the webhook route short. Do only the essential validation, mapping, and send call in the request path. For higher-volume systems, persist the event first using the CallRail id as a unique key, return success after durable acceptance, and have a worker perform the email send. That queue-based design gives you replay capability and more predictable response times.
If you use a queue, do not mark the event processed until the email job has a durable idempotency key. Otherwise, a worker crash between “recorded” and “sent” can leave a lead without a confirmation.
Some payload fields will be missing
A tracked form is not a normalized CRM object. It is an event built from the fields CallRail recognizes, the attribution it has, and the form structure on the page.
Expect these conditions:
- A form does not collect email, so no customer email can be sent.
- The form uses a custom field name that your mapping does not recognize.
- A name is absent, requiring a neutral greeting such as “Hi there.”
- UTM or campaign information is absent for direct, referral, or offline traffic.
- The submission message is empty or contains markup-like characters.
- A field is changed on the website but the middleware mapping is not updated.
Handle missing optional fields with fallbacks. Handle a missing or invalid recipient by skipping the customer email and logging the event. Do not send to a value merely because it looks vaguely like an address; validate it, and consider running addresses through a free email address verification tool before using them in broader lead workflows.
A Volanea acceptance response is not final delivery
A successful send response means Volanea accepted the message for processing. It does not guarantee that the recipient saw it in the inbox. A recipient can be suppressed, unsubscribed, invalid, over quota, or subject to mailbox filtering after the request is accepted.
Use Volanea’s delivery-event capabilities and message records when you need to reconcile operational outcomes. For a time-sensitive lead flow, your business process should also include a non-email fallback: a CRM task, a sales alert, or a phone follow-up. Do not rely on an automatic email as the sole proof that a valuable lead received help.
Secret exposure is an incident, not a minor configuration issue
If the Volanea API key appears in a repository, a screenshot, a frontend bundle, a support ticket, or a public endpoint URL, revoke or rotate it. Update the server-side secret, redeploy, and review logs and access controls.
The same discipline applies to CallRail credentials. Keep inbound verification data and any CallRail API credential in server-side storage, grant access only to the service that needs it, and rotate keys during offboarding or suspected exposure.
Improve the basic flow for production use
The sample route is intentionally compact, but a mature lead-response system should add durable state and observability.
Store a submission ledger
Create a database table or collection keyed by the CallRail Form Submission ID. At a minimum, store:
callrail_submission_id.received_at.- A masked recipient or encrypted recipient field.
- The selected email purpose.
- The Volanea idempotency key.
- Send request status.
- Provider response identifier, where available.
- Error category and retry count.
Make callrail_submission_id + email_purpose unique. That gives your own application a second deduplication layer in addition to the Volanea idempotency header.
Separate customer and internal notifications
A customer confirmation and an internal sales notification have different purposes and failure priorities. Model them as separate sends with separate idempotency keys and templates.
For example, the customer message can be short and reassuring: “We received your request.” The team message can include the lead’s message, form URL, landing-page URL, campaign, and a CRM link. Never send sensitive attribution data to the prospect simply because it is convenient for internal reporting.
Use templates as content grows
Inline HTML is appropriate for a small confirmation. As message variants grow by location, service line, language, or business hours, use a stored Volanea template and pass only the variables your template needs.
That approach reduces code changes for copy edits and helps keep brand, unsubscribe handling where applicable, and layout consistent. Keep template variables constrained and escaped; form input is user input even when it came from a legitimate lead.
Add outcome monitoring
At minimum, monitor these signals:
- Number of CallRail Form Submission webhooks received.
- Number skipped for missing or invalid email.
- Number accepted by Volanea.
- Number of provider-side failures by HTTP status.
- Duplicate/idempotent replay count.
- Time from CallRail submission to accepted email request.
A sudden increase in skipped records often means a web-form field was renamed. A rise in 401 responses can mean the receiver token was changed in one place but not the other. A rise in provider failures can indicate a revoked key, unverified sender domain, or account-level sending issue.
Alternatives when a direct receiver is not practical
CallRail also identifies Zapier as an option for connecting CallRail activity to platforms that do not have a native integration. That can be useful when your team does not operate a backend service.
However, treat an automation platform as middleware, not as a place to expose permanent credentials carelessly. If you choose Zapier, Make, or another workflow service, use its secure connection or secret-management capability for the Volanea key and ensure it can send the exact HTTP request, headers, and JSON body you need. Preserve the CallRail submission ID as the idempotency key if the platform lets you control custom headers.
A direct receiver remains the stronger choice when you need:
- Strict inbound validation.
- Custom consent rules.
- A database-backed deduplication ledger.
- Fast operational debugging.
- Custom error handling and alerting.
- Protection from automation-step changes that alter field names.
- Fine-grained control over recipient and content rules.
For teams that need a managed workflow quickly, an automation platform can be a reasonable first version. For high-value lead routing, a small server-side endpoint is usually simpler to audit and safer to evolve.
Conclusion
To send email from CallRail with Volanea, use CallRail’s Form Submission webhook as the event source and a server-side endpoint as the secure integration layer. The webhook carries the tracked form data; your middleware validates and maps form_data; Volanea’s POST /v1/send delivers the transactional message.
The key design choices are straightforward but essential: never put the Volanea API key in client-visible configuration, treat CallRail payload fields as optional except for the event identity you require, escape user input, and use the CallRail submission ID in a stable Volanea Idempotency-Key. Those choices turn a simple lead confirmation into a workflow that remains reliable when requests are retried, fields change, or networks fail.
FAQ
Does Volanea have a native CallRail integration?
No. This setup uses CallRail Webhooks and your own middleware endpoint to call the Volanea REST API. It is not a CallRail marketplace installation or native plugin.
What CallRail event should trigger the email?
Use the Form Submission webhook event when you want to send an email after someone submits a tracked website form. It is the best fit when the form includes a usable email address.
Where should I store the Volanea API key?
Store it only in server-side environment variables or a secret manager used by the webhook receiver. Do not place it in CallRail form code, a browser app, a webhook URL, or any client-visible configuration.
How do I stop duplicate confirmation emails?
Set Volanea’s Idempotency-Key header to a stable value derived from the CallRail Form Submission id, such as callrail-form-submission:<id>. Reuse that exact key if the same event is processed again.
What happens if a CallRail form submission has no email address?
Do not attempt a customer email. Return a successful skipped result after logging the submission ID and reason, then route the lead through an internal process if appropriate.