Send email from Close without pretending there is a native marketplace app: configure a Close webhook, receive the event in a server-side endpoint, and make one authenticated Volanea REST API call. This approach keeps sending credentials out of Close client-visible configuration while giving your team control over templates, recipient rules, retries, and delivery monitoring.

Close has a strong built-in communication stack, but a custom email workflow is useful when a CRM event must trigger a message from your product, operations, support, or transactional sending domain. For example, you may want a prospect to receive an onboarding email when a new Lead enters Close, a customer to receive a service notice when an Opportunity is won, or an internal team to receive an alert when a Close Form is submitted.

There is no native Volanea app, Close marketplace listing, or one-click plugin to install for this workflow. The direct integration path is Close’s webhook subscription API. Close sends an HTTP POST to an endpoint you control when a subscribed event occurs; that endpoint validates and normalizes the event, then sends the email through Volanea.

What this integration does

The architecture is deliberately simple:

  1. A Lead is created in Close.
  2. Close emits a lead.created webhook event to your HTTPS endpoint.
  3. Your server reads the lead and its contact data from event.data.
  4. Your server chooses an eligible contact email address.
  5. Your server calls POST https://api.volanea.com/v1/send.
  6. Volanea accepts the message for transactional delivery and records the send outcome.

The concrete Close trigger in this guide is Lead created. In Close terminology, a Lead represents a company or organization and can contain Contacts, Opportunities, Tasks, Activities, and custom fields. A newly created Lead can include Contacts with email addresses, making it a useful event for a welcome, confirmation, routing, or next-steps email.

This is not the only trigger you can use. Close webhooks can subscribe to events across Leads, Contacts, Opportunities, Activities, and other objects. But start with one narrowly defined business event. A new Lead is less ambiguous than a broad lead.updated subscription, which can fire for many normal CRM changes.

Why use a webhook relay instead of calling Volanea from Close

Close webhooks are outbound event notifications, not a programmable HTTP step inside a Close Workflow. The webhook subscription lets Close POST event data to a URL you provide. It does not give you a safe place to place a Volanea secret key, compose conditional JSON bodies, choose an idempotency key, or interpret an email API response.

That is why the relay is essential. It can be a small Node.js service, an API route in your application, a serverless function, or a Worker. Its responsibilities are clear:

  • Verify that the request is a legitimate Close webhook.
  • Deduplicate Close event deliveries.
  • Reject events that do not meet your actual send criteria.
  • Select the right Contact and email address.
  • Escape data inserted into HTML.
  • Call Volanea using a server-side secret.
  • Return a fast success response to Close after safe handling.

The relay also prevents a dangerous design mistake: placing a Volanea API key in browser JavaScript, a public form configuration, or a URL that gets copied into a client-side automation tool. A secret key can send mail on behalf of your domain. Treat it as production infrastructure credentials, not as a field mapping value.

Prerequisites before you send the first message

Set up the underlying email system before creating the webhook. The webhook is only the trigger; it does not replace sender authentication, recipient policy, or operational logging.

You need:

  • A Close organization with API access and permission to create a webhook subscription.
  • A public HTTPS endpoint that can receive POST requests.
  • A Volanea project and secret API key.
  • A verified sending domain in Volanea.
  • A sender address on that verified domain, such as notifications@example.com.
  • A persistence layer for processed Close event IDs. A database table, Redis key, durable object, or queue consumer is sufficient.
  • A defined rule for who is eligible to receive the message.

For the Volanea-specific endpoint schema, sender setup, templates, and response handling, use the email API reference and setup guides. Do not deploy a production flow until the sender domain is verified and the exact From address is approved for the project.

Choose a message with a clear transactional purpose

A CRM trigger is not automatically permission to send any kind of email. A new Lead could represent an inbound form completion, a manually entered sales prospect, an imported list, or a record created by another integration. Those cases do not have the same expectations.

