A Typeform transactional email flow can send a fast, relevant confirmation, lead handoff, receipt, or next-step message as soon as someone submits a form. The dependable pattern is not a native app connection: it is a Typeform webhook that reaches your server-side endpoint, where you validate the submission and call Volanea’s REST API.
This guide builds that pattern from end to end. You will configure Typeform to deliver a form-response event, identify answers by stable field references, verify Typeform’s signature, prevent duplicate sends, and submit a properly authenticated email request to Volanea. The result is flexible enough for a simple “we received your request” email and safe enough to become the starting point for a production workflow.
What this integration is—and is not
There is no Volanea app that you install inside Typeform, and Typeform webhooks do not transform a response into a provider-specific email request by themselves. A webhook is an HTTP notification: Typeform posts a JSON document to a URL you control when a configured event occurs.
That distinction matters. Volanea needs an API credential, and that credential must never be placed in a Typeform question, a hidden field, browser-side JavaScript, or a public webhook URL. Your application, serverless function, or automation platform is the trusted middle layer that receives Typeform’s payload and sends the email.
The route looks like this:
- A respondent completes and submits a Typeform.
- Typeform sends a
form_responsewebhook payload to your HTTPS endpoint. - Your endpoint verifies the
Typeform-Signatureheader against the untouched raw request body. - It extracts the answers needed for the message, using Typeform field
refvalues. - It records the webhook
event_idbefore or alongside the send attempt. - It calls Volanea’s email API with the recipient, sender, subject, and HTML/text content.
- It returns a successful HTTP response to Typeform only when the event has been accepted for processing.
For lower-volume no-code workflows, Zapier or Make can occupy much of the middle layer. They are useful for mapping a Typeform response and making an HTTP request, but a dedicated endpoint gives you stronger signature verification, idempotency, audit records, template control, and secret handling. Those concerns become important quickly when the message contains account, order, support, or lead information.
Why a webhook bridge is the right Typeform transactional email pattern
A transactional message is triggered by an individual’s action or an operational event. A submission confirmation, appointment request acknowledgement, quote follow-up, and support intake receipt are typical examples. The recipient expects it because of something they just did; this is not the same job as a bulk campaign sent to a subscriber list.
Typeform is responsible for collecting structured answers and notifying your systems. Volanea is responsible for sending the resulting email through authenticated email infrastructure. The bridge owns the application logic between them: deciding whether this response should send an email, who receives it, what it says, and how repeated deliveries are handled.
The bridge protects credentials
An API key authorizes a sender to use your Volanea account. Keep it in a server environment variable such as VOLANEA_API_KEY, where it is available only to the deployment runtime. Do not put it in Typeform’s welcome screen, URL parameters, client bundle, or email template fields.
The same principle applies to the Typeform webhook secret. Typeform uses the secret to create the signature; your bridge uses it to verify that the request really came from a webhook configured for your form. Store it as TYPEFORM_WEBHOOK_SECRET and rotate it if it is exposed.
The bridge makes data handling explicit
A form may contain an email address, name, company, plan, free-text requirement, consent checkbox, and hidden tracking value. You should decide deliberately which fields belong in an email and which should remain only in your application database.
For example, a confirmation to the respondent may safely include their first name and their selected consultation date. It should not echo sensitive free-text answers, payment details, government identifiers, or internal scoring. A notification to your team may include more operational context, but it still needs access controls and a retention policy.
The bridge deals with retries correctly
Network failures happen after a remote system has accepted work but before your code sees the response. Webhook systems can also retry a delivery if they do not receive a successful response. Without idempotency, one Typeform submission can create multiple emails.
Typeform includes an event_id in its webhook payload. Treat that value as the event’s unique key. Store it in a durable table, Redis key, or queue-backed workflow with a uniqueness constraint. If the same event arrives again, return a 2xx response without sending a second message.
Prepare Typeform: fields, references, and the webhook
Before writing code, make the form easy for software to read. A question title is written for respondents and may change during copy edits. A Typeform field reference is the machine-friendly identifier your integration should use.
Set a clear, stable ref for every answer your bridge needs. For a consultation-request form, a practical set might be:
customer_emailfor the email questionfirst_namefor a short-text name questioncompany_namefor an optional company questionrequest_typefor a multiple-choice questionmessagefor a long-text questioncontact_consentfor any required consent capture
Avoid writing integration code that searches for a field by its displayed title, such as “What is your email address?” A title can be localized, reworded, or duplicated. A ref is intended to stay meaningful as the form evolves.
Configure the Typeform webhook
In Typeform, create a webhook for the form response event and point it at a publicly reachable HTTPS URL, for example:
https://your-app.example.com/webhooks/typeform
Set a webhook secret while configuring it. Typeform signs webhook deliveries with an HMAC SHA-256 signature and sends that signature in the Typeform-Signature request header. Your endpoint needs the exact raw bytes of the incoming request body to reproduce and compare the signature.
Use a separate endpoint and secret for development, staging, and production. This prevents a test form from triggering real customer mail and makes it easier to inspect changes safely. During local development, expose a local HTTPS endpoint with a tunneling tool only for the duration of testing; do not leave a development receiver publicly open.
Understand the payload you receive
A Typeform response webhook is a JSON object with top-level event information and a nested form_response. The exact answer array depends on your form, but its shape follows this pattern:
{
"event_id": "01HZYEXAMPLEEVENTID",
"event_type": "form_response",
"form_response": {
"form_id": "AbCdEf",
"token": "response-token",
"landed_at": "2025-01-15T10:00:00Z",
"submitted_at": "2025-01-15T10:02:13Z",
"definition": {
"id": "AbCdEf",
"title": "Request a consultation",
"fields": [
{
"id": "field-email-id",
"ref": "customer_email",
"type": "email",
"title": "Work email"
}
]
},
"answers": [
{
"type": "email",
"email": "ada@example.com",
"field": {
"id": "field-email-id",
"ref": "customer_email",
"type": "email"
}
},
{
"type": "text",
"text": "Ada",
"field": {
"id": "field-name-id",
"ref": "first_name",
"type": "short_text"
}
}
],
"hidden": {},
"calculated": {
"score": 0
}
}
}
Do not assume every form field appears in answers. Unanswered optional questions may be absent. The answer value also varies by answer type: an email answer uses email, short and long text use text, a choice answer can use choice, and other field types have their own representations. Your parser should handle absence and type mismatch as normal conditions rather than crashing.
Map Typeform answers safely
The most reusable mapper converts the answers array into an object keyed by field.ref. Once that is done, message composition is ordinary application code rather than a loop full of positional assumptions.
Here is a small JavaScript helper for the common email and text cases:
function answersByRef(answers = []) {
return Object.fromEntries(
answers
.filter((answer) => answer.field?.ref)
.map((answer) => {
const value =
answer.email ??
answer.text ??
answer.choice?.label ??
answer.choice?.other ??
null;
return [answer.field.ref, value];
})
);
}
Given the example payload, answersByRef(payload.form_response.answers) returns an object like:
{
customer_email: "ada@example.com",
first_name: "Ada"
}
Validate the recipient before asking Volanea to send. At minimum, ensure the value is present, is a string, and passes your application’s email validation policy. A form’s email question provides useful client-side validation, but the webhook is still an external input to your server and should be treated accordingly.
If a response contains a checkbox or consent field, enforce the policy on the server. Do not rely only on conditional Typeform screens to decide whether a marketing-style follow-up is allowed. A submission confirmation connected to a user’s request may be appropriate, while promotional email requires the consent and compliance basis applicable to your audience and jurisdiction.
Escape all respondent-provided HTML
Never insert raw Typeform text into html. A respondent can type characters that alter markup, break layout, or create an unsafe email body. Escape dynamic values before interpolating them, and keep the message template under version control.
function escapeHtml(value = "") {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
Escaping is not only a security measure. It prevents an innocent company name such as Smith & Sons from rendering incorrectly and keeps a pasted URL or angle bracket from damaging the rest of the email.
Send the email through Volanea’s REST API
After your endpoint has authenticated the Typeform delivery and mapped the response, it can create the email. Configure and verify the sending domain in Volanea before testing with external recipients. The from address must use a domain you control and have authorized for sending; do not set from to the form respondent’s address.
Use the respondent’s address in to, and set reply_to to an address your team monitors when a reply should start a conversation. For an internal alert, reverse that pattern: send to a verified internal mailbox and use the respondent’s email as reply_to only if your reply-handling and policy allow it.
The following request uses Volanea’s REST email endpoint. Keep the API key server-side and send both HTML and plain-text versions of the message.
curl --request POST \
--url https://api.volanea.com/v1/emails \
--header "Authorization: Bearer $VOLANEA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"from": "Acme Requests <requests@mail.acme.example>",
"to": ["ada@example.com"],
"reply_to": "team@acme.example",
"subject": "We received your consultation request",
"html": "<p>Hi Ada,</p><p>Thanks for your request. Our team will reply shortly.</p>",
"text": "Hi Ada,\n\nThanks for your request. Our team will reply shortly."
}'
The endpoint receives a JSON payload, with bearer authentication in the Authorization header. Build the same request from your server rather than from the browser. For field definitions, authentication details, and the current response schema, use the Volanea email API reference and setup guides as the source of truth when implementing your deployment.
A useful design choice is to add a custom correlation value to your own logs rather than putting sensitive data into a subject line. Log the Typeform event_id, Typeform response token, the provider message identifier returned by Volanea, the template version, and a redacted recipient. These values make it possible to investigate a complaint or missing confirmation without storing the full form answer in log files.
Working Node.js webhook receiver
This example uses Express. It deliberately captures the raw body before JSON parsing because signature verification fails if middleware reformats the payload first. In a serverless framework, use that framework’s raw-body mechanism instead of assuming req.body still contains the original bytes.
import crypto from "node:crypto";
import express from "express";
const app = express();
app.post("/webhooks/typeform", express.raw({ type: "application/json" }), async (req, res) => {
const signature = req.get("Typeform-Signature") || "";
const rawBody = req.body;
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.TYPEFORM_WEBHOOK_SECRET)
.update(rawBody)
.digest("base64");
const received = Buffer.from(signature);
const calculated = Buffer.from(expected);
if (
received.length !== calculated.length ||
!crypto.timingSafeEqual(received, calculated)
) {
return res.status(401).send("Invalid webhook signature");
}
const payload = JSON.parse(rawBody.toString("utf8"));
if (payload.event_type !== "form_response") {
return res.status(204).end();
}
// Replace these two functions with durable database or queue operations.
if (await wasAlreadyProcessed(payload.event_id)) {
return res.status(200).json({ received: true, duplicate: true });
}
const fields = answersByRef(payload.form_response?.answers);
const recipient = fields.customer_email;
const firstName = fields.first_name || "there";
if (!isValidEmail(recipient)) {
await markRejected(payload.event_id, "missing or invalid customer_email");
return res.status(200).json({ received: true, sent: false });
}
const safeName = escapeHtml(firstName);
const emailPayload = {
from: "Acme Requests <requests@mail.acme.example>",
to: [recipient],
reply_to: "team@acme.example",
subject: "We received your consultation request",
html: `<p>Hi ${safeName},</p><p>Thanks for your request. Our team will reply shortly.</p>`,
text: `Hi ${firstName},\n\nThanks for your request. Our team will reply shortly.`
};
const response = await fetch("https://api.volanea.com/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VOLANEA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(emailPayload)
});
if (!response.ok) {
const detail = await response.text();
console.error("Volanea send failed", response.status, detail);
// Return a non-2xx result so Typeform can retry the webhook delivery.
return res.status(502).send("Email provider unavailable");
}
const result = await response.json();
await markProcessed(payload.event_id, {
typeformToken: payload.form_response.token,
volaneaMessageId: result.id
});
return res.status(200).json({ received: true, sent: true });
});
function answersByRef(answers = []) {
return Object.fromEntries(
answers.filter(a => a.field?.ref).map(a => [
a.field.ref,
a.email ?? a.text ?? a.choice?.label ?? a.choice?.other ?? null
])
);
}
function escapeHtml(value = "") {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
function isValidEmail(value) {
return typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}
The database functions in the example are intentionally application-specific. The key requirement is atomicity: two concurrent deliveries of the same event_id must not both pass the “already processed” check. A unique database index on event_id, or a queue with a deduplication key, is safer than an in-memory Set.
Also note the error behavior. A malformed or unauthorized request receives a 401 and must not send mail. A valid event with no usable recipient is acknowledged but recorded as rejected; retrying it will not repair the missing data. A temporary Volanea failure returns a non-2xx response, allowing Typeform’s webhook delivery behavior to retry it. In a higher-volume system, enqueue the validated work, return a 2xx promptly, and let a worker retry the Volanea API call with controlled backoff.
Build messages that recipients recognize
A fast email is valuable only if the recipient can identify why it arrived. The sender name, subject, and first paragraph should match the form and the action that triggered it.
A weak confirmation says, “Thank you for contacting us.” A stronger one says, “We received your Enterprise demo request” and identifies the expected next step: “A solutions specialist will contact you within one business day.” The stronger version reduces duplicate submissions and support tickets because it answers the immediate question: did the form work?
Use a verified From address
Your From domain is part of your sending identity. Authenticate the domain in Volanea and use a consistent mailbox such as requests@yourdomain.example or notifications@yourdomain.example. Authentication and alignment support deliverability, while a recognizable sender helps recipients distinguish legitimate mail from phishing.
Do not use the submitter’s address in from. Besides impersonating a person, that can conflict with mailbox-provider authentication policies. Put their address in reply_to only when a human should be able to reply directly and you have validated it appropriately.
Always include a text alternative
HTML makes layout and calls to action easier, but plain text remains important for accessibility, stripped-down mail clients, and troubleshooting. Write text as an actual readable message, not as a collapsed version of HTML.
For a request confirmation, include the basic transaction details in both versions: who submitted it, what category they selected, and what happens next. Avoid reproducing private long-form answers unless the recipient needs them. A link to an authenticated customer portal is often safer than placing detailed content in an inbox.
Reliability, deliverability, and observability
The HTTP request succeeding means Volanea accepted the email request; it does not mean a human has read the message. Treat sending, provider acceptance, delivery, bounce, complaint, and engagement as distinct stages when you design monitoring.
Start with a simple operational record containing the Typeform event ID, form ID, response token, recipient hash or redacted address, template name, Volanea message ID, attempted timestamp, and status. This record lets support staff answer “Was a confirmation sent?” without searching raw webhook bodies.
Protect the sender reputation
Even a legitimate Typeform transactional email can harm deliverability if it has poor list hygiene or confusing content. Required email fields reduce typos but do not eliminate them. If a workflow sends to addresses collected outside Typeform or imported from another source, validate them before sending; Volanea provides a free email address verification tool for checking an address before it becomes part of a sending workflow.
Keep transactional and promotional purposes separate in both logic and expectations. A confirmation should not silently become a newsletter. If you add optional marketing consent to the form, record the consent language, timestamp, source, and response separately, then use that record for campaign eligibility rather than assuming every form submitter opted in.
Plan for provider errors
A 4xx response commonly signals a request problem you should fix: missing required properties, an unverified sender, malformed recipient, or authentication issue. Retrying the identical bad request repeatedly creates noise rather than recovery.
A timeout, network error, or 5xx response can be transient. Retry those cases with exponential backoff and a bounded attempt count. Before each retry, consult your idempotency record so a delayed success does not result in another email. For business-critical messages, put failed jobs in a dead-letter queue and alert a human with enough metadata to investigate safely.
Alternatives: Zapier, Make, and a custom endpoint
A custom receiver is not the only way to connect the systems, but it is the clearest option when the email is part of your product or operations.
Zapier or Make can trigger from a Typeform submission and use an HTTP request step to call an email API. This can be a sensible prototype for a small team that needs a straightforward acknowledgement and has no application backend. Store the Volanea API key in the automation platform’s secure connection or secret facility, not in a mapped field.
The trade-offs are worth acknowledging:
- Visual automations are quick to build but can become difficult to review when branches, formatting, and error paths grow.
- Signature verification and exact raw-body handling may not be available in the same way as in your own endpoint.
- Idempotency, queueing, custom logging, and sophisticated retries usually require extra design.
- Usage limits and execution delays can affect cost and timing as submission volume rises.
A native Typeform webhook plus serverless function is usually the best balance for developers. It requires a deployment but gives you source control, secrets management, explicit HTTP behavior, and a direct path to a queue or database.
A full application endpoint and worker is appropriate when form responses start workflows: CRM creation, account provisioning, quotes, attachments, approval steps, or multiple recipient messages. In that model, accept and validate the webhook first, persist an event, and perform outbound email from a worker. The user-facing confirmation remains fast even if a downstream CRM is slow.
Test the complete flow before publishing
Test a real submission, not only the Volanea curl request. Form integrations often fail in the mapping layer: a field ref was changed, an optional answer was omitted, or the endpoint was deployed without the expected environment variable.
Use this production-readiness checklist:
- Submit the form with a test address you can inspect.
- Confirm that the receiver sees a valid
form_responseevent and verifies the signature. - Confirm
customer_emailand every required ref map to the expected values. - Verify the sender domain and inspect the delivered From name, subject, HTML, and text part.
- Submit the same test only through an intentional replay or retry path and verify that the event ID prevents a second send.
- Remove an optional answer and verify that the template still renders correctly.
- Simulate a Volanea API failure and ensure the event is retried or queued according to your policy.
- Review logs to ensure they do not contain the webhook secret, API key, or unnecessary form content.
Test recipient behavior too. Reply to the email, view it on mobile and desktop, and check that support staff can identify the related Typeform response through your correlation IDs. An integration that sends technically valid mail but routes replies to an unmonitored inbox still creates a poor customer experience.
A practical deployment checklist
Before enabling the Typeform transactional email flow for real respondents, confirm these controls are in place:
- An authenticated, verified Volanea sending domain and a stable From address
- A private
VOLANEA_API_KEYstored only in the runtime’s secret manager - A private
TYPEFORM_WEBHOOK_SECRETand HMAC validation on every request - Stable Typeform field refs, documented alongside the template mapping
- An atomic idempotency record keyed by Typeform
event_id - HTML escaping for every respondent-supplied value
- Clear separation between operational messages and marketing consent
- Monitoring for webhook failures, API failures, bounces, and complaints
- A tested process for replaying a failed event without sending duplicates
The smallest reliable implementation is not necessarily the shortest script. It is the one that assumes external requests can be forged, answers can be absent, providers can time out, and users can submit the form more than once. Designing for those realities makes the workflow dependable as volume and message importance increase.
FAQ
Can Typeform send directly to Volanea without my server?
Not as a native Volanea-Typeform app connection. Typeform can deliver a webhook, and an automation platform can make an HTTP request, but the Volanea API key must be held in a trusted server-side or automation-secret environment. A small webhook receiver is the most controllable direct integration pattern.
Which Typeform field should I use for the recipient email?
Use an Email question and assign it a stable ref such as customer_email. In the webhook answer object, read the answer whose field.ref matches that value and use its email property. Do not rely on answer position or question title.
Why do I need Typeform signature verification?
Your webhook URL is an internet-facing endpoint. Verifying the HMAC signature proves that the request body was signed with your configured Typeform webhook secret and helps prevent an attacker from using the endpoint to trigger emails.
How do I stop duplicate confirmation emails?
Persist Typeform’s top-level event_id as an idempotency key with a uniqueness constraint. If the same event is delivered again, acknowledge it but do not submit another Volanea send request.
Should I return an error when Volanea is temporarily unavailable?
For a simple synchronous receiver, return a non-2xx response after a temporary send failure so the webhook can be retried. For stronger reliability, save the validated event to a durable queue, return success after it is safely stored, and retry the email from a worker with backoff and idempotency controls.