Send email from Zendesk without a marketplace app by using the outbound webhook capability Zendesk already provides. This guide shows a production-ready route: a Zendesk ticket trigger posts a controlled JSON payload to your relay, and the relay calls Volanea’s REST API with a server-side API key.

Zendesk does not need a native Volanea app for this workflow. In fact, a webhook relay is usually the better integration boundary: it gives you a place to validate ticket data, control which emails are allowed, create a stable idempotency key, and keep the Volanea credential out of a help-desk configuration that may be accessible to multiple administrators.

This walkthrough uses a concrete event: a ticket is created. When Zendesk creates a ticket that matches your conditions, its ticket trigger runs immediately after creation or update, then performs the action to notify an active webhook. The relay converts the ticket fields into a Volanea POST /v1/send request.

What this Zendesk integration does

The finished flow is deliberately simple:

  1. A customer creates a Zendesk Support ticket.
  2. A Zendesk ticket trigger checks whether that ticket should generate an email.
  3. The trigger runs the Notify by > Active webhook action and sends a JSON body built with Zendesk placeholders.
  4. Your HTTPS relay authenticates and validates the request.
  5. The relay calls Volanea’s send endpoint with the recipient, sender, subject, HTML content, and an Idempotency-Key.
  6. Volanea accepts the transactional message into its sending pipeline.

This is not the same as Zendesk’s built-in requester notification. Use this integration when the email needs to come from a domain managed in Volanea, must use a separate transactional template, needs a different recipient than the ticket requester, or has to be coordinated with application events outside Zendesk.

A useful example is an internal escalation notification. A ticket submitted through a premium-support form can create a message to a designated account owner, with ticket ID, requester details, priority, and a direct ticket URL. Another common use is sending a branded acknowledgement or next-step message from a system that centralizes transactional mail through Volanea.

Why use a Zendesk ticket trigger and webhook

Zendesk has outbound HTTP webhooks. A webhook can be connected to a trigger or automation for ticket activity, and the trigger’s webhook action lets you define a custom request body. That is the right native building block here—not a Zendesk Marketplace installation and not browser-side scripting.

The concrete trigger is a ticket trigger. Ticket triggers are business rules that run immediately after a ticket is created or updated when their conditions match. For this guide, configure the trigger to fire only when the ticket is newly created. That prevents every later comment, assignment, or status update from automatically producing another copy of the same email.

The direct-to-Volanea option versus a relay

A Zendesk webhook can send an authenticated HTTPS request to an external API. In theory, you could configure its endpoint as Volanea’s send endpoint and place Volanea authentication in the webhook configuration.

For a low-risk proof of concept, that may be acceptable. It is not the preferred production design for most teams for three reasons:

  • Zendesk trigger bodies are excellent for placeholder substitution, but they are not an application runtime for conditional validation, rich HTML construction, or audit logic.
  • A message-sending POST needs stable idempotency handling. Zendesk can retry failed webhook invocations, while a fixed header value would be unsafe across all sends.
  • A relay can authenticate Zendesk, enforce recipient allowlists, strip unsafe content, create one stable key per logical email, and return fast responses to Zendesk.

The recommended architecture is therefore Zendesk → your relay → Volanea, with the Volanea API key stored only as a secret in the relay environment. Zendesk stores a separate shared bearer token used only to authenticate to the relay.

This design also means a Zendesk administrator never needs access to the Volanea sending credential. The key is not client-visible, is not included in browser JavaScript, and is not placed in ticket text, custom fields, macros, or webhook request bodies.

Prerequisites before you build

Prepare these items before changing a production trigger:

  • A verified Volanea sending domain and a sender address such as support@example.com.
  • A Volanea secret API key with permission to send email.
  • A public HTTPS endpoint for the relay, such as a serverless function, Worker, container endpoint, or application route.
  • A randomly generated shared secret for Zendesk-to-relay authentication.
  • Zendesk administrator access, or a custom agent role that can manage webhooks and business rules.
  • A test requester email address that you control.

Volanea’s single-message endpoint is POST https://api.volanea.com/v1/send. It can send to one address or multiple addresses, up to the documented per-message recipient limit. For this ticket-trigger workflow, use one recipient per send unless the business case explicitly requires a group notification.

Before you test live tickets, verify the sender domain in Volanea. An unverified sender domain can cause the API to reject the request, and a successfully accepted API request is still not the same thing as inbox delivery. Domain authentication, valid recipient data, and suppression handling all remain part of reliable transactional email.