A good first message is one tightly connected to the event: an acknowledgment that a person requested information, a requested document delivery, a confirmation that a demo request was received, or internal notification to an account owner. Keep promotional campaigns out of a trigger that fires on ordinary CRM record creation unless your consent model and sending policy explicitly support it.

Add a custom field when the event alone is too broad

If every new Close Lead should not receive email, add a specific custom field such as Send onboarding email, Form source, or Transactional message type. Your relay can then require that value before it sends.

This protects against unexpected sends caused by imports, manual data entry, test records, data migrations, and integrations that create Leads in bulk. It also gives operations a visible, auditable control in Close instead of hiding business policy solely in code.

Create the Close webhook subscription

Close supports webhook subscriptions that match an object type and action. For this integration, subscribe to the lead object with the created action. The subscription points to your relay’s HTTPS URL.

Use a Close API key only from an administrator-controlled environment such as a terminal, deployment secret store, or internal provisioning script. Close API keys are authorized with HTTP Basic authentication using the key as the username and an empty password.

curl -X POST https://api.close.com/api/v1/webhook/ \
  -H "Content-Type: application/json" \
  -u "$CLOSE_API_KEY:" \
  -d '{
    "url": "https://email-relay.example.com/webhooks/close",
    "verify_ssl": true,
    "events": [
      {
        "object_type": "lead",
        "action": "created"
      }
    ]
  }'

The response includes a webhook subscription ID and a signature_key. Store the signature key as a secret on the relay, alongside—not inside—your Volanea key. The Close signature key is used to verify that a POST reaching your endpoint belongs to that particular Close webhook subscription.

Keep verify_ssl enabled. A webhook carrying names, email addresses, company details, and CRM metadata should not travel to an endpoint with an invalid TLS certificate.

The Close event shape you will receive

Close wraps webhook data in an object with an event property. The event includes metadata such as an event ID, object type, action, creation time, organization ID, and the object data relevant to the event.

For a Lead-created flow, the important paths are generally:

  • event.id: the immutable event ID used for deduplication.
  • event.object_type: expected to be lead.
  • event.action: expected to be created.
  • event.data.id: the Close Lead ID.
  • event.data.name: the Lead or company name.
  • event.data.contacts: Contacts associated with the Lead.
  • event.data.contacts[].name: a Contact name.
  • event.data.contacts[].emails[].email: a Contact email address.
  • event.data.custom.<field id>: values from populated Close custom fields.

A representative payload looks like this:

{
  "event": {
    "id": "ev_abc123",
    "object_type": "lead",
    "action": "created",
    "date_created": "2026-09-20T14:15:16.000000+00:00",
    "organization_id": "orga_abc123",
    "object_id": "lead_abc123",
    "data": {
      "id": "lead_abc123",
      "name": "Northwind Traders",
      "contacts": [
        {
          "id": "cont_abc123",
          "name": "Avery Smith",
          "emails": [
            {
              "email": "avery@example.com",
              "type": "office",
              "is_unsubscribed": false
            }
          ]
        }
      ]
    }
  },
  "subscription_id": "whsub_abc123"
}

Do not assume every Lead has a Contact, every Contact has an email address, or the first listed email is suitable for your message. Your code must handle missing arrays, blank values, malformed addresses, and contacts marked unsubscribed in Close.

Map a Close Lead event to a Volanea send request

The following Node.js example is a focused relay handler. It uses the Close webhook event ID as the Volanea Idempotency-Key, so a Close retry of the same event maps to the same logical send rather than generating a duplicate email.

The code intentionally makes the mapping explicit:

  • Close Contact email → Volanea to
  • Verified sender address → Volanea from
  • Close Contact name and Lead name → subject and HTML/text content
  • Close event ID → Volanea Idempotency-Key
import express from "express";

const app = express();
app.use(express.json({ type: "application/json" }));

const VOLANEA_API_KEY = process.env.VOLANEA_API_KEY;
const FROM_EMAIL = "notifications@example.com";

