Send email from Insightly without manually exporting contacts or exposing an email API key by using Insightly Workflow Automation webhooks as the trigger and Volanea as the delivery layer. The reliable architecture is not a native Insightly plugin: it is an Insightly workflow that POSTs a record payload to your server, followed by one server-side Volanea API request.
This distinction matters. Insightly can send outbound webhook notifications when a workflow event occurs, but its webhook authentication model is HTTP Basic authentication. Volanea’s sending API uses a secret API key, so a small middleware endpoint is the correct place to authenticate Insightly, validate the record, prevent duplicate sends, and call Volanea. Your CRM remains the source of the business event; your application remains the trusted environment for email credentials and delivery logic.
What this Insightly email integration does
This integration sends a transactional email when an Insightly CRM record enters a state that deserves an immediate customer message. A common example is a newly created Contact whose record meets your workflow criteria, such as a contact created from a consultation request, partner signup, customer onboarding process, or event registration.
The concrete trigger in this guide is an Insightly Workflow Automation workflow for the Contact record type, evaluated when a record is added or updated. The workflow has matching criteria that limit sends to Contacts with a valid email address and a deliberate business-state field, such as a custom checkbox named SEND_WELCOME_EMAIL set to true. When the Contact matches, the workflow action is Add New Webhook. Insightly then sends an HTTP POST to the webhook URL you supply.
The flow looks like this:
- A Contact is created or updated in Insightly.
- Insightly Workflow Automation evaluates the Contact against matching criteria.
- The workflow’s webhook action sends the Contact payload to your endpoint over HTTP POST.
- Your endpoint validates Insightly’s Basic authentication credentials and checks the payload.
- Your endpoint derives a stable idempotency key from the Contact ID and the email event.
- Your endpoint calls
POST https://api.volanea.com/v1/sendwith the Volanea secret key. - Volanea accepts, queues, and delivers the transactional email through your authenticated sending domain.
The result is a clean separation of responsibilities. Insightly decides when an email-worthy CRM event has happened. Your middleware decides whether the event is valid and should be sent once. Volanea handles how the message is submitted to email infrastructure.
Why a webhook bridge is required
Volanea does not provide a native Insightly marketplace application or an installable Insightly plugin. More importantly, Insightly workflow webhooks are designed to send record information to an endpoint you control; they are not a general-purpose API client where you can freely configure a Bearer authorization header for a downstream email provider.
Insightly documents workflow webhooks as HTTP POST callbacks. You configure a URI, and Insightly sends a collection of record field IDs and values when the workflow event happens. Its webhook configuration uses Basic authentication, allowing a username and password to be passed to the receiver. That is useful for protecting your webhook endpoint, but it is not the same as safely injecting Volanea’s secret key into an outbound request.
Do not place a Volanea API key in:
- a public website form or front-end JavaScript bundle;
- an Insightly custom-field value visible to ordinary CRM users;
- a webhook URL query string;
- an Insightly workflow name, description, or other operational note;
- a source-code repository or pasted integration screenshot.
Instead, store VOLANEA_API_KEY in the secret manager or encrypted environment-variable facility of the service hosting your webhook receiver. The receiver is the only component that should read that value. This is both a security boundary and an operational advantage: you can rotate the Volanea key without editing every CRM workflow.
For the API endpoint, authentication, payload options, and current response formats, keep the implementation aligned with the Volanea email API reference and setup guides. The implementation below uses the documented POST /v1/send endpoint and Idempotency-Key support.
Choose the right Insightly workflow trigger
A webhook is only as good as the business event that causes it. “Contact added” is easy to configure, but it is often too broad for production. If every imported Contact receives a welcome email, you can create accidental sends, duplicate messages, or messages sent before data enrichment finishes.
A safer pattern is a Contact workflow that combines a lifecycle event with explicit criteria. For example:
- Record type: Contact
- When to evaluate: when the Contact is added or updated
- Criteria:
EMAIL_ADDRESSEScontains a usable primary email,SEND_WELCOME_EMAILis true, andWELCOME_EMAIL_SENTis false - Immediate action: Add New Webhook
This makes the actual trigger specific: a Contact is added or updated and matches the workflow’s configured criteria. The custom fields are not required by Insightly; they are an intentional design for controlling the business event. A sales representative or a separate automation can set SEND_WELCOME_EMAIL only after consent, qualification, or onboarding requirements are satisfied.
A note about stage-change emails
If your message is driven by a deal milestone instead, use an Opportunity workflow rather than trying to infer a stage from a Contact. Configure the workflow for the Opportunity record type, evaluate it on record update, and set criteria for the specific pipeline stage or status your organization uses. The webhook payload will then contain an Opportunity entity, and your middleware should fetch or look up the related Contact before sending.
That second design is valuable for quote-ready, closed-won, renewal, or implementation emails. It is more involved because the recipient may not live directly on the Opportunity record. For a first implementation, a Contact workflow provides a simpler and more transparent field mapping.
Avoid sending from every update
Insightly evaluates workflows when records are added or updated. A Contact can be updated for mundane reasons: an owner changes, a phone number is corrected, data enrichment adds a company name, or an import process revises a tag. Your matching criteria must therefore describe the exact moment that deserves a send.
The best practical test is to ask: “If this Contact is updated three times tomorrow, which one update should generate this exact email?” If the answer is not one clear state transition, introduce an explicit custom field or a separate workflow state before connecting the webhook.
Understand the Insightly webhook payload
Insightly’s Workflow Automation webhook sends a JSON POST body with an entity object containing the record’s field IDs paired with values. Insightly’s own webhook example uses that wrapper and field-ID naming style. For a Contact, the fields include the Contact identifier and can include contact details and subcollections such as email addresses.
A Contact webhook payload follows this shape:
{
"entity": {
"CONTACT_ID": 123456789,
"FIRST_NAME": "Avery",
"LAST_NAME": "Jordan",
"DATE_CREATED_UTC": "2026-09-21T15:42:10.000Z",
"DATE_UPDATED_UTC": "2026-09-21T15:42:10.000Z",
"EMAIL_ADDRESSES": [
{
"EMAIL_ADDRESS": "avery.jordan@example.com",
"TYPE": "WORK",
"IS_PRIMARY": true
}
],
"CUSTOMFIELDS": [
{
"FIELD_NAME": "SEND_WELCOME_EMAIL",
"FIELD_VALUE": "true"
}
]
}
}
Treat the example as the data contract your receiver expects, not as permission to assume every Contact will have every value. Field availability varies with the record type, account configuration, enabled features, custom fields, and whether the Contact has completed all data-entry steps. In particular, a Contact can have no usable email address or more than one address.
Before production, point the Insightly webhook at a temporary request-inspection endpoint and create a test Contact in your own account. Compare the received JSON with the fields your handler extracts. Then update the mapping to match your actual primary-address and custom-field conventions.
Field mapping for this guide
The middleware maps Insightly fields to Volanea email fields as follows:
| Insightly webhook field | Volanea send field | Purpose |
|---|---|---|
entity.CONTACT_ID | Idempotency-Key input | Makes one logical Contact event map to one email send. |
entity.FIRST_NAME | HTML and text body | Personalizes the greeting. |
entity.LAST_NAME | Logging context | Helps trace an event without using email as the only identifier. |
entity.EMAIL_ADDRESSES[] | to | Supplies the recipient’s primary email address. |
entity.CUSTOMFIELDS | Validation input | Ensures the workflow intent is present if your process requires it. |
| server environment variable | from | Uses a verified sender identity, not CRM-supplied input. |
| server environment variable | Authorization header | Keeps the Volanea API key out of Insightly and the browser. |
Do not let a CRM Contact field choose the from address without an allowlist. A malformed or unapproved sender can damage deliverability, cause API rejection, or make message provenance harder to audit.
Build the secure webhook receiver
The following Node.js example uses Express. It accepts Insightly’s Basic authentication, extracts the primary Contact email, builds a transactional email, and sends it through Volanea. It also returns quickly after the Volanea request so Insightly receives a clear acknowledgment.
Set these server-side secrets before deploying:
VOLANEA_API_KEY=sk_live_replace_me
VOLANEA_FROM="Northstar Team <hello@updates.example.com>"
INSIGHTLY_WEBHOOK_USER=insightly-webhook
INSIGHTLY_WEBHOOK_PASSWORD=use-a-long-random-secret
Install Express and run the handler only behind HTTPS:
npm install express
node server.js
import express from "express";
import crypto from "node:crypto";
const app = express();
app.use(express.json({ limit: "256kb" }));
const {
VOLANEA_API_KEY,
VOLANEA_FROM,
INSIGHTLY_WEBHOOK_USER,
INSIGHTLY_WEBHOOK_PASSWORD
} = process.env;
if (!VOLANEA_API_KEY || !VOLANEA_FROM || !INSIGHTLY_WEBHOOK_USER || !INSIGHTLY_WEBHOOK_PASSWORD) {
throw new Error("Missing required server-side environment variables");
}
function basicAuthIsValid(header) {
if (!header?.startsWith("Basic ")) return false;
const decoded = Buffer.from(header.slice(6), "base64").toString("utf8");
const [username, password] = decoded.split(":");
const supplied = Buffer.from(`${username}:${password}`);
const expected = Buffer.from(`${INSIGHTLY_WEBHOOK_USER}:${INSIGHTLY_WEBHOOK_PASSWORD}`);
return supplied.length === expected.length && crypto.timingSafeEqual(supplied, expected);
}
function getPrimaryEmail(contact) {
const addresses = Array.isArray(contact.EMAIL_ADDRESSES)
? contact.EMAIL_ADDRESSES
: [];
const primary = addresses.find((address) => address.IS_PRIMARY === true);
const candidate = primary ?? addresses[0];
const email = candidate?.EMAIL_ADDRESS?.trim().toLowerCase();
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
return null;
}
return email;
}
function escapeHtml(value = "") {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
app.post("/webhooks/insightly/contact-welcome", async (req, res) => {
if (!basicAuthIsValid(req.get("authorization"))) {
return res.status(401).json({ error: "Unauthorized" });
}
const contact = req.body?.entity;
const contactId = contact?.CONTACT_ID;
const recipient = getPrimaryEmail(contact);
if (!contactId || !recipient) {
// Return 2xx after recording this internally, so malformed records do not retry forever.
console.error("Insightly Contact webhook missing CONTACT_ID or recipient", {
contactId,
hasRecipient: Boolean(recipient)
});
return res.status(202).json({ accepted: false, reason: "Missing contact ID or valid email" });
}
const firstName = contact.FIRST_NAME?.trim() || "there";
const safeFirstName = escapeHtml(firstName);
// Keep this stable for the same logical event. Do not generate a new random value on retries.
const idempotencyKey = `insightly-contact-${contactId}-welcome-v1`;
const volaneaResponse = await fetch("https://api.volanea.com/v1/send", {
method: "POST",
headers: {
"Authorization": `Bearer ${VOLANEA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey
},
body: JSON.stringify({
from: VOLANEA_FROM,
to: [recipient],
subject: "Welcome to Northstar",
html: `<p>Hi ${safeFirstName},</p><p>Thanks for getting in touch. We received your request and will follow up shortly.</p>`,
text: `Hi ${firstName},\n\nThanks for getting in touch. We received your request and will follow up shortly.`
})
});
const result = await volaneaResponse.json().catch(() => ({}));
if (!volaneaResponse.ok) {
console.error("Volanea send failed", {
contactId,
status: volaneaResponse.status,
result
});
// A non-2xx response tells Insightly the delivery did not complete successfully.
return res.status(502).json({ error: "Volanea send failed" });
}
console.info("Volanea email accepted", {
contactId,
recipient,
idempotencyKey,
result
});
return res.status(200).json({ accepted: true });
});
app.listen(3000, () => {
console.log("Listening for Insightly webhooks on port 3000");
});
This is deliberately a server-side call. The Authorization: Bearer header is created only after Insightly’s webhook reaches your protected endpoint. Neither Insightly users nor recipients receive the Volanea key as part of the record payload, email body, browser configuration, or client-side code.
Configure the Insightly workflow
In Insightly, create the workflow in Workflow Automation for the Contact record type. The exact screen arrangement can vary by account and plan, but the configuration concepts are consistent: define the record type, choose when matching criteria are evaluated, add criteria, and add a webhook action.
Use a purpose-built workflow name, such as Contact — Send welcome email via webhook. A clear name is more useful than a generic label because workflows become operational dependencies. Someone troubleshooting a missed or duplicate email should be able to identify the workflow without opening every automation.
Recommended workflow configuration
Configure the workflow with these choices:
- Select Contact as the record type.
- Set the evaluation behavior so the workflow is considered when the Contact is added or updated.
- Add criteria that require a valid email and your intentional send flag, such as
SEND_WELCOME_EMAIL = true. - Add another condition if needed to prevent sending to imported, unsubscribed, test, or internal Contacts.
- Under the workflow action, select Add New Webhook.
- Give the webhook a descriptive name, such as
Volanea welcome-email receiver. - Set the endpoint URI to
https://your-domain.example/webhooks/insightly/contact-welcome. - Configure Basic authentication using
INSIGHTLY_WEBHOOK_USERandINSIGHTLY_WEBHOOK_PASSWORDvalues that match your server environment. - Save and activate the workflow.
Do not use the Volanea API key as the Basic-auth username or password. Those credentials authenticate Insightly to your receiver only. The receiver has a different credential set for Volanea, held in its server-side secrets.
Test with a controlled Contact
Create a test Contact using an inbox your team controls. Add a unique name and set the field that makes the Contact match the workflow. Then inspect three locations:
- the webhook receiver logs, confirming the raw event arrived and a Contact ID was extracted;
- the Volanea send log, confirming the API accepted a single message;
- the recipient inbox, confirming the sender, subject, personalization, and reply behavior are correct.
If you need to validate an address before triggering a nonessential transactional message, use an address-quality check in your middleware or a separate process. Volanea also provides a free email address verification tool for one-off checks during testing and data cleanup.
Authenticate the sending domain before production
A successful API response is not the same as good inbox placement. Before turning on customer-facing sends, configure and verify the sending domain that appears in VOLANEA_FROM. Use a sender address owned by your organization, such as hello@updates.example.com, rather than a personal mailbox or a Contact-provided value.
Domain authentication establishes that Volanea is authorized to send for the domain. It also gives you a stable identity for message streams, tracking, reply routing, and future reputation management. Keep transactional mail isolated from promotional programs where possible, particularly if messages have different consent and engagement expectations.
The from field should be configured by the server, not sourced from Insightly. The CRM may help supply a reply-to context or record owner data, but sender identity needs centralized governance. If you later add per-brand sending, use a server-side allowlist mapping a safe Insightly field value to one of your verified sender identities.
Prevent duplicates with idempotency and state
Webhooks are delivery notifications, not an exactly-once business workflow. Insightly retries a webhook when it does not receive a positive acknowledgment; its documentation says it will try two more times and then stop. A timeout can produce the most dangerous ambiguity: your middleware might send the email successfully, but Insightly may not receive the response and retry the same event.
That is why the example sends a deterministic Idempotency-Key:
insightly-contact-{CONTACT_ID}-welcome-v1
If Insightly retries the same Contact welcome event, the middleware sends the same key again. Volanea can recognize the repeated logical request and avoid creating an additional send. Do not generate a fresh UUID for each webhook attempt; doing so defeats idempotency because every retry looks like a new message.
Choose an idempotency scope that matches the email
A key based only on CONTACT_ID is appropriate for a one-time welcome email. It is not appropriate for a recurring message, such as an annual renewal reminder. In that case, include the distinct business event in the key:
insightly-contact-123456789-renewal-2026-09-21
For an Opportunity-stage email, a useful scope might contain the Opportunity ID, the stage identifier, and a template version. This protects against retries while still allowing a legitimate later send after a real new stage transition.
For high-value workflows, add your own durable database table with a unique constraint on an event key. Record the Insightly record ID, event type, recipient, Volanea response, and timestamps. Idempotency at the provider layer protects the API call; durable application state protects your overall business process, supports audits, and makes recovery easier.
When this breaks
Every integration needs a failure model. The key is to distinguish an event that should be retried from an event that is structurally invalid or no longer eligible to receive email.
Insightly retries cause duplicate-send risk
Insightly retries webhook deliveries when it does not receive a positive acknowledgment. If your receiver calls Volanea, Volanea accepts the email, and then your process crashes before returning 200, Insightly may send the webhook again. Without a stable idempotency key, that can create duplicate messages.
Use the same key for every retry of the same logical event. Also log the Contact ID, event type, idempotency key, Volanea status, and provider message reference returned by the API. If your handler uses a queue, acknowledge Insightly only after the job is durably stored, then let the worker call Volanea with the same event key.
Webhook timeouts create ambiguous outcomes
A receiver that performs long database work, external enrichment, or slow template rendering before responding can time out. Insightly sees an unsuccessful callback even if part of the work completed. Keep the synchronous path short: authenticate, validate the body, persist the event or execute the small send request, and return a clear 2xx response.
For larger workloads, accept the event into a durable queue first. Respond to Insightly after successful persistence, not after every downstream system has finished. The queue worker can retry Volanea failures with the same idempotency key and without making Insightly wait.
Payload fields are missing or inconsistent
A Contact may not have EMAIL_ADDRESSES, may have multiple addresses, or may have no IS_PRIMARY value. Custom fields can also differ across Insightly account configurations. Never assume a field exists because a test Contact contained it.
The handler should reject or quarantine records that have no valid recipient rather than falling back to an arbitrary field. Return a controlled 2xx response for permanently invalid CRM data if you do not want Insightly retries, but alert an owner or create a follow-up task through a separate process. Return a non-2xx response only when the failure is transient and retrying could plausibly work.
A workflow fires on an update you did not intend
This usually means the workflow criteria describe a current record state rather than a one-time transition. If SEND_WELCOME_EMAIL = true remains true, later updates can keep matching the workflow. Idempotency protects against duplicate API sends for the same key, but it does not replace clear workflow design.
Use a separate sent-state field, a timestamp, or a downstream update that marks the Contact as processed after the email succeeds. Be careful with that last option: writing back to Insightly can itself trigger another workflow evaluation. Exclude WELCOME_EMAIL_SENT = true records from the original workflow so the loop terminates.
Basic authentication fails
A 401 from your receiver usually means the username or password configured in Insightly does not exactly match the server secret, the Base64 Authorization header was not parsed correctly, or a proxy removed the header. Check that the endpoint is HTTPS and that the reverse proxy forwards Authorization headers.
Use a unique webhook credential rather than reusing an employee login, an Insightly API key, or your Volanea key. Rotate it like any other integration secret. If you have multiple Insightly workflows, use separate credentials or endpoint paths when separate audit trails are valuable.
Volanea rejects the send
A Volanea API error can result from an invalid recipient, an unverified sender domain, an incorrect API key, malformed content, or a policy and suppression decision. Log the HTTP status and safe error metadata, but do not put the Volanea key or full personal data into centralized error traces.
Distinguish between errors that deserve retrying and errors that require data correction. Authentication and malformed-request errors should page the integration owner. A bad recipient address should be routed to CRM data cleanup. A temporary network or server error can be retried with the same idempotency key.
Production improvements for a durable integration
The basic Express example is intentionally direct. For production workflows that affect revenue, onboarding, or regulated communications, add infrastructure around it.
A mature implementation usually includes:
- A durable event store keyed by Insightly record ID and email event type.
- A queue for asynchronous processing and controlled retries.
- Structured logging with correlation IDs, but redacted message content and secrets.
- Alerting for sustained webhook authentication failures, Volanea 4xx errors, and queue backlogs.
- A template strategy so content changes do not require editing workflow code.
- Recipient-policy checks for consent, suppression, internal-test addresses, and account status.
- An audit record containing the CRM source, event time, recipient, template version, and Volanea response metadata.
A queue is especially useful when many Contacts are imported or a batch update triggers many qualifying records. It prevents burst traffic from tying up webhook requests and lets you control concurrency. It also gives operations teams a clear place to inspect failed jobs without asking Insightly to replay old events manually.
Alternatives when a server endpoint is not available
The direct webhook-to-middleware architecture is the preferred route when you can deploy a small service, serverless function, or worker. It gives you control over secrets, validation, idempotency, and logging.
If you cannot operate a webhook receiver, Insightly also supports integration approaches through Zapier and AppConnect. In that model, use an Insightly trigger such as New Record or Updated Record, add filtering so only intentional Contact events continue, and then use an HTTP request action to call Volanea’s send endpoint. Store the Volanea API key in the automation platform’s encrypted connection or secret facility, never in a mapped Contact field.
That route is useful for low-volume operational messages, but review its retry behavior and duplicate controls carefully. Ensure the automation platform can set the Idempotency-Key header deterministically. If it cannot, use a server-side endpoint even if the platform is still used as the event router.
A practical launch checklist
Before activating the workflow for real Contacts, verify each layer in order:
- The Volanea sending domain is authenticated and the configured sender is approved.
VOLANEA_API_KEYexists only in a server-side secret store.- The webhook endpoint is HTTPS, publicly reachable, and protected with unique Basic-auth credentials.
- A test Insightly Contact produces the expected
entitypayload. - The receiver selects the correct primary address and safely handles Contacts without one.
- The email event has a stable, deterministic idempotency key.
- A simulated retry produces one accepted logical send, not two emails.
- The workflow criteria exclude internal testing, opted-out records, and unintended imports.
- Logs can connect the Insightly Contact ID to the Volanea response without exposing secrets.
- Someone owns alerting and remediation when a webhook, queue job, or email send fails.
Conclusion
To send email from Insightly with Volanea, use Insightly Workflow Automation as the event source and a secure webhook receiver as the bridge. A Contact added or updated event can trigger Insightly’s webhook action, but your server should own the Volanea API key, validate the CRM payload, and apply idempotency before it sends.
That architecture avoids pretending there is a native Insightly app, keeps credentials out of client-visible configuration, and handles the real operational behavior of webhooks: retries, timeouts, incomplete records, and changes to workflow criteria. Start with one narrowly defined Contact email, test the payload from your own Insightly account, and expand only after duplicate protection and monitoring are in place.
FAQ
Does Volanea have a native Insightly integration?
No. This setup uses Insightly Workflow Automation webhooks and a server-side middleware endpoint that calls the Volanea REST API. There is no marketplace-install flow required or assumed.
What Insightly event starts the email send?
In this guide, the event is a Contact record being added or updated and then matching the workflow’s configured criteria. The workflow action is an Insightly webhook that POSTs the Contact entity payload to your receiver.
Can I put the Volanea API key directly in an Insightly webhook?
No. Insightly webhooks use Basic authentication to authenticate to your endpoint, while the Volanea key should stay in a server-side secret store. The middleware endpoint reads the Volanea key and creates the authenticated API request.
How do I stop duplicate emails when Insightly retries a webhook?
Send a deterministic Idempotency-Key with the Volanea request. For a one-time welcome email, derive it from the Insightly CONTACT_ID and the event name, then reuse exactly the same key for every retry.
What should happen when an Insightly Contact has no email address?
Do not send. Validate the Contact payload, record the failure for CRM cleanup, and avoid selecting an arbitrary field as a fallback recipient. Whether you return 2xx or a retryable error depends on whether the data problem is permanent or likely to resolve on retry.