If you are still choosing a sending volume, sending domain count, or production plan, review transactional email pricing before wiring a high-volume trigger into every inbound ticket.

Create the secure webhook relay

The relay is intentionally small. It accepts the shaped payload from Zendesk, checks the bearer secret, validates the fields, generates a deterministic idempotency key, and invokes Volanea.

The following Node.js example uses the built-in fetch available in modern Node runtimes. Set VOLANEA_API_KEY and ZENDESK_RELAY_TOKEN as platform environment secrets, not as source-code constants.

// POST /webhooks/zendesk-ticket-created
// Environment secrets:
// VOLANEA_API_KEY=sk_live_...
// ZENDESK_RELAY_TOKEN=<long random value>

import crypto from "node:crypto";

export async function zendeskTicketCreated(request) {
  const authorization = request.headers.get("authorization");
  const expected = `Bearer ${process.env.ZENDESK_RELAY_TOKEN}`;

  if (!authorization || !crypto.timingSafeEqual(
    Buffer.from(authorization),
    Buffer.from(expected)
  )) {
    return Response.json({ error: "unauthorized" }, { status: 401 });
  }

  const payload = await request.json();

  const required = [
    "ticketId",
    "ticketUrl",
    "requesterEmail",
    "requesterName",
    "subject",
    "description"
  ];

  for (const key of required) {
    if (typeof payload[key] !== "string" || payload[key].trim() === "") {
      return Response.json(
        { error: `missing or invalid ${key}` },
        { status: 400 }
      );
    }
  }

  // Example policy: send only to the requester. Replace this with a controlled
  // internal routing rule if the email should go to an account owner or on-call team.
  const to = payload.requesterEmail.trim().toLowerCase();

  // One logical ticket-created acknowledgement must always reuse this key.
  // Do not include a timestamp, random UUID, or mutable ticket subject here.
  const idempotencyKey = `zendesk-ticket-created-${payload.ticketId}`;

  const safeText = (value) =>
    value.replace(/[&<>'"]/g, (character) => ({
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      "'": "&#39;",
      "\"": "&quot;"
    })[character]);

  const html = `
    <p>Hi ${safeText(payload.requesterName)},</p>
    <p>We received your support request.</p>
    <p><strong>Ticket #${safeText(payload.ticketId)}</strong>: ${safeText(payload.subject)}</p>
    <p><a href="${safeText(payload.ticketUrl)}">View your ticket</a></p>
    <hr>
    <p>${safeText(payload.description).replace(/\n/g, "<br>")}</p>
  `;

  const volaneaResponse = await fetch("https://api.volanea.com/v1/send", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": idempotencyKey
    },
    body: JSON.stringify({
      from: "support@example.com",
      to,
      subject: `We received your request: ${payload.subject}`,
      html,
      replyTo: "support@example.com"
    })
  });

  const responseBody = await volaneaResponse.text();

  if (!volaneaResponse.ok) {
    console.error("Volanea send failed", {
      ticketId: payload.ticketId,
      status: volaneaResponse.status,
      responseBody
    });

    // A 5xx response asks Zendesk to retry. For a definite 4xx validation error,
    // return 200 after logging/alerting so a malformed ticket does not retry forever.
    if (volaneaResponse.status >= 500) {
      return Response.json({ error: "email provider unavailable" }, { status: 503 });
    }

    return Response.json({ accepted: false }, { status: 200 });
  }

  return Response.json({ accepted: true }, { status: 200 });
}

The field mapping is explicit:

Zendesk payload fieldVolanea field or usage
ticketIdIdempotency key and visible ticket reference
ticketUrlLink in the HTML email
requesterEmailto recipient
requesterNameGreeting in html
subjectVolanea subject and message content
descriptionHTML email body

The relay should return a 2xx response only after it has made a deliberate decision: Volanea accepted the send, the event was already handled idempotently, or the payload was definitively invalid and has been logged for review. It should return a retryable 5xx response when a transient dependency problem means Zendesk should try again.

Configure the Zendesk webhook

In Zendesk Admin Center, go to Apps and integrations > Webhooks > Webhooks and create a webhook. The exact labels can vary slightly across Zendesk account experiences, but this is the current Admin Center location for webhook management.

