Fillout is excellent at collecting structured responses, but a form submission is not itself an email workflow. To send email from Fillout with Volanea, use Fillout’s outbound webhook as the trigger, receive that submission on a secure server endpoint, map its answers, and make the Volanea REST API request from that server.

This matters because Fillout does not need to be your email sender, and Volanea does not need a native Fillout marketplace app for the integration to be dependable. The webhook is the connection point. Your endpoint is the small but important translation and security layer between a form-shaped payload and an email-shaped API request.

The integration architecture

The complete flow has four parts:

  1. A respondent submits a published Fillout form.
  2. Fillout sends a JSON webhook for that submission to an HTTPS endpoint you control.
  3. Your endpoint finds the answers it needs, validates them, and decides whether an email should be sent.
  4. Your endpoint calls Volanea’s email API with a server-side API key, then records the submission ID and result.

The concrete Fillout trigger is a form submission. It is not a contact record being created or a workflow stage changing: the event begins when a respondent completes and submits the form. That distinction affects how you design confirmation messages. A submitted form can contain incomplete optional answers, conditional questions that were never shown, or an email field that is syntactically valid but not deliverable.

A direct webhook-to-email-API connection is usually the wrong design. Fillout’s webhook body represents an entire submission, including its answers array. An email API expects recipient, sender, subject, and content fields. More importantly, placing a Volanea API key in a browser-side script, a public form URL, or client-visible configuration would let anyone who finds it send mail from your account.

Use a lightweight service instead. A serverless function, Cloudflare Worker, Express route, Next.js route handler, or small application backend is enough. It should be reachable over HTTPS and should return promptly after it has safely accepted the webhook.

What Fillout sends after a form submission

Fillout webhooks send a submission payload as JSON. The important structural detail is that responses live in an answers array rather than as top-level properties named after your questions. Each answer has metadata such as the question name, an ID, a type, and a value.

A typical submission event has this shape. IDs, question names, and answer values below are illustrative, but the nesting is the part your receiver must handle:

{
  "submissionId": "sub_01JQ7P7X8YJ4Z3D8N4S3K2M1A0",
  "formId": "frm_8xQ1pL2r",
  "formName": "Request a demo",
  "submissionTime": "2026-10-04T14:32:18.421Z",
  "answers": [
    {
      "id": "q_email",
      "name": "Work email",
      "type": "EmailInput",
      "value": "maya@example.com"
    },
    {
      "id": "q_name",
      "name": "First name",
      "type": "ShortAnswer",
      "value": "Maya"
    },
    {
      "id": "q_company",
      "name": "Company",
      "type": "ShortAnswer",
      "value": "Northstar Labs"
    },
    {
      "id": "q_consent",
      "name": "I agree to receive product updates",
      "type": "MultipleChoice",
      "value": "Yes"
    }
  ],
  "urlParameters": []
}

Treat this as an event envelope, not as a guaranteed contract for every question. The answers array can omit a question that was hidden by conditional logic, optional and left blank, or altered after a form revision. File uploads, address inputs, multi-select controls, calculations, scheduling data, and other advanced fields can have values that are not simple strings.

Map by question ID, not only by label

Question labels are for people. IDs are better integration keys. Someone can edit “Work email” to “Business email” in Fillout without intending to change automation; a name-based mapping would quietly stop finding the address. Capture the IDs from an actual webhook delivery or your form’s data and keep them in server-side environment variables.

For example, use variables such as FILLOUT_EMAIL_QUESTION_ID=q_email and FILLOUT_NAME_QUESTION_ID=q_name. This also makes development, staging, and production forms easier to separate. Each form can have different question IDs while the same code runs unchanged.

Do not assume that the first item in answers is the email address. Question order may change, and conditional questions make positional mapping fragile. Search for the specific ID and explicitly convert the value to the type you expect.

Set up the Fillout webhook

In Fillout, configure a webhook integration for the form that should initiate email. Provide your receiver’s HTTPS URL, such as https://example.com/webhooks/fillout. Submit a real test response after saving it, then inspect the payload your receiver logged before writing final mappings.

The endpoint should be dedicated to this integration. Avoid pointing Fillout at an endpoint that also accepts browser form submissions, because it becomes harder to apply event-specific authentication, idempotency, logging, and rate limits.

Before enabling production sends, establish these operational choices:

  • Use a production form and production webhook endpoint separately from test assets.
  • Select a test recipient you control while validating templates and mappings.
  • Keep question IDs and your Volanea sender address in environment variables rather than in source code.
  • Decide whether every submission receives a message or whether consent, qualification, or an internal status must be present first.
  • Record the Fillout submissionId before or alongside sending so a retry cannot generate a second email.

