If you need to send transactional email from HubSpot, the dependable pattern is not a native app installation: it is a HubSpot workflow webhook that calls your server, followed by a Volanea REST API request. That extra relay gives you control over credentials, validation, templates, retries, and the difference between a CRM event and a message that should actually be delivered.

There is no native Volanea application or one-click “Send Email From HubSpot” connection to install. Instead, HubSpot supplies the event and contact context, while Volanea supplies the email delivery API. Your application sits between them and translates an approved workflow event into a transactional message.

This guide shows the architecture, the payload you should send from HubSpot, a Node.js relay implementation, the Volanea send request, and the operational details that prevent duplicate or unsafe sends.

What this integration does—and does not do

HubSpot is often the system where a business event becomes visible first: a deal moves to Closed Won, a support property changes, a form is submitted, or an onboarding task is completed. Those events can enroll a record in a workflow. A workflow webhook can then make an HTTP request to an endpoint you control.

Volanea is the sending layer. It accepts a structured email request, applies your authenticated sending domain and delivery configuration, and returns a response that your application can log and act on. The relay is the integration layer that decides whether the event is valid, maps fields, and makes the API request.

That means this setup is appropriate for messages such as:

  • account activation and verification emails;
  • welcome messages after a qualified signup;
  • invoices, receipts, and payment-status notifications;
  • appointment confirmations and reminders;
  • customer onboarding milestones;
  • security alerts and password-related notifications; and
  • operational messages triggered by a deal or ticket property.

It is not a replacement for HubSpot marketing email features. Promotional newsletters, broad lifecycle campaigns, and messages requiring campaign-style subscription management should be designed as marketing communications. Transactional mail should be tied to a recipient action, account state, service request, or necessary operational update.

The distinction matters operationally as well as legally. A workflow enrollment is evidence that something happened in HubSpot; it is not automatically evidence that every message is appropriate to send. Your relay should make the final decision based on message type, recipient data, consent rules where applicable, and the state of the event.

The recommended HubSpot-to-Volanea architecture

The simplest reliable design has three components:

  1. HubSpot workflow: identifies the business event and issues an outbound webhook request.
  2. Your webhook relay: authenticates the request, validates and normalizes the payload, prevents duplicate sends, and selects the email content.
  3. Volanea REST API: receives the final transactional email request and hands it to the email-delivery infrastructure.

The relay can be an Express application, a serverless function, a worker, or an endpoint in your existing backend. It does not have to be large. However, it should be server-side. Do not put a Volanea API key in browser code, a public form, or a client-visible HubSpot page.

Why use a relay instead of calling Volanea directly from a workflow?

A direct webhook can appear attractive because it removes one service. In practice, it creates several problems. A workflow tool is good at initiating an HTTP request, but it is not a full integration runtime. It is a poor place to implement conditional templates, safely rotate secrets, validate recipient addresses, record idempotency keys, interpret provider responses, or retry transient failures.

A relay also lets you make a deliberate choice about what data leaves HubSpot. Instead of passing every available contact property, send only the values needed for this message. That reduces accidental exposure of notes, internal fields, or sensitive CRM context.

A useful event flow

For a customer welcome email, the flow might be:

  1. A contact reaches a workflow after completing a signup-related action.
  2. HubSpot sends the contact email, first name, contact ID, and a workflow event identifier to your endpoint.
  3. The endpoint verifies its shared secret and validates the recipient.
  4. The endpoint creates a deterministic idempotency key from the event and contact IDs.
  5. The endpoint sends a welcome email to Volanea.
  6. The endpoint stores the Volanea message identifier and returns a successful HTTP response to HubSpot.
  7. Delivery events, if you consume them, are recorded separately from the initial send result.

The key insight is that an accepted API request is not the same as inbox delivery. Keep those states separate in your database and reporting.

How HubSpot workflow webhook payloads work

There is no single, immutable “HubSpot webhook payload shape” for the workflow action described here. The workflow’s outbound webhook request is configured by the portal user: its URL, method, headers, and request body are chosen for that action. Therefore, the actual payload your endpoint receives is the JSON body you configure HubSpot to send, after HubSpot resolves the selected record values or personalization tokens.

That is different from HubSpot developer-app webhook subscriptions. Developer-app webhooks have HubSpot-defined event payloads and signatures. Do not confuse those subscription events with a workflow action that makes an outbound HTTP request.