Use these settings:

  • Name: Send ticket-created email through Volanea relay
  • Endpoint URL: https://your-app.example.com/webhooks/zendesk-ticket-created
  • Request method: POST
  • Request format: JSON
  • Authentication: Bearer token
  • Token: the same secret value stored as ZENDESK_RELAY_TOKEN in your relay environment

Do not put the Volanea API key in the ticket-trigger JSON body. A request body can be copied into trigger configurations, logs, test tools, and support documentation. It is application data, not a secret store.

Where the Volanea API key belongs

In the recommended relay architecture, the Volanea key lives nowhere on the Zendesk side. It belongs in your server or serverless platform’s encrypted environment-secret store under a name such as VOLANEA_API_KEY.

Zendesk holds only the relay bearer token in the webhook’s authentication settings. Zendesk supports API key, basic, and bearer authentication options for webhooks, and it does not show the stored credential after creation or update. That is useful protection, but it does not turn a help-desk webhook setting into a full secret-management and application-policy layer.

Keep the two credentials separate:

  • ZENDESK_RELAY_TOKEN proves that Zendesk may call your relay.
  • VOLANEA_API_KEY authorizes your relay to send mail through Volanea.

Rotate them independently. If the Zendesk secret is exposed, replace the webhook authentication token and the relay secret. If the Volanea key is exposed, revoke and replace it in Volanea without needing to modify Zendesk’s ticket data or trigger body.

Create the Zendesk ticket trigger

Next, configure the business rule that starts the email send. In Admin Center, go to Objects and rules > Business rules > Triggers and create a ticket trigger.

For an acknowledgement that should run when a ticket is first created, start with these conditions:

Meet ALL of the following conditions

  • Ticket Is Created
  • Channel Is not Email — optional, if you do not want a second acknowledgement for email-originated support tickets
  • Tags Contains none of the following volanea_ack_sent — optional extra protection if you also use a tag action

Actions

  • Notify by Active webhook → select Send ticket-created email through Volanea relay
  • Enter the JSON body below.
  • Optionally add tag volanea_ack_sent after the webhook action if your workflow uses ticket tags as an operational signal.

Zendesk renders placeholders inside the webhook action’s body. The JSON you configure is the actual payload the relay receives after Zendesk substitutes the ticket values:

{
  "event": "ticket.created",
  "ticketId": "{{ticket.id}}",
  "ticketUrl": "{{ticket.link}}",
  "requesterEmail": "{{ticket.requester.email}}",
  "requesterName": "{{ticket.requester.name}}",
  "subject": "{{ticket.title}}",
  "description": "{{ticket.description}}",
  "priority": "{{ticket.priority}}",
  "status": "{{ticket.status}}"
}

For a ticket numbered 48291, the outbound JSON might look like this after Zendesk renders it:

{
  "event": "ticket.created",
  "ticketId": "48291",
  "ticketUrl": "https://example.zendesk.com/agent/tickets/48291",
  "requesterEmail": "alex@example.net",
  "requesterName": "Alex Rivera",
  "subject": "Unable to update billing address",
  "description": "I changed offices and need to update our billing address.",
  "priority": "normal",
  "status": "new"
}

The trigger sends this custom payload; it is not a fixed Zendesk event-subscription schema. That distinction matters. Zendesk event subscriptions always use POST and predefined JSON payloads, while a webhook connected to a ticket trigger or automation lets you customize the method, format, and body.

Placeholders are case-sensitive. Also remember that a placeholder with no value can render as blank. This is why the relay treats requesterEmail, ticketId, and the other required fields as validation requirements rather than assuming every ticket has complete data.

For more syntax and endpoint details as you expand the relay, consult the Volanea email API reference.

Build the message intentionally

A support ticket is not automatically safe email content. Customer-entered text may include markup-like characters, URLs, personal data, or content that is appropriate for a support agent but not for an automated external recipient.

The relay example HTML-escapes the requester name, title, and description before inserting them into HTML. That prevents ticket content such as <img> or <a> from becoming active markup in the email body. It also turns new lines into <br> elements for readability.

Choose the recipient deliberately

The example sends to {{ticket.requester.email}}, which is appropriate for a narrowly scoped acknowledgement. It is not automatically appropriate for every workflow.

For internal escalation email, do not let a requester-controlled custom field determine the recipient without validation. Instead, route by an allowlisted organization, ticket form, group, priority, or a server-side lookup. For example, a relay can map an organization ID to an account owner’s corporate address and reject any recipient outside your permitted domains.

Keep Zendesk and Volanea roles clear

