A Help Scout email integration with Volanea is possible without a marketplace app: use Help Scout’s conversation webhooks to notify a server-side endpoint, retrieve the conversation through the Help Scout API, and send the resulting transactional message through Volanea. This approach keeps email credentials private and gives your application control over exactly which support events create outbound mail.
There is an important boundary to understand first. Volanea does not provide a native Help Scout app, marketplace listing, or one-click plugin. Help Scout webhooks also cannot reshape their payload into Volanea’s email API format or safely hold your Volanea API key. The practical integration is therefore a small middleware service—often a serverless function—that sits between the two products.
That extra hop is useful rather than incidental. It lets you filter events, look up the complete conversation, suppress duplicate sends, choose a verified sender, record an audit trail, and prevent a support workflow from accidentally becoming an email loop.
What this integration does—and does not do
This pattern sends a new email because something happened in Help Scout. A common example is a customer opening a new support conversation: Help Scout emits a conversation.created webhook, your endpoint retrieves the conversation, and Volanea sends an acknowledgement or next-step message.
It is not a way to replace Help Scout’s normal reply composer. When an agent replies inside Help Scout, Help Scout remains responsible for that support-thread email. Volanea is better suited to separate, application-controlled messages such as:
- a support-case receipt with a ticket number and expected response window;
- a follow-up after a conversation enters a particular business process outside Help Scout;
- an escalation notice to an operations mailbox;
- a product or account message whose audience is identified from a Help Scout conversation;
- a post-resolution sequence initiated by your own system after checking conversation state.
The distinction matters for customer experience. If you send a Volanea acknowledgement every time a Help Scout conversation is created, make sure Help Scout itself is not already sending an automatic acknowledgement for the same mailbox. Two nearly identical confirmations are confusing, and they can make the customer reply twice.
The concrete Help Scout trigger
The trigger used in this guide is Help Scout’s conversation.created webhook event. In Help Scout’s API model, a conversation is the support record that contains the customer, subject, threads, status, mailbox, and related details. A newly created conversation can originate from an email, a supported contact channel, or another Help Scout intake route.
Register the webhook against the mailbox and events that fit your workflow. Help Scout documents webhook registration in its Mailbox API; the registration points Help Scout at a public HTTPS URL you operate. Do not treat the webhook registration as an email configuration screen: its only job is to notify your service that an event occurred.
For a production integration, begin with one narrow event—usually conversation.created. Add other event types only after you have defined their idempotency and customer-message rules. In particular, an event that fires for replies can be much noisier than an event that fires once for a newly created conversation.
The architecture: webhook, lookup, then email send
A reliable Help Scout email integration has three separate actions:
- Help Scout posts a webhook notification when
conversation.createdoccurs. - Your middleware retrieves the canonical conversation from Help Scout’s Mailbox API using the resource URL in that notification.
- Your middleware calls Volanea’s REST email endpoint with a mapped
from,to,subject, and HTML or text content.
The lookup step is not optional busywork. Help Scout’s webhook body is a resource notification, not a full export of every conversation field. It tells the receiver what type of resource changed and where to retrieve it. The API response is where your service gets the customer address, conversation number, subject, mailbox context, and any data it needs to build an email.
Why not post the Help Scout webhook directly to Volanea?
The two payloads have different purposes. Help Scout posts an event envelope containing a resource reference. Volanea expects an outbound email request containing recipient and content fields. More importantly, Volanea authentication belongs in a server-side Authorization header; a Help Scout webhook registration is not a secure secret store or a request-transformation engine.
A direct URL substitution would also make it hard to prevent duplicates, inspect status, choose a different sender by mailbox, or reject malformed events. Use a dedicated endpoint—even if it is only a short serverless function—rather than trying to make one vendor’s webhook resemble another vendor’s send API.
Where the middleware can run
The adapter can be an Express route, a Next.js route handler, a Cloudflare Worker, AWS Lambda, Google Cloud Function, or an automation platform’s secure code step. The runtime matters less than these operational requirements:
- it accepts public HTTPS POST requests from Help Scout;
- it can make outbound HTTPS requests to Help Scout and Volanea;
- it has private environment-variable or secret-manager storage;
- it can persist idempotency records; and
- it can emit logs and alerts without storing raw customer content unnecessarily.
If you are already deploying application APIs, add the endpoint there. If you are validating the idea, a serverless endpoint is usually the shortest route. Either way, treat it as production integration code once it can send real customer email.
The Help Scout webhook payload shape
For a conversation event, Help Scout sends an event envelope that identifies the resource. The meaningful parts for this flow are the event name, resource type, resource ID, and the self link used to retrieve the resource. The payload shape is represented like this:
{
"resourceType": "conversation",
"resource": {
"id": "123456789",
"links": {
"self": "https://api.helpscout.net/v2/conversations/123456789"
}
},
"event": "conversation.created"
}
Your endpoint should first check that event is the event it intends to process and that resourceType is conversation. It should then use the resource.links.self URL to request the full conversation with a valid Help Scout OAuth access token.
Do not assume that a webhook includes customer.email, subject, message body text, tags, or custom fields at the top level. Code that does so may appear to work in a hand-built test payload and fail in production because those are conversation-resource details, not guaranteed fields in the notification envelope.
What to read from the full conversation
After retrieving the conversation, the typical mapping for a case-receipt email is:
| Email value | Help Scout source | Reason |
|---|---|---|
| Recipient | conversation.primaryCustomer.email | The primary customer is the person associated with the conversation. |
| Subject context | conversation.subject | Gives the customer recognizable context. |
| Case number | conversation.number | A human-friendly support reference. |
| Customer name | conversation.primaryCustomer.firstName | Optional personalization; use a fallback. |
| Mailbox routing | conversation.mailboxId | Lets your code choose a sender or template per mailbox. |
A conversation can be missing values your template considers convenient. A subject can be empty, a customer may not have a usable email address for every intake channel, and custom fields can be omitted when they are not configured, not populated, unavailable to the API credentials, or unavailable in an account’s plan and feature set. Build fallbacks deliberately; never send to an undefined address or interpolate missing fields as the literal word undefined.
Configure credentials before writing the send logic
There are two credential systems in this integration, and neither should be exposed in browser code, static site configuration, or a Help Scout-visible custom field.
First, your service needs Help Scout API access. Use the OAuth approach and application credentials supported by Help Scout’s Mailbox API to obtain and refresh a server-side access token. The token is used only for the follow-up request that retrieves the conversation resource.
Second, your service needs a Volanea API key. Store that key in the middleware platform’s encrypted environment variables or secret manager—for example, as VOLANEA_API_KEY. The endpoint adds it to the outbound request at runtime.
Why the Volanea key must stay on the server
A Volanea API key authorizes email sending. If it is embedded in a frontend bundle, mobile app, browser-side integration, public Git repository, or client-visible automation configuration, anyone who obtains it may be able to send as your account. Revoking the leaked key stops legitimate traffic too, so exposure creates both a security and availability incident.
Keep the key in a server-only secret store and limit access to the deployment identity that needs it. Use separate keys for development, staging, and production when your account setup supports that separation. Rotate a key immediately if it appears in logs, issue trackers, screenshots, source history, or client code.
The Help Scout webhook URL itself is not a substitute for credential security. An opaque, high-entropy route can reduce random traffic, but it is still a URL that may be logged by infrastructure. Authenticate and validate downstream requests based on the source API retrieval, keep the route private where possible, and avoid putting the Volanea key in that URL.
For endpoint and authentication details specific to your sending account, consult the email API reference and setup guides before deployment.
Working Node.js adapter: Help Scout to Volanea
The following Express example implements the complete flow. It accepts the Help Scout event envelope, validates the resource URL, obtains a Help Scout access token using client credentials, retrieves the conversation, maps the fields, and posts an email to Volanea.
It uses these server-only environment variables:
HELPSCOUT_APP_ID=...
HELPSCOUT_APP_SECRET=...
VOLANEA_API_KEY=...
VOLANEA_FROM="Acme Support <support@notify.example.com>"
WEBHOOK_PATH_TOKEN=a-long-random-route-token
import express from "express";
const app = express();
app.use(express.json({ limit: "256kb" }));
const HELPSCOUT_TOKEN_URL = "https://api.helpscout.net/v2/oauth2/token";
const HELPSCOUT_API_ORIGIN = "https://api.helpscout.net";
const VOLANEA_EMAIL_URL = "https://api.volanea.com/v1/emails";
function escapeHtml(value = "") {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
async function getHelpScoutAccessToken() {
const basic = Buffer.from(
`${process.env.HELPSCOUT_APP_ID}:${process.env.HELPSCOUT_APP_SECRET}`
).toString("base64");
const response = await fetch(HELPSCOUT_TOKEN_URL, {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({ grant_type: "client_credentials" })
});
if (!response.ok) {
throw new Error(`Help Scout token request failed: ${response.status}`);
}
const token = await response.json();
return token.access_token;
}
function isHelpScoutConversationUrl(value) {
try {
const url = new URL(value);
return (
url.origin === HELPSCOUT_API_ORIGIN &&
/^\/v2\/conversations\/[^/]+$/.test(url.pathname)
);
} catch {
return false;
}
}
app.post("/webhooks/helpscout/:token", async (req, res) => {
// Return promptly only after the event is durably queued in a real deployment.
if (req.params.token !== process.env.WEBHOOK_PATH_TOKEN) {
return res.sendStatus(404);
}
const event = req.body;
if (
event?.event !== "conversation.created" ||
event?.resourceType !== "conversation"
) {
return res.sendStatus(204);
}
const resourceUrl = event?.resource?.links?.self;
if (!isHelpScoutConversationUrl(resourceUrl)) {
return res.status(400).json({ error: "Invalid Help Scout resource URL" });
}
try {
const accessToken = await getHelpScoutAccessToken();
const conversationResponse = await fetch(resourceUrl, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (!conversationResponse.ok) {
throw new Error(
`Help Scout conversation lookup failed: ${conversationResponse.status}`
);
}
const conversation = await conversationResponse.json();
const recipient = conversation?.primaryCustomer?.email;
const caseNumber = conversation?.number ?? event.resource.id;
const customerName = conversation?.primaryCustomer?.firstName || "there";
const originalSubject = conversation?.subject || "your support request";
if (!recipient || !recipient.includes("@")) {
console.warn("Skipping conversation without a usable customer email", {
conversationId: conversation?.id
});
return res.sendStatus(204);
}
const volaneaPayload = {
from: process.env.VOLANEA_FROM,
to: [recipient],
subject: `We received your request (#${caseNumber})`,
html: `<p>Hi ${escapeHtml(customerName)},</p>
<p>We received your request about <strong>${escapeHtml(originalSubject)}</strong>.</p>
<p>Your support reference is <strong>#${escapeHtml(caseNumber)}</strong>.</p>
<p>Our team will be in touch.</p>`,
text: `Hi ${customerName},\n\nWe received your request about "${originalSubject}".\nYour support reference is #${caseNumber}.\n\nOur team will be in touch.`
};
const sendResponse = await fetch(VOLANEA_EMAIL_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VOLANEA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(volaneaPayload)
});
if (!sendResponse.ok) {
const responseText = await sendResponse.text();
throw new Error(
`Volanea send failed: ${sendResponse.status} ${responseText}`
);
}
return res.sendStatus(202);
} catch (error) {
console.error("Help Scout to Volanea webhook failed", error);
return res.sendStatus(500);
}
});
app.listen(3000);
The mapping is explicit: conversation.primaryCustomer.email becomes Volanea’s to array; your verified support sender becomes from; conversation.number becomes the support reference; and conversation.subject becomes safe, escaped contextual content. The code intentionally creates a new transactional message rather than attempting to copy an entire Help Scout thread into an external email.
Before using the route, ensure VOLANEA_FROM uses a sender identity and domain you have configured for sending. A valid API request is not a guarantee that an arbitrary from address is authorized. Sender-domain authentication and alignment are core deliverability controls, not merely setup chores.
Make the email useful without duplicating support replies
A basic receipt is a sensible first message because it communicates a discrete fact: the customer’s request exists and has a reference number. It should not claim a response deadline unless your team can actually meet it, and it should not contain private internal notes, assignment data, or full unreviewed message content.
The following information is usually safe and useful in a receipt template:
- the customer’s first name when present;
- the Help Scout conversation number;
- a short restatement of the subject;
- a clear next step, such as “Our team will review this request”; and
- a reply path that matches your support operation.
Be conservative with message bodies. The original conversation may contain passwords, account information, attachments, order details, or customer-entered HTML. Echoing it into a fresh email expands the number of systems and inboxes where sensitive data exists. If you must include content, use plain text, apply output escaping, set a length limit, and review your privacy obligations.
Choose the reply path intentionally
A Volanea message sent from a transactional sender does not automatically become a Help Scout thread. If customers reply to it, decide where that reply should go before launch. You might use a monitored support mailbox that Help Scout imports, or use a Reply-To address designed for your support workflow if your sending configuration supports it.
Avoid forwarding replies back into the exact condition that creates another conversation.created receipt. Otherwise a customer’s reply to the acknowledgement could create a new conversation and trigger another acknowledgement. The cleanest solution is often to use an acknowledgement sender or reply path that does not generate a second intake event, plus an idempotency guard on your own endpoint.
When this breaks: failure modes in this specific hop
Webhook integrations should be designed for retries and partial failure. A support event, an API lookup, and an email submission are independent network operations; any one can succeed while another times out or returns an error.
Help Scout retries can cause duplicate sends
A sender may retry a webhook when your endpoint does not acknowledge it successfully or quickly enough. This is correct behavior for delivery reliability, but it means the same conversation.created event can reach your service more than once. If your handler sends a message every time it sees the event, a customer can receive duplicate receipts.
Use a durable idempotency record keyed by a stable value, such as helpscout:conversation.created:<conversation-id>. Create the record atomically before sending or use a transactional outbox/job record with a unique constraint. A process-local Set is acceptable for a tutorial but not for production: it disappears on restart and is not shared across multiple serverless instances.
Also consider the ambiguous case where Volanea accepts the send but your middleware times out before receiving the response. Retrying blindly can duplicate the message. Persist a send attempt state and, where your sending API and architecture support it, attach a stable internal identifier or idempotency mechanism to the outbound operation.
Webhook timeouts and slow work
Fetching an OAuth token, retrieving a conversation, rendering content, and calling an email API can take longer than a webhook sender expects. The robust pattern is to validate and durably enqueue the event quickly, return a successful response, and let a background worker perform the API calls.
If you handle the full workflow synchronously, keep it lean and instrument the latency of each request. Do not add slow CRM queries, attachment downloads, AI processing, or large template rendering to the webhook request path unless your queue design accounts for it. A timeout does not prove that no email was sent; it proves only that the caller did not receive a timely response.
Missing fields, permissions, and plan-dependent features
The webhook envelope is intentionally sparse, so missing recipient details are normal until you retrieve the conversation. Even the full conversation can lack a usable primaryCustomer.email for some channels or records. Treat a missing address as a skipped, observable outcome—not as an opportunity to send to a guessed address.
Custom fields deserve special care. Their availability and visibility can depend on account plan, mailbox configuration, the field’s presence on that conversation, and the permissions associated with the API application. If your template requires a custom field such as an account ID, check for it explicitly and route incomplete records to a review queue rather than sending a broken message.
Delivery and sender-identity failures
A 2xx response from the send endpoint means the provider accepted the request, not that a recipient has read it. Domain authentication, sender alignment, suppression rules, invalid addresses, and recipient-provider filtering all affect final delivery. Keep operational acknowledgements transactional and use a properly authenticated domain that recipients recognize.
Validate addresses before adding them to automated flows. For one-off checks and preflight testing, the free email address verification tool can help identify obviously risky or malformed recipients, but it should complement—not replace—your consent, suppression, and bounce-handling processes.
Testing the integration safely
Start in a non-production mailbox or with a test route that cannot message real customers. Test the entire chain using a real Help Scout-created conversation, because handcrafted JSON only verifies your parser; it does not verify webhook registration, resource retrieval permissions, or the actual shape of the conversation response.
Use a checklist like this:
- Create a test conversation with a known recipient and subject.
- Confirm the endpoint logs one accepted
conversation.createdevent and a stable conversation ID. - Confirm the Help Scout API lookup succeeds with the expected OAuth scope and credentials.
- Inspect the rendered
to,from,subject, and content before allowing the send. - Verify that the Volanea response is successful and that the message reaches the intended inbox.
- Replay the same event deliberately and confirm idempotency prevents a second send.
- Test an empty subject, missing first name, and missing email address.
- Test a delayed or failed Volanea request and verify that the retry path does not duplicate a completed send.
Log identifiers, not full sensitive payloads. Useful fields include Help Scout event type, conversation ID, mailbox ID, queue job ID, Volanea response status, and a generated correlation ID. Be cautious about logging email addresses, subjects, and bodies; they are customer data and can become broadly accessible through observability tools.
Alternatives: automation platforms and native Help Scout messages
A low-code automation platform can host the middle step when you do not want to deploy a server. The same architectural rules remain: receive the Help Scout event, retrieve or map the needed record data, store the Volanea key in the platform’s protected connection or secret facility, and call the Volanea API from a server-side action.
Do not assume an automation platform eliminates duplicate handling. If Help Scout retries an event, the automation may run twice. Use a data store, deduplication step, or downstream idempotency strategy keyed to the conversation ID and event type.
For a simple support acknowledgement, native Help Scout workflows or mailbox auto-replies may be a better fit when you do not need Volanea’s sending infrastructure, separate sender domain, or application-level control. Use Volanea when the message belongs to your product’s transactional email stream or must be coordinated with records and logic outside the help desk.
Operational guidance for production sends
Once the first receipt works, resist the urge to add every support event immediately. Define a message catalog: which event can send which template, to whom, from which sender, and with what frequency cap. This prevents well-intentioned automations from creating an inbox flood during migrations, bulk imports, or unusual support incidents.
Maintain an audit record containing the Help Scout conversation ID, webhook event, template version, intended recipient, Volanea message response identifier if returned, and final state. That record makes it possible to answer a common support question: “Did we send the acknowledgement for case #12345?” without searching multiple systems manually.
Finally, separate transactional acknowledgements from campaigns. A case receipt is operational mail tied to a customer action; it should not silently become a marketing message or include promotional content that changes the user’s expectations. Clear purpose, recognizable sender identity, and restrained content support both deliverability and trust.
Conclusion
A dependable Help Scout email integration with Volanea is a webhook-and-middleware workflow, not a native plugin installation. Use Help Scout’s conversation.created event as the trigger, follow the webhook resource link to retrieve the full conversation, map only the fields your message needs, and make the Volanea API call from a server-side environment where the API key remains private.
The details that make the integration production-ready are equally important: durable idempotency for webhook retries, a queue for slow or failed work, fallbacks for missing customer data, sender-domain authentication, and a reply path that cannot create a new-message loop. Build those safeguards before expanding the automation to more events.
FAQ
Does Volanea have a native Help Scout integration?
No. This workflow uses Help Scout webhooks and a custom middleware endpoint that calls Volanea’s REST API. There is no marketplace installation or native app required for the approach described here.
What Help Scout event should trigger the first email?
Use conversation.created for a one-time case receipt or acknowledgement. It is a clear support-record event and is easier to deduplicate than reply-driven events. Confirm that native Help Scout automations are not already sending the same acknowledgement.
Why does the webhook handler need to retrieve the conversation again?
Help Scout’s webhook notification identifies the changed resource through its event envelope and resource link. Retrieve that conversation through the Mailbox API to obtain fields such as the primary customer email, conversation subject, and conversation number.
Can I store the Volanea API key in Help Scout or frontend code?
No. Store it only in the server-side middleware’s encrypted environment variables or secret manager. A client-visible key can be copied and used to send unauthorized email from your account.
How do I stop duplicate messages after webhook retries?
Create a durable idempotency key such as conversation.created plus the Help Scout conversation ID, and enforce uniqueness before sending. Queue-based processing and persistent send state also help with timeout cases where the email provider may have accepted a request before your handler lost the response.