Fillout webhooks should be considered at-least-once delivery. A network interruption can leave Fillout unsure whether your endpoint accepted the event, even when your service already started processing it. Retrying is a sensible behavior for Fillout, but it means your service must make duplicate delivery harmless.

Give the webhook a secret of its own

If your Fillout webhook setup supports a custom request header, put a randomly generated secret in that header and verify it on the server. Use a name such as X-Webhook-Secret; do not reuse your Volanea API key for this purpose. A webhook secret authenticates the event source to your receiver, while the Volanea key authenticates your receiver to Volanea.

If your Fillout configuration does not provide a header mechanism in your account or plan, use a long, unguessable path component as a minimum measure, such as /webhooks/fillout/<random-value>, and add network protections where available. That is weaker than a signed webhook scheme, so do not treat the URL as public documentation or expose it in client code. Regardless of how the inbound webhook is protected, validate the body before sending an email.

Build the secure Volanea relay

The following Node.js example is an Express route that receives Fillout’s submission JSON, maps answers by question ID, deduplicates by submissionId, and sends through Volanea. It uses a simple in-memory Set only to make the mechanics readable. Replace that set with a database table, Redis key, or durable queue in production.

The Volanea key is read from process.env.VOLANEA_API_KEY. That means it belongs in the encrypted server-side environment settings for your hosting provider, never in Fillout, frontend JavaScript, a public repository, or an email template.

import express from "express";

const app = express();
app.use(express.json({ limit: "1mb" }));

const processedSubmissionIds = new Set(); // Use durable storage in production.

const answerById = (answers, id) => {
  const answer = answers.find((item) => item.id === id);
  return answer?.value ?? null;
};

app.post("/webhooks/fillout", async (req, res) => {
  // Optional when a custom Fillout webhook header is configured:
  if (process.env.FILLOUT_WEBHOOK_SECRET &&
      req.get("X-Webhook-Secret") !== process.env.FILLOUT_WEBHOOK_SECRET) {
    return res.status(401).json({ error: "Unauthorized webhook" });
  }

  const { submissionId, formId, answers } = req.body ?? {};

  if (!submissionId || !formId || !Array.isArray(answers)) {
    return res.status(400).json({ error: "Invalid Fillout submission payload" });
  }

  // Idempotency: do not send the same submission twice after a retry.
  if (processedSubmissionIds.has(submissionId)) {
    return res.status(200).json({ accepted: true, duplicate: true });
  }

  const email = answerById(answers, process.env.FILLOUT_EMAIL_QUESTION_ID);
  const firstName = answerById(answers, process.env.FILLOUT_NAME_QUESTION_ID);
  const company = answerById(answers, process.env.FILLOUT_COMPANY_QUESTION_ID);
  const consent = answerById(answers, process.env.FILLOUT_CONSENT_QUESTION_ID);

  if (typeof email !== "string" || !email.includes("@")) {
    return res.status(422).json({ error: "A valid email answer is required" });
  }

  // Example policy: only send this non-essential follow-up after explicit consent.
  if (consent !== "Yes") {
    processedSubmissionIds.add(submissionId);
    return res.status(200).json({ accepted: true, skipped: "no consent" });
  }

  const safeName = typeof firstName === "string" ? firstName.trim() : "there";
  const safeCompany = typeof company === "string" ? company.trim() : "your team";

  const volaneaResponse = await fetch("https://api.volanea.com/v1/emails", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `fillout-${submissionId}`
    },
    body: JSON.stringify({
      from: {
        email: process.env.VOLANEA_FROM_EMAIL,
        name: "Northstar Labs"
      },
      to: [{ email, name: safeName }],
      subject: `Thanks, ${safeName} — we received your request`,
      html: `<p>Hi ${safeName},</p><p>Thanks for contacting us about ${safeCompany}. We will be in touch shortly.</p>`,
      text: `Hi ${safeName},\n\nThanks for contacting us about ${safeCompany}. We will be in touch shortly.`,
      tags: ["fillout", "demo-request"]
    })
  });

  if (!volaneaResponse.ok) {
    const detail = await volaneaResponse.text();
    console.error("Volanea send failed", volaneaResponse.status, detail);
    // Return non-2xx so the delivery can be retried according to webhook behavior.
    return res.status(502).json({ error: "Email provider rejected the send" });
  }

  processedSubmissionIds.add(submissionId);
  return res.status(200).json({ accepted: true });
});

app.listen(process.env.PORT || 3000);

Before deploying this request, compare the endpoint, authentication header, payload properties, and supported idempotency mechanism with the current Volanea API reference and setup guides. The essential mapping is stable even if you use another server runtime: answers[] becomes a recipient and personalized content; the Volanea key remains on the server.

Escape personal data before putting it in HTML