Zendesk is the system that detects ticket activity and provides support context. Volanea is the system that accepts and sends the transactional email. Your relay is the policy boundary between them.

That separation helps avoid a common failure mode: placing all logic in a long trigger body, then trying to troubleshoot recipient rules and HTML formatting without normal application logs, tests, or version control. Keep the Zendesk body compact and structured; keep message policy in code.

Test the integration safely

Start with a trigger condition that is deliberately narrow, such as a test ticket form, a volanea_test tag, or a specific internal requester domain. Do not enable a ticket-created rule across the whole help desk until you have observed both a successful send and a controlled failure.

Use this test sequence:

  1. Create the webhook in inactive or test-ready form and use Zendesk’s webhook test capability to verify that the relay receives authentication and JSON.
  2. Deploy the relay with structured logs that record the ticket ID, endpoint result, and Volanea response status—but never log API keys or full sensitive ticket content.
  3. Create a trigger limited to a volanea_test tag.
  4. Open a ticket containing that tag from a controlled requester address.
  5. Confirm the Zendesk webhook invocation completed successfully.
  6. Confirm the relay logged the same ticket ID and returned 2xx.
  7. Confirm Volanea accepted the message and inspect the resulting email record or delivery events.
  8. Remove the test restriction only after confirming the exact trigger conditions will not overlap another acknowledgement rule.

A test that reaches Volanea but sends no email can still be a valid result if the address is suppressed or unsubscribed. Treat API acceptance, sending, delivery, bounce, and inbox placement as separate states when investigating outcomes.

When this breaks

Every integration of this type is a distributed system: Zendesk, your network, the relay, Volanea, and the recipient mailbox can each fail independently. Design the handoff around the actual failure modes instead of assuming a single POST is atomic.

Zendesk retries can create duplicate sends

Zendesk retries some failed webhook requests and uses a circuit breaker to avoid continually calling broken endpoints. A timeout is particularly ambiguous: your relay may have called Volanea successfully but failed to return a response to Zendesk before the connection closed. Zendesk can then retry the same logical ticket event.

That is why the relay sets Idempotency-Key: zendesk-ticket-created-<ticketId>. When the same ticket-created event is retried, Volanea can recognize the same logical send instead of creating a duplicate email.

Do not use a random UUID generated per request for this key. That would make every retry look like a new email. Do not use a static key such as zendesk-ticket-created, either; it would incorrectly merge all ticket notifications into one operation.

If the email must change when the ticket changes, use distinct event semantics. For example, a ticket-created acknowledgement can use zendesk-ticket-created-48291, while a resolved-ticket survey invitation could use zendesk-ticket-resolved-48291. Avoid combining a mutable ticket subject or description into an idempotency key because later edits could turn a retry into a different request.

Webhook timeouts and slow relays

Your webhook endpoint should validate, enqueue or call Volanea, and return promptly. Avoid making the Zendesk request wait on unrelated database reads, large template generation, CRM enrichment, or downstream analytics.

If richer enrichment is required, acknowledge the Zendesk webhook after you have durably queued the work. A worker can then enrich and send it asynchronously, using the same deterministic idempotency key. This provides a more reliable path than making Zendesk wait for every dependency in a long chain.

Monitor three values separately: Zendesk webhook failures, relay errors, and Volanea send failures. A Zendesk failure means the first hop did not complete successfully. A relay log entry means the second hop was attempted. A Volanea result tells you whether the provider accepted the message request.

Placeholder fields can be blank or unavailable

Zendesk placeholders return blank when the underlying field has no value. For example, a ticket may have no priority, no organization, or no requester email suitable for the message you intend to send. Custom fields can also behave differently depending on their configuration and the ticket form used.

The remedy is not to guess at missing data in the trigger. Send only fields your relay needs, validate them server-side, and fail safely. For a required acknowledgment, the relay can return a logged 200 for a malformed payload so Zendesk does not retry a permanently invalid ticket forever, while creating an internal alert for follow-up.

Also account for plan and configuration differences. The exact ticket features, custom fields, objects, roles, and trigger options available in a Zendesk account can vary by product plan and setup. Build the first version using standard ticket fields—ID, requester email, requester name, title, description, and link—then add custom-field dependencies one at a time with test tickets.

A 200 response does not mean inbox delivery

A successful relay response means only that the relay handled the webhook. A successful response from Volanea means the email request was accepted into its sending workflow. It does not guarantee the recipient inboxed the message.