function escapeHtml(value = "") {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

app.post("/webhooks/close", async (req, res) => {
  const { event } = req.body ?? {};

  // Accept only the event this endpoint was created to process.
  if (event?.object_type !== "lead" || event?.action !== "created") {
    return res.sendStatus(204);
  }

  // Persist event.id first in a database/queue in production.
  // If it already exists, return 2xx without sending again.
  if (!event.id) return res.status(400).json({ error: "Missing Close event ID" });

  const lead = event.data ?? {};
  const contact = (lead.contacts ?? []).find((candidate) =>
    (candidate.emails ?? []).some((item) => item.email && !item.is_unsubscribed)
  );
  const emailEntry = contact?.emails?.find(
    (item) => item.email && !item.is_unsubscribed
  );

  if (!emailEntry?.email) {
    // No eligible recipient is not a failed email send.
    return res.sendStatus(204);
  }

  const contactName = contact.name || "there";
  const leadName = lead.name || "your company";
  const subject = `Thanks for contacting ${leadName}`;

  const volaneaResponse = await fetch("https://api.volanea.com/v1/send", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${VOLANEA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `close-event-${event.id}`
    },
    body: JSON.stringify({
      from: FROM_EMAIL,
      to: [emailEntry.email],
      subject,
      html: `<p>Hi ${escapeHtml(contactName)},</p>
             <p>Thanks for contacting ${escapeHtml(leadName)}.</p>
             <p>We received your request and will be in touch shortly.</p>`,
      text: `Hi ${contactName},\n\nThanks for contacting ${leadName}. We received your request and will be in touch shortly.`
    })
  });

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

  return res.sendStatus(204);
});

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

This is the core request that turns the Close event into an email. Before production deployment, add Close webhook signature validation against the raw request body, durable event storage, structured logs, and a queue if your send logic can take more than a few seconds.

Where the Volanea API key belongs

The Volanea API key does not live on the Close side of this integration. Close’s webhook subscription stores the destination URL, event selection, SSL behavior, and its own subscription signing material. It should not contain your Volanea secret.

Store VOLANEA_API_KEY in the environment or secret manager of the relay runtime. Examples include a server-side environment variable, Cloudflare Worker secret, AWS Secrets Manager entry, platform secret store, or container-orchestration secret. The key must never be embedded in:

  • A Close custom field.
  • A Close note, Workflow text field, or template.
  • Browser JavaScript.
  • A public Git repository.
  • A query string.
  • An email template.
  • A client-visible configuration file.

If the relay is an application route, ensure it runs only on the server. A frontend build process can accidentally expose environment variables that have a public prefix or are bundled into JavaScript. Use the platform’s documented server-secret mechanism, then rotate the Volanea key if it is ever logged, committed, pasted into a ticket, or exposed to an untrusted party.

Separate Close credentials from Volanea credentials

The Close API key and the Volanea API key serve different purposes. Close credentials create and manage the webhook subscription or retrieve additional CRM data. Volanea credentials authorize email sending. Do not reuse either secret as a shared webhook password.

For a production service, use separate secrets for development, staging, and production. That prevents a test webhook from sending through your production domain and makes key rotation less disruptive.

Make recipient selection deliberate

The easy implementation selects the first Contact email in the Lead. The reliable implementation defines a recipient policy.

For example, you might send only when all of these conditions are true:

  1. The Lead was created through a specific Close Form or approved integration.
  2. A Contact has an email address.
  3. The email is not marked unsubscribed in Close.
  4. The Lead has a custom field such as custom.cf_TRANSACTIONAL_TYPE set to demo_request_received.
  5. The Contact address passes your validation policy.
  6. The event has not already been processed.

This is especially important because a Close Lead can represent an organization with multiple Contacts. Sending to every address automatically may surprise recipients and create duplicate messages within the same company. If the event should notify one person, choose a named primary-contact rule or create a dedicated recipient field.