The concise example above inserts safeName and safeCompany into HTML to make the field mapping clear. Production code must HTML-escape any respondent-provided value before interpolating it. A respondent can enter angle brackets, quotes, and arbitrary text in a short-answer field. Escaping prevents that text from changing the email markup.

Also keep the plain-text version. Some mail clients prefer it, and it improves accessibility and resilience when HTML is disabled. Never put a secret, account status, raw internal notes, or data that the recipient did not provide into an automatic confirmation merely because it is available in the Fillout payload.

Keep credentials out of Fillout and the browser

There are two kinds of secrets in this setup, and they have different jobs.

The Volanea API key authorizes email sending. Store it only in server-side environment configuration, where the relay can read it at runtime. Rotate it if it is exposed, scope it as narrowly as the platform permits, and use different keys for test and production environments.

The webhook secret, if you use one, helps your service reject unsolicited requests. Store it in both Fillout’s webhook configuration and the server’s secret manager. It is still sensitive, but disclosure of that secret does not automatically grant permission to send through Volanea.

Do not attempt to use Fillout’s URL parameters, hidden fields, custom JavaScript, or a browser fetch() request to carry the Volanea API key. All of those can become visible to a respondent, browser extension, proxy, page source, network inspector, or third-party script. A key in a client-visible configuration is a sending credential waiting to be abused.

A server relay also lets you keep sender identity under your control. The from.email should be a domain and mailbox you have configured for Volanea, not an address submitted in the form. Put the submitter’s address in to; if a reply should route to them, use a properly supported reply-to field only after confirming the address and your mail policy permit it.

Design the email event before writing the template

A form submission is an event, not necessarily consent to ongoing marketing. The right email depends on what the respondent reasonably expects after submitting the form.

Good transactional or operational examples include:

  • A receipt after someone submits a paid registration form.
  • A confirmation that a support request was received.
  • A secure sign-in or access link requested through a form.
  • A copy of a document request or booking inquiry.
  • An internal notification to an account owner after a qualified lead submits a form.

A promotional newsletter, nurture series, or product-update sequence requires a separate consent and audience model. Do not make an unchecked “contact me” field mean permission for unrelated marketing. Capture the consent response, source form, timestamp, and policy version you need for your compliance process.

For an internal alert, map the recipient to a fixed team inbox or route it based on a controlled answer such as region. Do not allow an arbitrary form answer to determine a privileged internal recipient. For an external confirmation, keep the content expected and useful: what was received, what happens next, and how to correct a mistake.

Validate recipient data before invoking the API

A basic @ check is only a guard against obviously malformed input. Your form’s email input validation should do the first pass, while the server repeats essential checks because webhook bodies are untrusted input. For higher-value flows, validate deliverability before triggering expensive downstream work. Volanea’s email address verification tool can help distinguish a formatting check from a more useful address-quality decision.

Do not silently replace an invalid email with a default recipient. That turns a data-quality problem into an accidental disclosure problem. Return a handled response, record why the event was skipped, and arrange a workflow for reviewing submissions that require follow-up.

When this breaks: Fillout-to-Volanea failure modes

This integration has two independent hops: Fillout to your receiver, then your receiver to Volanea. Logging only “email failed” makes diagnosis needlessly difficult. Log the Fillout submission ID, form ID, a redacted recipient indicator, the outbound email request ID if available, HTTP status, and timestamps for each hop.

Retry deliveries can create duplicate email

A webhook sender may retry when it does not receive a timely successful response, or when a network failure obscures the response. Your relay might have sent the email successfully but failed before returning 200. On a retry, an unprotected handler sends the same confirmation again.

Use submissionId as your primary idempotency key. Create a durable record with a unique constraint before sending, or place the event in a queue with deduplication. If Volanea supports an idempotency key for sends, pass a deterministic value such as fillout-<submissionId> too. The database is still important because it protects your workflow across restarts and gives you an audit trail.

The in-memory set in the sample is not production-grade: it is emptied on deploy, does not work across multiple instances, and has no recovery state. A table with submission_id, status, email_provider_id, attempt_count, and timestamps is a practical starting point.

Webhook timeouts cause avoidable retries

Do not perform slow enrichment, CRM searches, PDF rendering, or multiple external requests before acknowledging a webhook. The safest pattern is to validate and durably enqueue the event, return a successful response quickly, then let a worker send the email. That separates Fillout’s delivery window from Volanea’s API availability.

If you choose synchronous handling for a small-volume form, set a conservative outbound timeout, catch network errors, and make processing idempotent. Returning success before persisting the event risks losing it; returning failure after successfully sending risks a duplicate. A durable queue resolves both sides of that trade-off.

A mapped answer may be absent

