Send email from ConnectWise without relying on a mailbox rule, manually copied ticket details, or an unverified marketplace plugin. This guide shows a production-safe route: ConnectWise PSA triggers a Zapier workflow when a service ticket is created or updated, Zapier passes a controlled ticket payload to your middleware, and that middleware calls the Volanea REST API.

Volanea does not ship a native ConnectWise app, ConnectWise Marketplace listing, or PSA plugin. The practical integration path is therefore middleware-based rather than an in-product installation flow. ConnectWise Manage—now ConnectWise PSA—has a supported Zapier connection with an instant New/Updated Ticket trigger, while Zapier can send data onward to an HTTP endpoint.

That distinction matters. A ticket status update is an operational event inside your PSA. Sending an email is an external side effect. Treating the email send as a small integration service gives you a place to protect secrets, validate recipient data, prevent duplicate messages, handle temporary failures, and leave an audit trail.

What this ConnectWise email integration does

The workflow in this guide sends a transactional email when a ConnectWise PSA service ticket is created or updated and meets your chosen condition. A common example is a ticket entering a customer-facing status such as Awaiting Customer, Scheduled, or a custom status your service board uses.

The complete path looks like this:

  1. A technician or automation creates or updates a service ticket in ConnectWise PSA.
  2. Zapier receives the ConnectWise Manage New/Updated Ticket trigger event.
  3. A Zapier Filter step decides whether this particular update should send an email.
  4. Zapier maps only the required ticket fields into a small JSON request and POSTs it to your private middleware endpoint.
  5. Middleware validates the request, produces an idempotency key, and calls POST /v1/send on Volanea.
  6. Volanea queues and dispatches the message through the sending domain you have verified.
  7. Your middleware returns a concise result to Zapier, which preserves the run history for operational troubleshooting.

The trigger is deliberately specific: New/Updated Ticket. It is an instant ConnectWise Manage trigger in Zapier and fires when a service ticket is created and/or updated. That means it is useful for status-driven customer updates, but it also means you must filter carefully. A ticket can be updated for many reasons that do not warrant an email: a technician changes an internal note, adjusts a priority, logs time, or changes an assignment.

The integration should not attempt to replace ConnectWise PSA’s own email templates for every ticket notification. Use this route when you need API-driven sending controls, a custom sender identity, richer transactional layouts, a workflow that connects to other systems, or a reliable record of the send request outside the PSA notification system.

Why the Zapier and middleware route is the right fit

ConnectWise PSA has workflow rules for automating PSA actions based on events and conditions. Those are valuable for service operations, escalations, and internal consistency. But this guide does not assume that a PSA workflow rule can make a generic outbound HTTP call with custom authentication, a JSON body, and an idempotency header. Instead, it uses the documented ConnectWise Manage integration available in Zapier.

Zapier acts as the event bridge. Middleware acts as the secure integration boundary. Volanea acts as the email delivery API.

Why not put the Volanea key directly in ConnectWise?

Do not put a Volanea secret key in a ticket template, custom field, email body, client-side form, browser extension, or any configuration that technicians or customers can view. A Volanea API key authorizes outbound email activity. If it leaks, the problem is not merely a failed automation; it can become an unauthorized sending and deliverability incident.

ConnectWise PSA is the event source, not the ideal secret vault for a third-party email credential. In this architecture, the Volanea key lives only in your middleware runtime’s encrypted environment-secret store—for example, a Cloudflare Worker secret, a server environment variable, or a managed secrets service. Zapier receives a separate shared webhook secret used only to authenticate requests to your middleware.

This separation gives you two important controls:

  • A compromised Zapier webhook credential cannot be used directly to send through Volanea without passing your validation logic.
  • A compromised ConnectWise PSA API member does not automatically expose your Volanea sending key.

Why middleware is worth the extra hop