For this integration, use a compact, explicit JSON object. Avoid trying to forward a complete contact record. A recommended request body is:

{
  "event": "customer_welcome",
  "eventId": "hs-workflow-welcome-{{contact.hs_object_id}}-{{contact.createdate}}",
  "contactId": "{{contact.hs_object_id}}",
  "email": "{{contact.email}}",
  "firstName": "{{contact.firstname}}",
  "companyName": "{{contact.company}}",
  "plan": "{{contact.plan}}"
}

The values shown in double braces are illustrative property substitutions. Build the body in HubSpot using the workflow editor’s property or personalization-token picker rather than copying token syntax blindly: the exact token rendered by the editor depends on the object and property selected. Before activating the workflow, use its available test or enrollment tooling to inspect what your endpoint actually receives.

The important part is the resulting JSON, not the visual token syntax. After substitution, a real request should look like this:

{
  "event": "customer_welcome",
  "eventId": "hs-workflow-welcome-1049231-2026-08-22T10:14:03.000Z",
  "contactId": "1049231",
  "email": "maya@example.com",
  "firstName": "Maya",
  "companyName": "Northstar Labs",
  "plan": "starter"
}

Configure only the properties your email needs

The body should contain stable identifiers and presentation values separately. contactId is useful for audit logs and troubleshooting. email, firstName, and companyName are needed for the content. An eventId supports idempotency. If you have a true external order, invoice, or ticket identifier, include it too.

Do not include a password, access token, full support conversation, payment card data, or internal sales notes. A webhook body can be logged by intermediary systems during debugging. Treat it as data leaving your CRM boundary.

Set a shared authentication secret

Configure a secret value on the outbound request, such as an Authorization header containing a long, random bearer token. Your relay compares that value with a server-side environment variable before processing the JSON.

Use HTTPS. Reject requests without the expected secret. Also limit the endpoint to the HTTP method you configured, normally POST, and impose a reasonable body-size limit. A secret configured in a workflow is still accessible to appropriately privileged portal users, so rotate it when access changes and never reuse your Volanea API key as the HubSpot-to-relay secret.

Prepare Volanea before wiring the workflow

Before sending live traffic, set up the sending identity you intend to use in Volanea. A transactional email should have a stable From address on a domain you control, such as notifications@example.com or receipts@example.com. The exact sending address should match the authenticated domain and the purpose of the message.

Follow the domain authentication instructions in the email API reference and setup guides to add the DNS records Volanea provides for your domain. DNS records should be copied exactly from the Volanea dashboard or documentation for your domain; do not substitute values from another provider or an old setup. Authentication is the foundation for consistent alignment and mailbox-provider trust.

Keep these separate in your deployment configuration:

  • VOLANEA_API_KEY: credential used only by your relay to call Volanea;
  • VOLANEA_FROM_EMAIL: the verified sender address;
  • VOLANEA_FROM_NAME: the human-readable sender name;
  • HUBSPOT_WEBHOOK_SECRET: credential HubSpot sends to your relay; and
  • VOLANEA_API_URL: the current Volanea send endpoint from the API documentation.

Using environment variables is not merely a deployment preference. It prevents keys from being committed to source control and allows independent rotation. A staging environment should use a separate key and, ideally, a separate authenticated subdomain or a tightly controlled test-recipient allowlist.

Select the right message construction approach

For a small number of operational emails, building HTML and text in the relay is straightforward. For a larger system, use a template renderer in your application and keep content versioned alongside code. In both cases, send a plain-text alternative. Plain text improves accessibility, gives recipients a useful fallback, and makes a message more robust when HTML is blocked.

Keep display data separate from HTML. Never directly interpolate untrusted CRM values into HTML without escaping them. A company name is usually harmless, but a freeform property can contain characters that break markup or introduce unwanted links. Escape text before placing it into HTML, and use an allowlisted value for URL parameters.

Build the secure webhook relay

The following example uses Node.js, Express, and the built-in fetch available in current Node.js releases. It implements the essential steps: authentication, schema checks, address validation, idempotency, HTML escaping, and a Volanea API call.

Because API endpoints and request fields can change, set VOLANEA_API_URL to the send endpoint documented for your Volanea account rather than hard-coding an endpoint you found in an old code sample. The email object below uses the standard send fields—sender, recipient, subject, HTML, text, tags, and metadata—so confirm the current field names against the Volanea reference before deploying.