Conditional logic can mean the email question was not displayed. Optional questions can be blank. A form editor may duplicate or replace a question, changing its ID. Some fields and advanced submission data may also not be present in the form of data your integration expects, depending on the feature and plan available to the form owner.

Handle missing values deliberately. If the recipient email is absent, do not call Volanea. Return or record a validation result, alert the form owner if this becomes frequent, and inspect the actual captured webhook payload. If a field is a list or object rather than a string, serialize or normalize it only after deciding how it belongs in the email.

Sender rejection and deliverability issues are separate problems

A webhook delivered successfully does not guarantee that an email was accepted, and API acceptance does not guarantee inbox placement. Check that the configured sender is authorized, that domain authentication is complete, and that your message content matches the recipient’s expectation. Use a clear sender name, a relevant subject, a text alternative, and a restrained sending pattern.

For debugging, distinguish a 4xx request problem—such as an invalid recipient, bad authentication, or malformed payload—from a transient 5xx or network failure. Retry transient failures with bounded exponential backoff. Do not blindly retry permanent validation failures; fix the data or configuration that caused them.

Test the integration without surprising real people

Use a test form or a dedicated test path first. Fill in each conditional branch at least once, submit an address you control, and compare the captured Fillout JSON with the mappings in code. Then test a duplicate delivery by replaying the exact payload and verify that only one email is sent.

A useful test matrix includes:

  1. A normal submission with every mapped answer present.
  2. A submission with no consent, confirming the message is intentionally skipped.
  3. A submission with a missing or malformed recipient field.
  4. A conditional path where the email field is not displayed.
  5. The same submissionId delivered twice.
  6. A forced Volanea API failure, confirming the event is retried or queued according to your design.
  7. Input containing <, >, quotes, Unicode characters, and long values, confirming HTML escaping and truncation rules.

Keep production test sends out of customer lists. Tag test messages, use a distinct subject prefix, and avoid copying production submissions into development logs. Form answers often contain personal data, so restrict log access and establish retention limits.

Alternatives when you do not want to host code

Automation services can receive a Fillout submission and call an HTTP endpoint, but they do not remove the security and data-mapping questions. If you use Zapier or Make as middleware, store the Volanea API key in that platform’s protected connection or credential area, not in a field supplied by Fillout. Configure the HTTP step with fixed authentication and sender values, then map only approved answer fields into recipient and content fields.

This can be appropriate for a low-volume internal alert, especially when non-developers need to maintain the workflow. It is less attractive for security-sensitive, high-volume, or exactly-once email flows, where durable idempotency, reviewable code, controlled retries, and detailed observability matter more.

A custom relay gives you fuller control over HTML escaping, consent logic, sender rules, message tags, queues, and audit records. A middleware workflow gives you faster iteration. Either way, do not expose the sending key to the respondent’s browser, and test what happens when the same submission arrives more than once.

Operational checklist before going live

Before switching a real Fillout form to email automation, confirm all of the following:

  • The form submission webhook reaches an HTTPS endpoint you control.
  • The receiver verifies an inbound secret or has equivalent access controls.
  • Recipient, consent, and personalization values are mapped by stable question IDs.
  • Missing, hidden, and non-string answer values are handled safely.
  • The Volanea API key is stored only in server-side or protected automation credentials.
  • Your from address is authorized and domain authentication is configured.
  • Every submission is deduplicated with durable storage using submissionId.
  • HTML values are escaped and a plain-text message is present.
  • Logs redact sensitive data and retain enough identifiers to trace failures.
  • Test, staging, and production forms do not share credentials or recipients accidentally.

The result is a deliberately small integration with clear boundaries: Fillout captures the response, your server applies business rules, and Volanea sends the email. That structure is easier to secure, easier to debug, and more resilient than trying to make a form client act like an email backend.

FAQ

Can Fillout send directly to Volanea without a native app?

Fillout can initiate the flow with a form-submission webhook, but its submission payload does not automatically become an email API request. Use a server endpoint or an automation middleware step to map the payload and securely call Volanea.

What is the Fillout trigger for this workflow?

The trigger is a completed form submission. Your webhook receiver should treat each submission as an event identified by Fillout’s submissionId.

Where should the Volanea API key be stored?

Store it in a server-side secret manager or protected automation credential store. Never place it in Fillout form fields, URL parameters, frontend code, or any configuration visible to respondents.

How do I stop duplicate confirmation emails?

Persist the Fillout submissionId in a database or queue with a uniqueness rule before sending. If a webhook is retried, return success for the already-processed ID instead of sending again.

Why is an email answer missing from some submissions?

The question may be optional, hidden by conditional logic, replaced in the form editor, or represented differently than your code expects. Inspect a real webhook payload, map by question ID, and treat absent values as a handled validation case.