It is tempting to point a generic webhook step directly at an email API. That can work for a quick test, but it makes production safeguards harder. Middleware gives you a predictable place to reject malformed requests, remove unsafe HTML, normalize recipient addresses, throttle accidental bursts, log a correlation ID, and reuse the same idempotency key after a retry.

It also gives you future options. You can add a delivery-event webhook from Volanea later, write the outcome to a data store, or create an internal ConnectWise note through the PSA API only after delivery or bounce processing. Keep the first implementation simple: send the notification reliably, then expand observability when the operational need exists.

The concrete ConnectWise trigger to use

In Zapier, create a new Zap and choose ConnectWise Manage as the trigger app. Although the product is now branded ConnectWise PSA, the Zapier connector uses the ConnectWise Manage name.

Choose this trigger event:

  • New/Updated Ticket (Instant) — triggers when a ConnectWise PSA service ticket is created and/or updated.

Connect your PSA account using a dedicated API Member rather than a technician’s personal credentials. The connection requires your ConnectWise company identifier, API public key, private key, and site URL. Give the API Member only the permissions required to read the ticket data that will drive this workflow.

After the connection test succeeds, use a real test ticket. The sample is important because ticket output is not a universal, frozen contract across every PSA tenant. Your service board configuration, security roles, activated modules, custom fields, and Zapier connector version affect which fields are available to map.

Filter the event before it becomes an email

A New/Updated Ticket trigger is broad by design. Add a Filter by Zapier step before any webhook or code step. A sensible starting rule is:

  • Continue only when the ticket status name equals your customer-notification status.

For example, if your service board uses a status called Awaiting Customer, you might filter for that exact value. Do not copy that name blindly: ConnectWise PSA statuses are configurable per service board. Use the status that your own process treats as an intentional customer handoff.

You can also add safeguards such as:

  • Continue only when contactEmailAddress exists.
  • Continue only when the company is not your internal company.
  • Continue only when the ticket is on a particular service board.
  • Continue only when a custom field such as Send Customer Update is set to true.
  • Stop the Zap when the ticket is closed, cancelled, or marked as an internal-only request.

The best first rule is narrow. You can widen the automation after a week of observing real ticket updates and confirming that technicians are not receiving unintended customer emails.

Understand the ticket payload before mapping it

ConnectWise PSA itself is not directly posting a webhook payload to Volanea in this design. Zapier receives the ConnectWise ticket event, exposes its output fields in the Zap editor, and then maps those fields into the JSON body sent to your middleware.

A service-ticket record commonly contains fields and nested objects similar to the following. Treat this as the ticket data model you should expect to inspect in your Zap test, not as a promise that every field will be present in every tenant or trigger sample.

{
  "id": 8421,
  "summary": "VPN access needed for new employee",
  "company": {
    "id": 55,
    "name": "Example Manufacturing"
  },
  "contactName": "Morgan Lee",
  "contactEmailAddress": "morgan.lee@example.com",
  "board": {
    "id": 7,
    "name": "Service Desk"
  },
  "status": {
    "id": 12,
    "name": "Awaiting Customer"
  },
  "priority": {
    "id": 3,
    "name": "Priority 3"
  },
  "lastUpdated": "2026-10-02T15:42:18Z"
}

The fields that matter for a straightforward customer update are the ticket ID, ticket summary, contact email address, contact name, company name, status name, and last-updated timestamp. Do not send the entire ticket object simply because it is available. Ticket descriptions, internal notes, configuration details, passwords, or security findings may be sensitive. An email automation should send the minimum necessary information.

Create a stable payload owned by your integration

In your Zapier webhook action, map the ConnectWise fields into a smaller payload that your middleware owns. This is preferable to coupling your email logic to every raw field returned by the connector.

Use a request body shaped like this:

{
  "ticketId": "8421",
  "summary": "VPN access needed for new employee",
  "companyName": "Example Manufacturing",
  "contactName": "Morgan Lee",
  "contactEmailAddress": "morgan.lee@example.com",
  "statusName": "Awaiting Customer",
  "lastUpdated": "2026-10-02T15:42:18Z"
}