For addresses collected outside your normal lead form, use the free email address verification tool before adding uncertain contacts to important sending workflows. Verification is not a substitute for consent, but it can catch obvious formatting and domain problems before they become bounces.

When this breaks

A webhook-to-email hop is dependable only when it is designed for normal distributed-systems failures. The most important failures are not dramatic outages; they are duplicate deliveries, timing gaps, changing payloads, and data that is incomplete in some records.

Close retries can cause duplicate sends

Close retries failed webhook deliveries with exponential backoff, up to a 20-minute interval, and can continue retrying for up to 72 hours. A retry can occur because your endpoint truly failed, because it timed out, or because Close did not receive your successful response in time.

Never use a newly generated UUID as the Volanea idempotency key for this event. That would make every retry appear to be a new request. Instead, base the key on event.id, as in close-event-${event.id}.

Also store the Close event ID before triggering the downstream send. A durable processed_close_events table with a unique constraint on event_id is stronger than in-memory deduplication. It continues to work after deployments, restarts, and horizontal scaling.

Webhook timeouts can produce an ambiguous outcome

Imagine that your relay sends the Volanea request, Volanea accepts it, and then your service crashes before responding to Close. Close will retry because it did not receive a successful acknowledgment. Without the same idempotency key, the recipient gets two emails.

The correct design is to persist or enqueue the Close event quickly, return a 2xx response promptly, and let a worker perform the email send. If you use a synchronous handler for a low-volume integration, preserve the event ID and use the same Volanea idempotency key on every retry path.

Payload fields may be missing on real records

A sample Lead may contain a name, contact, and email; production data often does not. A Lead can have no Contacts. A Contact can have no email addresses. contacts can be empty. A custom field may be absent because it was not populated. Imported records may have a different completeness level than Close Form submissions.

Treat missing recipient data as an expected no-send state, not as an exception that keeps Close retrying for days. Log the skip reason with the event ID and Lead ID, then decide whether an operations workflow should fill in missing data.

Event ordering is not guaranteed

Close does not guarantee webhook event ordering. Do not assume that a Contact update will arrive before a Lead-created webhook, even if that order seems intuitive in your test. A Lead-created event may arrive before a downstream system has finished enriching it, or a later event may arrive first because of parallel delivery and retries.

If the email depends on data that may not exist at creation time, subscribe to the specific later event or add a controlled delay and fetch the current Close record from the API before sending. Avoid broad update subscriptions unless you can precisely filter and deduplicate them.

A 2xx response is not proof of inbox placement

A successful Volanea API response means the send request was accepted; it does not mean the recipient saw it in the inbox. A message can later bounce, be deferred by a receiving server, be suppressed, or land in spam.

Operational monitoring should distinguish four states: Close webhook received, event accepted by your relay, Volanea send accepted, and downstream delivery outcome. That separation makes troubleshooting much faster than treating every missing reply as a webhook issue.

Test the integration before enabling it for live leads

Use a test sender and a controlled Close Lead first. Do not point a brand-new webhook at production leads and hope the conditions are correct.

Run this checklist:

  1. Create a test Lead with one Contact and a controlled inbox address.
  2. Confirm the relay receives event.object_type = lead and event.action = created.
  3. Confirm the handler chooses the intended email address.
  4. Confirm the generated subject and body contain the expected names.
  5. Check that the Volanea request uses your verified From address.
  6. Repeat delivery of the exact Close event and confirm only one email is created.
  7. Test a Lead with no Contact email and confirm the endpoint returns a safe no-send result.
  8. Test an unsubscribed Contact and confirm the relay does not send.
  9. Temporarily make Volanea return an error and confirm your retry and alerting policy behaves as intended.
  10. Review delivery logs and the received email in more than one mailbox provider.

Use realistic edge cases: contacts with a blank name, organizations with punctuation in names, multiple Contacts, multiple email entries, HTML-sensitive characters, and Leads created by imports. A test containing only Jane Doe <jane@example.com> will not reveal most production defects.