import express from "express";
import crypto from "node:crypto";

const app = express();
app.use(express.json({ limit: "100kb" }));

const sentEvents = new Map(); // Replace with Redis or a database in production.

function safeEqual(actual = "", expected = "") {
  const left = Buffer.from(actual);
  const right = Buffer.from(expected);
  return left.length === right.length && crypto.timingSafeEqual(left, right);
}

function escapeHtml(value = "") {
  return String(value)
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/\"/g, "&quot;")
    .replace(/'/g, "&#39;");
}

function isEmail(value) {
  return typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}

app.post("/webhooks/hubspot/transactional-email", async (req, res) => {
  const authorization = req.get("authorization") || "";
  const expected = `Bearer ${process.env.HUBSPOT_WEBHOOK_SECRET}`;

  if (!safeEqual(authorization, expected)) {
    return res.status(401).json({ error: "unauthorized" });
  }

  const { event, eventId, contactId, email, firstName = "", companyName = "", plan = "" } = req.body;

  if (event !== "customer_welcome") {
    return res.status(400).json({ error: "unsupported_event" });
  }
  if (!eventId || !contactId || !isEmail(email)) {
    return res.status(422).json({ error: "invalid_payload" });
  }

  // A production implementation should make this an atomic database/Redis operation.
  if (sentEvents.has(eventId)) {
    return res.status(200).json({ status: "already_processed" });
  }

  const recipientName = escapeHtml(firstName) || "there";
  const safeCompany = escapeHtml(companyName);
  const safePlan = escapeHtml(plan);
  const subject = "Welcome—your account is ready";
  const html = `
    <p>Hi ${recipientName},</p>
    <p>Your ${safePlan ? `${safePlan} ` : ""}account is ready.</p>
    ${safeCompany ? `<p>We are glad to have ${safeCompany} with us.</p>` : ""}
    <p>If you need help, reply to this email.</p>
  `;
  const text = [
    `Hi ${firstName || "there"},`,
    "",
    `Your ${plan ? `${plan} ` : ""}account is ready.",
    companyName ? `We are glad to have ${companyName} with us.` : "",
    "",
    "If you need help, reply to this email."
  ].filter(Boolean).join("\n");

  const volaneaResponse = await fetch(process.env.VOLANEA_API_URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      from: {
        email: process.env.VOLANEA_FROM_EMAIL,
        name: process.env.VOLANEA_FROM_NAME
      },
      to: [{ email }],
      subject,
      html,
      text,
      tags: ["hubspot", "transactional", "customer_welcome"],
      metadata: {
        hubspotContactId: String(contactId),
        hubspotEventId: String(eventId)
      }
    })
  });

  const responseText = await volaneaResponse.text();
  if (!volaneaResponse.ok) {
    console.error("Volanea send failed", volaneaResponse.status, responseText);
    return res.status(502).json({ error: "email_provider_failed" });
  }

  sentEvents.set(eventId, { sentAt: new Date().toISOString(), responseText });
  return res.status(200).json({ status: "sent" });
});

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

The VOLANEA_API_URL configuration is intentional. Consult the current Volanea documentation for the precise endpoint and schema supported by your account, then make that endpoint a deployment setting. This avoids silently freezing a provider URL into application code and makes a future API-version migration easier.

Replace the in-memory deduplication store

The Map in the example illustrates the logic but is not production-safe. It disappears when the process restarts, does not coordinate across multiple instances, and is not atomic. Use a database unique constraint, Redis SET with an expiry and “only if absent” behavior, or your job system’s idempotency facility.

Store at least the event ID, contact ID, message type, send timestamp, provider message ID when available, and final state. A unique key such as hubspot:{eventId}:customer_welcome prevents accidental duplicate sends when HubSpot retries a request or an operator reenrolls a record.

Map HubSpot data to a transactional email safely

The mapping layer is where a basic webhook becomes a dependable messaging system. Define each message type as a small contract: required properties, optional properties, sender identity, subject logic, template, and permitted recipient source.

For example, a receipt email might require invoiceId, invoiceTotal, currency, and email; an onboarding email might require only email and firstName. If required values are missing, do not send a half-complete email. Return or record a validation failure, then fix the workflow or upstream property population.

Use an allowlist of event names

Do not let a webhook body supply arbitrary subjects, HTML, From addresses, or template names. An endpoint that accepts any subject and html value can become an accidental internal spam tool. Instead, allow a known event name such as customer_welcome, invoice_paid, or ticket_received, and map each one to server-owned content.

This is especially important when workflows are edited by multiple teams. CRM automation changes should not automatically grant the ability to send an email as a financial, security, or legal sender identity.

Validate addresses before sending

At a minimum, reject empty and malformed addresses. For high-value workflows, also consider verifying an address before the triggering event occurs, particularly if addresses originate in a public form or imported list. Volanea’s free address verification tool can help investigate individual addresses during testing or support work.

Address syntax validation is not mailbox validation. A syntactically valid address may still be nonexistent, disabled, or risky. The best prevention is collecting addresses carefully, confirming them where appropriate, and suppressing recipients after hard bounces or explicit unsubscribe-related signals that apply to your message category.

Test the complete flow before activation

A production-looking email is not proof that the integration is correct. Test every boundary: HubSpot property rendering, webhook authentication, relay validation, Volanea acceptance, rendered content, and inbox placement.

Start with a dedicated test contact whose email you control. Populate every property your workflow references, including optional fields. Then trigger the workflow once and inspect the relay’s structured logs. Do not log full email bodies or secrets; log event IDs, contact IDs, status codes, and provider message IDs.

Use this checklist:

  1. Confirm the workflow sends POST requests to the intended HTTPS endpoint.
  2. Confirm the relay rejects a missing or incorrect shared secret.
  3. Confirm the received JSON contains resolved values rather than empty placeholders.
  4. Confirm malformed email addresses return a validation error and create no send.
  5. Confirm the sender address is authenticated in Volanea.
  6. Confirm both HTML and text render properly in at least one major webmail client and one mobile client.
  7. Trigger the same event twice and verify that idempotency prevents a second send.
  8. Test an intentional Volanea failure and verify that the error is visible to an operator.

Be cautious with workflow testing: some platforms offer test execution that does not behave exactly like a live enrollment, while others can send real requests. Treat every test webhook as capable of sending a real email unless your relay has a staging mode or recipient allowlist.

Retries, duplicates, and delivery state

Outbound webhooks and email APIs both operate over networks, which means ambiguity is normal. Your relay may time out after Volanea accepts a message. HubSpot may retry because it did not receive a timely response. A process may restart after the API call but before it writes a success record.

Idempotency is what turns those ambiguous cases into a controlled outcome. Generate or receive a stable event ID, claim it atomically before sending, and store the downstream result. If a request repeats, return success for the already-processed event rather than initiating another message.

Decide which errors should retry

Separate failures into categories:

  • Permanent input failures: missing email, unsupported event type, invalid required data. Do not retry automatically; fix the source data or workflow.
  • Authentication failures: invalid HubSpot secret or invalid Volanea credential. Do not retry repeatedly; rotate or correct configuration.
  • Rate-limit and server failures: HTTP 429 and many 5xx responses can be transient. Queue a retry with exponential backoff.
  • Network ambiguity: timeout or connection reset. Check your idempotency record and provider response strategy before retrying.

Do not make HubSpot wait for a long retry loop. A better model is to validate and enqueue quickly, return a successful response after durable acceptance into your own queue, and have a background worker send to Volanea. That architecture is especially useful when a workflow may trigger thousands of events after a bulk CRM update.

Separate accepted, delivered, and engaged

Record three different categories of status. “Accepted” means Volanea accepted the send request. “Delivered” means a downstream delivery event indicates mailbox-provider acceptance, where such event data is available. “Engaged” refers to opens or clicks and is neither a delivery guarantee nor an appropriate signal for every transactional program.

This separation prevents a common support mistake: telling a customer an email “was delivered” when the system only knows that an API request was accepted. It also helps diagnose whether a problem is in HubSpot enrollment, your webhook endpoint, API authentication, or delivery after sending.

Deliverability and message design considerations

A technically correct integration can still produce poor recipient experience if it sends unexpected messages, changes sender identities often, or ignores bounces. Transactional senders earn trust through consistency: one recognizable From identity, clear subjects, relevant content, and a predictable cadence.

Use a From name that identifies the product or organization. Keep reply handling intentional. If recipients can reply for help, monitor the mailbox. If replies should go elsewhere, set a suitable Reply-To address according to the current Volanea API schema and your support process.

Avoid using the same transactional sender for unrelated marketing promotions. Mailbox providers and recipients assess patterns over time. A confirmation, a security alert, and a sales blast have different expectations, and mixing them weakens your operational boundaries.

Message content should also be resilient. Include the essential action or information in text, use descriptive links, avoid image-only messages, and ensure a confirmation contains the details a recipient needs without requiring them to search a portal. For account or security emails, include recognizable context while avoiding unnecessary sensitive data.

Operational ownership and change management

This integration spans CRM administrators, developers, and whoever owns email operations. Assign responsibility before an incident forces the question. CRM owners should own workflow enrollment criteria and property quality. Engineering should own the relay, secrets, monitoring, and deployment. Email operations should own authenticated domains, sender policy, suppression handling, and delivery monitoring.

Version your event contract. If a workflow changes plan to subscriptionTier, deploy relay support before activating the workflow change. If you introduce a new email type, add it to the server allowlist, test it in staging, and review its sender and content separately.

A small operational runbook should answer these questions:

  • Which workflow triggers this message?
  • What endpoint receives the webhook?
  • Which secret authenticates HubSpot to that endpoint?
  • Which Volanea sender and API credential are used?
  • What idempotency key prevents duplicates?
  • Where are failed sends and provider responses logged?
  • Who can pause the workflow or disable sends during an incident?

This documentation is more valuable than it sounds. When a contact reports a missing receipt, the team should be able to trace one event through enrollment, webhook request, relay validation, provider acceptance, and delivery events without guessing.

Common implementation mistakes

The most common error is treating the workflow webhook as a native email-provider integration. It is not. The webhook is a transport mechanism, and your endpoint is responsible for interpreting the payload and protecting provider credentials.

Another common error is putting all personalization logic in the workflow body. That makes email content hard to review, test, version, and escape safely. Keep the workflow payload focused on data; keep message construction in code or a controlled template system.

Other mistakes to avoid include:

  • sending the Volanea API key as the HubSpot webhook authentication secret;
  • allowing any workflow to select an arbitrary sender address or HTML body;
  • relying on process memory for duplicate prevention;
  • assuming API acceptance proves inbox delivery;
  • testing with real customer records without an allowlist;
  • sending from an unauthenticated or mismatched domain; and
  • logging raw webhook bodies that contain more personal data than operators need.

A deliberate relay may seem like additional work, but it is the component that makes the connection auditable and safe to evolve.

Conclusion: make HubSpot the trigger and Volanea the sender

To send transactional email from HubSpot using Volanea, use HubSpot’s workflow webhook capability to notify a server endpoint you control. Have that endpoint authenticate the request, validate a narrow JSON payload, deduplicate the event, render server-owned content, and call the current Volanea REST send endpoint with a protected API key.

This is not a native app flow, and that is a strength rather than a limitation. The webhook-to-API pattern keeps your sender credentials out of the CRM automation layer, lets you enforce message policy, and gives you a durable place to handle retries and delivery records. Once the first message type is working, you can add new transactional events through the same tested contract.

FAQ

Is there a native Volanea integration for sending email from HubSpot?

No native Volanea app installation is required or assumed in this guide. The integration uses a HubSpot workflow’s outbound webhook capability plus your own server-side relay, which calls the Volanea REST API.

What payload does HubSpot send to my workflow webhook?

For a workflow outbound webhook, the body is the JSON you configure in the workflow action, populated with the selected record values. Use a small explicit schema containing an event name, stable event ID, contact ID, recipient email, and only the personalization fields your message needs.

Can I call the Volanea API directly from HubSpot?

A direct request may be possible depending on the workflow action’s HTTP configuration, but a server-side relay is safer and more maintainable. It protects the provider key, validates data, handles idempotency, and gives you control over retries and templates.

How do I prevent duplicate transactional emails?

Include a stable event identifier in the webhook body and enforce an atomic unique record for that event in a database or Redis before sending. If the same request arrives again, return an already-processed response instead of creating another message.

Does a successful Volanea API response mean the recipient received the email?

No. It normally means the sending API accepted the request. Track provider delivery events separately where available, and distinguish accepted, delivered, bounced, and engaged states in your reporting.