In Zapier, map ticketId from the ConnectWise ticket ID, summary from the ticket Summary field, companyName from the Company Name output, contactName from Contact Name, contactEmailAddress from Contact Email Address, statusName from Status Name, and lastUpdated from the ticket’s last-updated field if available.

If your test output does not include a contact email address, do not substitute a guessed address or a company-domain pattern. Add a lookup step, stop the Zap, or route the ticket for manual review. Sending a customer communication to the wrong person is worse than delaying it.

Build the Zapier workflow step by step

The operational version of this automation has four Zap steps after the ConnectWise connection is established.

Step 1: Trigger on New/Updated Ticket

Select ConnectWise Manage and New/Updated Ticket (Instant). Test with a ticket on the actual service board and status you plan to automate.

Review the trigger output carefully. A ticket’s summary and status may be available even when its contact-related fields are blank. That is especially common for tickets created from monitoring tools, internal requests, catchall-company records, or workflows that create a ticket before a contact is assigned.

Step 2: Filter customer-facing status changes

Add Filter by Zapier. Start with an exact comparison against the output status name. If you send emails only when a ticket reaches one state, filter by that state and nothing else.

Avoid a rule such as “ticket was updated.” That condition is already true for every trigger run. The filter needs to express your business decision: for example, “this ticket has now reached the stage where the contact needs an update.”

Step 3: Send the controlled payload to middleware

Add Webhooks by Zapier and use a POST request to your private endpoint, such as https://your-worker.example/connectwise-ticket-email. Configure JSON as the payload type and map the seven controlled values described above.

Add a request header such as X-ConnectWise-Webhook-Secret. Its value should be a long randomly generated secret stored in Zapier’s protected workflow configuration or credentials setup, not inside the ticket data. This is not the Volanea key. It merely proves that the request came through your approved automation route.

For an organization with strict credential controls, use an API gateway, mutual TLS, or a signed webhook pattern. The core principle remains the same: ConnectWise ticket fields must never contain the Volanea API key.

Step 4: Test with a non-production recipient first

Before publishing, use a test contact you control. Create a ticket, move it into the qualifying status once, and inspect all three systems:

  1. The Zap history should show the expected mapped payload.
  2. Middleware logs should show a successful validation and outbound Volanea request.
  3. Volanea should show the email request and its message state.

Once the result is correct, change the ticket status back, then repeat the update. This confirms that your duplicate prevention behaves as intended and that the email body does not leak internal-only ticket data.

For endpoint details, authentication patterns, and message options beyond this guide, review the Volanea email API reference.

Working middleware code: map a ConnectWise ticket to a Volanea email

The following Cloudflare Worker example accepts the controlled JSON payload from Zapier, validates the shared webhook secret, maps ticket values into an email, and calls Volanea’s POST /v1/send endpoint. Store VOLANEA_API_KEY, CONNECTWISE_WEBHOOK_SECRET, and FROM_EMAIL as Worker secrets or environment variables. Do not hard-code them in the script.

The code uses the ticket ID and status name to create a deterministic idempotency key. If Zapier retries the same ticket-status notification after a timeout, Volanea receives the same key and can safely recognize it as the same logical send. If a ticket later moves into a different customer-facing status, the status portion changes and a new email can be sent intentionally.