Extend the pattern to other Close events

Once Lead-created email is reliable, the same architecture can support other well-defined triggers.

Opportunity won

Close exposes Opportunity update events and includes status details in webhook payloads. An Opportunity transition to won can trigger a customer handoff email, internal implementation alert, or receipt of next steps. Because an Opportunity event may identify a Contact by ID rather than include every email field you need, the relay may need to retrieve the current Contact or Lead record through the Close API before sending.

Use an event filter or explicit status check. Do not email on every Opportunity update, because confidence changes, notes, values, and ordinary pipeline edits can also update an Opportunity.

Close Form submission

Close now has Form Submission activities, including webhook event types for form submissions. This is often a more precise trigger for an acknowledgement email than Lead-created because it represents a person actually submitting a Close Form.

The same rule applies: inspect the actual event payload in your environment, define the recipient source, and use the Close event ID as the deduplication anchor. Do not assume a form response uses the same field names as a Lead or Contact object.

Internal alerts

The recipient does not have to be the new Contact. You can send an internal notification to an account owner, onboarding inbox, or operations address when a Lead meets a condition. Keep the recipient address server-side or derive it from a carefully controlled ownership field, rather than allowing unvalidated CRM text to decide where operational messages are sent.

Operational guidance for production

The webhook receiver is part of your email infrastructure. Give it the same care as a payment callback or identity event receiver.

Use structured logs with the Close event ID, Close subscription ID, Lead ID, Contact ID, recipient domain, Volanea response status, and resulting message identifier when available. Avoid logging full email bodies or API keys. These details let you answer practical questions: Did Close send the event? Did the relay reject it? Did the recipient have an eligible address? Did Volanea accept the request?

Set alerts for repeated 5xx responses, Close webhook subscription pauses, an unexpected rise in skipped events, Volanea authentication errors, and duplicate-event conflicts. A sudden spike in Lead-created events could be a valid import—or a broken integration—and it deserves review before it sends a large number of messages.

Keep copy templates versioned. The code example uses inline content to show the field mapping clearly, but mature deployments commonly move message copy into a template layer. Whether you use inline HTML or stored templates, retain a text alternative, escape untrusted values, and keep operational emails concise and recognizable.

Conclusion

To send email from Close with Volanea, use Close’s outbound webhook system as the event source and a server-side relay as the secure decision point. In this guide, a Lead created event becomes a transactional email by mapping event.data.contacts[].emails[].email to the Volanea recipient, using a verified sender address, and carrying event.id into Volanea’s Idempotency-Key header.

The important design decision is not the HTTP request itself. It is preserving a trustworthy boundary: Close emits data, your relay validates and deduplicates it, and Volanea sends the message with credentials that never appear in Close fields or client-visible configuration. Build that boundary carefully, and the same pattern can support form acknowledgments, pipeline notifications, customer handoffs, and many other CRM-triggered email flows.

FAQ

Does Volanea have a native Close integration?

No. This integration uses a Close webhook subscription and a server-side relay that calls the Volanea REST API. There is no Close marketplace installation or native Volanea plugin required.

What Close event should trigger the email?

Start with lead.created if a new Lead reliably represents the business event that should send an email. Use a Close Form Submission event when the email should only follow an actual form completion, or a filtered Opportunity update when the message depends on a deal reaching a specific status.

Where should I store the Volanea API key?

Store it only in the server-side secret manager or environment variables of your webhook relay. Do not put it in Close custom fields, browser code, public configuration, URLs, or templates.

How do I prevent duplicate emails when Close retries a webhook?

Persist and deduplicate event.id, then use that same event ID in Volanea’s Idempotency-Key header. A retried delivery of the same Close event should result in the same logical send, not a second message.

What happens if the Lead has no email address?

Treat it as a normal no-send condition. Return a successful response after recording why the event was skipped, rather than repeatedly failing the webhook or sending to an unverified fallback address.