For delivery investigations, verify the sender domain, inspect the email event history, check whether the address is suppressed, and look for bounce or complaint signals. Use a stable, verified sender identity and avoid sending marketing-style content from an operational support trigger.

Trigger loops and duplicate business rules

Do not use this webhook to update the same Zendesk ticket unless you have designed the rule very carefully. Zendesk warns that using webhooks to update tickets directly can produce race conditions and rate-limit issues. A relay that updates a ticket could also cause another ticket trigger to fire, creating a loop.

Prefer one-way notification flows. If you must write data back to Zendesk, use a separate, tightly scoped integration with explicit loop-prevention tags and conditions. Test trigger ordering as well: Zendesk ticket triggers run in configured order, and overlapping triggers can produce multiple notifications from one ticket event.

Alternatives to the relay approach

A custom relay is the best default when you need control, auditability, idempotency, and safe key storage. It is not the only possible route.

Direct Zendesk webhook to Volanea

This can reduce infrastructure for a simple internal proof of concept. Configure the Volanea send endpoint as the webhook destination, select the appropriate authenticated request configuration, and make the trigger body match Volanea’s expected message shape.

The tradeoff is limited control over retries, recipient validation, HTML escaping, dynamic idempotency headers, and application logging. Treat this as a narrowly scoped option rather than a general integration pattern.

Zapier or Make as middleware

An automation platform can be useful when a non-developer team owns the workflow and accepts the platform’s operational model. Zendesk can trigger an external webhook or integration flow, and the automation can call an HTTP endpoint.

However, evaluate secret storage, retry behavior, error visibility, dynamic request headers, cost at ticket volume, and duplicate-send handling before moving a high-value support workflow there. A small relay often has less hidden complexity once reliable retries and compliance rules matter.

A full application integration

If ticket events must join account data, subscription state, purchase history, or a custom notification center, send the Zendesk webhook to your application. Your application can enrich the event, decide whether email is appropriate, store an audit record, and then call Volanea.

This is the natural next step for support operations that need per-customer rules or multiple downstream effects. Keep the email send idempotent even in this architecture; a queue does not eliminate retries by itself.

Operational checklist

Before turning the trigger on for all new tickets, confirm the following:

  • The sender address uses a verified Volanea domain.
  • Zendesk sends POST JSON to an HTTPS relay endpoint.
  • The webhook uses a dedicated bearer token, not the Volanea API key.
  • The relay stores the Volanea key as an environment secret.
  • The relay validates required fields and escapes ticket text before HTML insertion.
  • The trigger is limited to Ticket is Created or another precisely defined event.
  • The relay derives one idempotency key per logical notification.
  • A retryable provider outage returns 5xx; invalid payloads are logged and handled intentionally.
  • Logs include ticket IDs and response statuses without exposing credentials or unnecessary personal data.
  • Trigger conditions do not overlap with Zendesk’s existing requester notifications or another custom email rule.

The core lesson is straightforward: Zendesk supplies the trigger; your relay supplies safety and control; Volanea supplies the transactional email send. That division makes it practical to add templates, different routing policies, delivery-event handling, and richer audit trails later without rebuilding the Zendesk side.

FAQ

Can Zendesk send email through Volanea without a native app?

Yes. Zendesk can send outbound HTTP requests through webhooks, and a ticket trigger can invoke a webhook when ticket conditions match. A secure relay can translate that webhook into a Volanea POST /v1/send request.

What starts the email send in Zendesk?

In this guide, a ticket trigger starts the send when Ticket is Created. Ticket triggers run immediately after a ticket is created or updated when their conditions are true, and the action is Notify by > Active webhook.

Should I put my Volanea API key in the Zendesk webhook?

For production, no. Store the Volanea API key in the relay’s environment-secret store. Put only a dedicated relay authentication token in Zendesk’s webhook authentication settings. This limits the blast radius and lets the relay create safe idempotency keys.

How do I stop duplicate emails when Zendesk retries a webhook?

Use a deterministic Volanea Idempotency-Key, such as zendesk-ticket-created-<ticketId>, and reuse it for retries of that same ticket-created notification. Do not generate a new random value per retry.

Why is my Zendesk field empty in the email?

A Zendesk placeholder renders blank when its referenced value is missing. Validate required fields in the relay, test each ticket form and channel, and do not rely on optional custom fields unless your workflow guarantees they are populated.