export default {
  async fetch(request, env) {
    if (request.method !== "POST") {
      return new Response("Method Not Allowed", { status: 405 });
    }

    const suppliedSecret = request.headers.get("X-ConnectWise-Webhook-Secret");
    if (!suppliedSecret || suppliedSecret !== env.CONNECTWISE_WEBHOOK_SECRET) {
      return new Response("Unauthorized", { status: 401 });
    }

    const ticket = await request.json();

    const required = [
      "ticketId",
      "summary",
      "contactEmailAddress",
      "statusName"
    ];

    for (const field of required) {
      if (!ticket[field] || typeof ticket[field] !== "string") {
        return Response.json({ error: `Missing required field: ${field}` }, { status: 400 });
      }
    }

    const recipient = ticket.contactEmailAddress.trim().toLowerCase();
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(recipient)) {
      return Response.json({ error: "Invalid contactEmailAddress" }, { status: 400 });
    }

    const escapeHtml = (value = "") =>
      String(value)
        .replaceAll("&", "&")
        .replaceAll("<", "&lt;")
        .replaceAll(">", "&gt;")
        .replaceAll('"', "&quot;")
        .replaceAll("'", "&#039;");

    const ticketId = escapeHtml(ticket.ticketId);
    const summary = escapeHtml(ticket.summary);
    const companyName = escapeHtml(ticket.companyName || "your service provider");
    const contactName = escapeHtml(ticket.contactName || "there");
    const statusName = escapeHtml(ticket.statusName);

    const subject = `Update on ticket #${ticket.ticketId}: ${ticket.summary}`;
    const text = [
      `Hello ${ticket.contactName || "there"},`,
      "",
      `${companyName} has updated service ticket #${ticket.ticketId}.`,
      `Status: ${ticket.statusName}`,
      `Summary: ${ticket.summary}`,
      "",
      "Reply to your existing support conversation if you need help."
    ].join("\n");

    const html = `
      <p>Hello ${contactName},</p>
      <p>${companyName} has updated service ticket <strong>#${ticketId}</strong>.</p>
      <p><strong>Status:</strong> ${statusName}<br />
      <strong>Summary:</strong> ${summary}</p>
      <p>Reply to your existing support conversation if you need help.</p>
    `;

    const idempotencyKey = `connectwise-ticket-${ticket.ticketId}-${ticket.statusName}`;

    const volaneaResponse = await fetch("https://api.volanea.com/v1/send", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${env.VOLANEA_API_KEY}`,
        "Content-Type": "application/json",
        "Idempotency-Key": idempotencyKey
      },
      body: JSON.stringify({
        from: env.FROM_EMAIL,
        to: [recipient],
        subject,
        text,
        html
      })
    });

    const responseBody = await volaneaResponse.text();

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

      return Response.json(
        { error: "Volanea send failed", status: volaneaResponse.status },
        { status: 502 }
      );
    }

    return Response.json({
      ok: true,
      ticketId: ticket.ticketId,
      idempotencyKey,
      volanea: JSON.parse(responseBody)
    });
  }
};

The from value must be an address or sender identity permitted by the domain you have configured in Volanea. Do not use a customer contact’s address as the from address. If replies should reach a service desk mailbox, configure a reply-to behavior in the email design or use the customer’s existing support conversation pattern.

Keep the email content appropriate for a ticket update

The example intentionally includes only a ticket number, status, and summary. That is enough for a customer-facing update in many MSP workflows. Add more information only after deciding who is authorized to receive it.

Avoid automatically including internal discussion fields, technician-only notes, credentials, device serial numbers, security findings, raw monitoring alerts, or configuration passwords. In ConnectWise PSA, fields may look like ordinary ticket context to a technician but still be inappropriate for an external email.

Authentication and secret handling

This integration has three separate credential categories. Keep them separate rather than trying to reuse one value everywhere.

ConnectWise PSA credentials

Zapier connects to ConnectWise Manage using a ConnectWise API Member with a public key, private key, company identifier, and site URL. Give that API Member the least privilege needed to read the relevant tickets, contacts, companies, and service-board data. Use a dedicated integration identity so that rotating or disabling a technician account does not unexpectedly break your email automation.

Zapier-to-middleware credential

Use a unique shared secret in an HTTP header such as X-ConnectWise-Webhook-Secret. Middleware compares it to an environment secret before parsing or acting on the payload. Rotate it if Zapier access changes, if an administrator leaves, or if webhook configuration may have been exposed.

A stronger implementation can validate a signed request, use an API gateway token, or restrict inbound traffic. What matters most is that your endpoint cannot be called anonymously to generate emails from arbitrary JSON.

Volanea API key

The Volanea secret key belongs only in the middleware runtime’s secret store. It must not sit in the ConnectWise PSA ticket, a public Zap payload, a front-end application, or a shared document. Middleware adds the Authorization header only when it makes the server-to-server Volanea request.

This design also makes key rotation less disruptive. Replace the secret in one runtime configuration, deploy or restart as required by the platform, send a test message, then revoke the old key. You do not need to edit every ticket workflow or ask PSA users to update anything.

When this breaks: ConnectWise-to-email failure modes

Every automation has failure modes. The important question is whether a failure produces a safe retry, a visible alert, and a clear operational next step.

Zapier retries can otherwise create duplicate ticket emails

A request can reach middleware and Volanea successfully while the response back to Zapier is delayed or lost. Zapier may treat the step as failed and retry it. Without idempotency, that retry may generate a second customer email.

The example prevents that by using the same Idempotency-Key for the same ticket and status. Preserve the same key for a logical send. Do not generate a random key inside each retry attempt, because that turns retries into entirely new send requests.

Also think about the business event. A ticket may pass through Awaiting Customer, move to In Progress, then return to Awaiting Customer days later. The example’s ticket-plus-status key would treat the second visit as a duplicate. If repeat entry into the same status should send a new update, include a stable event timestamp or a dedicated outbound-notification marker in the idempotency design. If it should not send again, the example is intentionally conservative.

Webhook timeouts create ambiguous outcomes

A timeout does not prove that an email was not sent. It means one hop did not receive a response in time. Middleware should return quickly after the Volanea API call, avoid slow unrelated work, and log the Volanea result with the ticket ID and idempotency key.

If the Volanea call returns a temporary server error or a rate-limit response, return a failure to Zapier so its retry behavior can take over. If it returns a validation failure such as an invalid recipient or unverified sender, do not blindly retry forever. Fix the data or configuration first.

Ticket payload fields may be absent

Do not assume every ticket has a contact, a contact email, a company, or the same output shape. ConnectWise PSA data availability can vary with the selected modules, service-board configuration, API-member permissions, ticket origin, and the fields exposed by the Zapier trigger. Monitoring-generated tickets and catchall records are especially likely to lack a usable customer email address.

Require the fields your email needs. The middleware example rejects requests lacking a ticket ID, summary, recipient email, or status. That creates a visible Zap failure instead of silently sending a malformed message to a fallback address.

Status names change when processes change

Statuses are operational configuration, not a universal API standard. Someone may rename Awaiting Customer to Waiting on Client, create a similar status on another board, or move the workflow to a different board. Your filter may then stop matching without any code error.

Document the filter condition beside the service-board process. When service managers change statuses, include Zapier workflow review in the change checklist. A quarterly test ticket is a practical way to catch drift before a customer notices missing updates.

Recipient mistakes are deliverability and privacy issues

A syntactically valid address is not necessarily the correct recipient. A former employee may remain on a ticket, a shared mailbox may be inappropriate for an incident, or the primary contact may not be authorized to receive technical detail.

Use the contact associated with the ticket only if that association is part of your support process. For high-risk notifications, add an approval step or use a dedicated notification contact field. Before sending at scale, you can also validate candidate addresses with the email verification tool, but verification does not replace your own authorization and contact-management rules.

Improve the workflow after the basic send works

Once the first notification is reliable, improve it in small, observable increments.

Add a send-intent field or audit marker

The strongest duplicate-prevention design is based on an explicit business event. For example, your process might set a custom ticket field such as Customer Update Requested and clear it after a successful email. Another pattern is to add a private audit note through the PSA API stating that ticket update email abc123 was requested.

Do not build this feedback loop until the one-way send is stable. A two-way integration adds permission scopes, failure ordering questions, and potential loops. If you do add it, make sure the note or custom-field update does not itself trigger another email run.

Separate customer updates from technician notifications

A customer update has different content, sender identity, and urgency from an internal escalation. Use separate filters and separate templates or middleware routes. A dispatch manager may need a concise alert with SLA context; a customer may need a plain-language summary with no internal operational details.

This separation improves deliverability as well. Transactional customer messages should remain clearly transactional and relevant to the recipient. Avoid turning ticket events into bulk marketing sends.

Use a template when email formatting becomes complex

For one short status update, building text and html in middleware is clear and easy to audit. If you later need branded headers, multilingual variants, dynamic service hours, or many notification classes, move the presentation layer to a reusable email template while retaining the same payload-validation and idempotency layer.

Keep template variables boring and well defined: ticket number, contact first name, company name, status label, public summary, and a ticket portal link if your support process provides one. Avoid allowing untrusted ticket content to become executable HTML.

Monitor the whole chain, not just the Zap

A green Zap run means Zapier successfully completed its steps. It does not necessarily mean the customer read the email. Likewise, a Volanea API acceptance result means the message entered the sending pipeline, not that a mailbox provider accepted it.

Track the chain at the right levels:

  • ConnectWise PSA: did the ticket actually reach the qualifying status?
  • Zapier: did the trigger run and pass the filter?
  • Middleware: did the request authenticate and validate?
  • Volanea: was the API send request accepted, queued, delivered, bounced, or suppressed?
  • Support operations: did the customer receive an appropriate update and reply through the intended channel?

A practical rollout checklist

Before enabling the workflow for live customer tickets, complete this checklist.

  1. Create a dedicated ConnectWise PSA API Member with least-privilege access.
  2. Connect that API Member to Zapier and test the New/Updated Ticket trigger using a real but non-sensitive service ticket.
  3. Decide the exact service board and customer-facing status that should produce an email.
  4. Add a narrow Zapier Filter for that status and require a contact email address.
  5. Deploy middleware with VOLANEA_API_KEY, CONNECTWISE_WEBHOOK_SECRET, and FROM_EMAIL stored as secrets.
  6. Verify the sending domain and sender identity in Volanea before live use.
  7. Send a test to an internal mailbox and inspect the subject, text body, HTML rendering, sender, and reply behavior.
  8. Force one safe retry scenario and confirm that the idempotency key prevents a duplicate send.
  9. Test a ticket with no contact email and verify that the workflow fails visibly rather than sending to the wrong address.
  10. Publish the Zap, then review its history and Volanea send activity after the first several production events.

The goal is not simply to make an email appear in an inbox. The goal is to make every qualifying ticket event result in one appropriate, traceable, secure customer notification.

FAQ

Does Volanea have a native ConnectWise PSA plugin?

No. Volanea does not provide a native ConnectWise app, Marketplace listing, or installable PSA plugin. Use ConnectWise Manage in Zapier as the event source, then call Volanea through secure middleware.

What ConnectWise event starts the email?

Use Zapier’s New/Updated Ticket (Instant) trigger for ConnectWise Manage. It starts when a ConnectWise PSA service ticket is created or updated. Add a filter so that only your intended customer-facing status produces an email.

Where should the Volanea API key be stored?

Store it only as an encrypted server-side secret in middleware, such as a Worker secret or application environment variable. Do not place it in ConnectWise ticket fields, public configuration, client-visible code, or the raw ticket payload.

How do I stop duplicate emails if Zapier retries?

Send a stable Idempotency-Key with the Volanea POST /v1/send request. Reuse the same key for retries of the same ticket-notification event. Design the key around the business event, not around a new random value generated for every HTTP attempt.

What happens if a ticket has no contact email address?

The workflow should stop and surface an actionable failure. Do not invent an address, fall back to an unrelated company contact, or send to a technician by default unless that fallback is explicitly part of your support process.