Sending email from Easyship is most reliable when you treat a shipment event as an input to your own server-side workflow, rather than trying to make a shipping platform behave like an email provider. This guide shows how to send email from Easyship with Volanea using Easyship webhooks, a secure middleware endpoint, and Volanea’s REST email API.
Easyship does not provide a native Volanea application, marketplace listing, or one-click email action. That is not a limitation you should work around with browser automation or a front-end script. Instead, the durable architecture is straightforward: Easyship emits a shipment event, your endpoint validates and normalizes it, and that endpoint sends the appropriate transactional message through Volanea.
This pattern gives you control over recipients, templates, localization, duplicate prevention, logging, and failure handling. It also keeps the Volanea API key off customer-facing pages and out of shipment metadata.
What the Easyship-to-Volanea integration does
At a high level, the integration has three systems with separate responsibilities:
- Easyship is the source of shipping truth. It creates and updates shipments, purchases labels, receives carrier tracking updates, and emits webhook events.
- Your middleware receives the webhook over HTTPS. It decides whether the event should result in an email, extracts safe fields, records idempotency state, and calls the email provider.
- Volanea sends the transactional email through its email infrastructure and provides sending, delivery, and event visibility.
The key design decision is that Easyship does not send the email directly. A webhook is an HTTP notification: Easyship posts JSON to a URL you control. That URL can be a serverless function, an application route, a small worker, or an automation platform webhook. It is the bridge between a shipping event and a mail API request.
For a first shipping notification, use the Easyship shipment-created event only if your operational definition is “a shipment now exists.” For a customer-facing dispatch email, many teams instead wait for the event that reflects their real fulfillment milestone, such as a label being created, a shipment being shipped, or a tracking update that confirms carrier acceptance. The best event is a business decision, not merely the earliest event available.
The concrete Easyship trigger: a shipment webhook event
Easyship’s outbound webhook capability is the appropriate direct HTTP mechanism for this integration. Configure a webhook subscription for the shipment event that matches the message you want to send. In Easyship terminology, the trigger is a shipment event delivered to a webhook endpoint.
A common starting point is the shipment.created event. It fires when Easyship creates the shipment record. This is useful for an internal fulfillment alert or an order-confirmation workflow where the customer should know that fulfillment has begun. It can be too early for a “your order has shipped” message, because a shipment record may exist before a carrier has accepted the parcel or before a final tracking number is available.
Before building the integration, write down the customer promise attached to each event:
- Shipment created: “We are preparing your shipment.”
- Label or fulfillment milestone: “Your package is on its way,” if your workflow considers label creation dispatch.
- Carrier/shipped milestone: “Your package has shipped,” when carrier handoff is confirmed.
- Tracking update: “Your package is moving” or “Your delivery date changed.”
- Delivered milestone: “Your package was delivered.”
Do not send every message for every webhook by default. Shipping systems can generate many updates for one parcel, including repeated tracking states. Build an explicit event-to-template policy so customers receive useful communications rather than a stream of near-duplicate notices.
Configure the webhook destination
Create a publicly reachable HTTPS endpoint in your application, such as:
https://app.example.com/webhooks/easyship
Then configure that endpoint as the callback URL for the Easyship shipment event you selected. Use a dedicated endpoint rather than a general-purpose API route. It should accept POST requests, parse JSON, verify any webhook authentication or signature mechanism available in your Easyship configuration, and return a successful response quickly.
A webhook endpoint should not do slow work before acknowledging receipt. If a provider regards a request as timed out, it may retry the delivery even if your code eventually completed the email call. The practical result can be duplicate emails. The safer approach is to persist or enqueue the event, return a 2xx response, and process the email asynchronously.
Do not confuse a webhook with a customer-data API
A webhook event is a notification payload, not always a complete customer profile. Some Easyship event payloads may contain a shipment identifier and shipment data, while the precise fields present depend on the event, account configuration, order source, and available shipment information. Do not assume that every shipment has an email address, tracking URL, carrier name, or customer-facing order number.
Your integration should therefore have two paths:
- Send immediately when the webhook has all required, validated data.
- Fetch or resolve additional shipment/order data from your own order system when the webhook only supplies identifiers or partial shipment details.
That distinction prevents a delivery notification from being sent to an empty recipient, to an internal address accidentally stored in an order note, or with a tracking link that has not yet been generated.
Why a middleware endpoint is required
Easyship webhooks send data to a URL; they are not an email-template engine and cannot safely hold a Volanea secret for arbitrary request transformation. A middleware endpoint is therefore the normal direct integration route.
The middleware can be very small. It needs to perform five jobs:
- Authenticate the incoming Easyship request where your webhook configuration supports authentication or signature verification.
- Identify the event and ignore events that are not part of your messaging policy.
- Map shipment fields into an approved email payload.
- enforce idempotency so webhook retries do not create duplicate sends.
- Send the message to Volanea using a server-side API key.
This is not unnecessary complexity. It is where operational rules belong. For example, you may want to suppress customer notifications for test shipments, warehouse transfers, pickup orders, shipments with a missing recipient email, or orders that have already received the same notification.
If you do not operate a server, use an automation platform as the middleware. Easyship integrations are also available through automation tooling such as Zapier, where a shipment trigger can initiate a multi-step workflow. In that arrangement, use the platform’s secure connection/secret storage and an HTTP request action to call Volanea. Avoid putting a Volanea key in a publicly shared Zap, a front-end form, an order note, or a browser-side script.
For production shipment communications, a serverless endpoint or worker is usually easier to audit and test than a long automation chain. It also gives you reliable idempotency storage, custom event parsing, and control over timeouts.
Map the Easyship webhook payload before writing email code
Webhook payloads should be treated as external input. Log a redacted sample from your own Easyship account first, then build a mapping that reflects the field names and nesting in the event you actually receive. Do not copy a sample payload from another account and assume it contains the same optional fields.
A shipment-oriented mapping typically needs these concepts:
| Email variable | Source concept | Validation rule |
|---|---|---|
| recipient address | shipment recipient or your order record | Must be a valid customer email address |
| customer name | recipient name or order customer name | Optional; use a neutral fallback |
| order reference | platform order number or your internal order ID | Required for customer support usefulness |
| tracking number | shipment tracking data | Optional until carrier tracking exists |
| tracking URL | Easyship/carrier tracking URL | Use only an HTTPS URL you trust |
| carrier/service | courier name and selected service | Optional; never fabricate it |
| shipment ID | Easyship shipment identifier | Required for idempotency and diagnostics |
The following example shows a webhook receiver in Node.js. The extractShipment function deliberately supports a common event-wrapper pattern in which data appears under resource, data, or shipment; you should narrow it to the exact payload shape from your Easyship webhook logs once confirmed. The code does not assume that a shipping event always includes an email address.
// app/api/webhooks/easyship/route.js
import crypto from "node:crypto";
const VOLANEA_API_URL = "https://api.volanea.com/v1/emails";
function firstString(...values) {
return values.find((value) => typeof value === "string" && value.trim())?.trim();
}
function extractShipment(payload) {
// Easyship webhook event data can be wrapped by the event envelope.
// Confirm this selection against a real webhook captured from your account.
const shipment = payload.resource ?? payload.data ?? payload.shipment ?? payload;
const recipient = shipment.recipient_address ?? shipment.recipient ?? {};
return {
event: payload.event ?? payload.event_type ?? payload.type,
shipmentId: firstString(
shipment.easyship_shipment_id,
shipment.shipment_id,
shipment.id
),
orderNumber: firstString(
shipment.platform_order_number,
shipment.order_number,
shipment.order_id
),
customerEmail: firstString(
recipient.email,
shipment.recipient_email,
shipment.customer_email
),
customerName: firstString(
recipient.name,
shipment.recipient_name,
shipment.customer_name,
"there"
),
trackingNumber: firstString(shipment.tracking_number),
trackingUrl: firstString(shipment.tracking_url, shipment.tracking_link),
courierName: firstString(shipment.courier_name, shipment.courier?.name),
};
}
function escapeHtml(value = "") {
return String(value).replace(/[&<>'"]/g, (character) => ({
"&": "&", "<": "<", ">": ">", "'": "'", '"': """
}[character]));
}
export async function POST(request) {
const rawBody = await request.text();
// If you configure a shared webhook secret/signature in Easyship, verify it here
// before JSON.parse. The exact header and verification method must match your
// Easyship webhook configuration.
// Example only for a shared-secret header you control:
const suppliedSecret = request.headers.get("x-webhook-secret");
if (!suppliedSecret || !crypto.timingSafeEqual(
Buffer.from(suppliedSecret),
Buffer.from(process.env.EASYSHIP_WEBHOOK_SECRET)
)) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
const payload = JSON.parse(rawBody);
const shipment = extractShipment(payload);
// Set this to the exact Easyship event selected in your webhook subscription.
if (shipment.event !== "shipment.created") {
return Response.json({ ignored: true }, { status: 200 });
}
if (!shipment.shipmentId || !shipment.customerEmail) {
// Store this for review or enrich it from your order system; do not send.
return Response.json({ skipped: "missing shipment ID or recipient" }, { status: 200 });
}
// Replace this with a database uniqueness check, such as a unique key on:
// easyship:shipment.created:${shipment.shipmentId}
const idempotencyKey = `easyship:shipment.created:${shipment.shipmentId}`;
const subject = shipment.orderNumber
? `We’re preparing order ${shipment.orderNumber}`
: "We’re preparing your shipment";
const trackingBlock = shipment.trackingUrl
? `<p>Track it here: <a href="${escapeHtml(shipment.trackingUrl)}">Track your shipment</a>.</p>`
: "";
const emailPayload = {
from: { email: process.env.VOLANEA_FROM_EMAIL, name: "Example Store" },
to: [{ email: shipment.customerEmail, name: shipment.customerName }],
subject,
html: `<p>Hi ${escapeHtml(shipment.customerName)},</p>
<p>Your shipment${shipment.orderNumber ? ` for order ${escapeHtml(shipment.orderNumber)}` : ""} is being prepared.</p>
${shipment.courierName ? `<p>Carrier: ${escapeHtml(shipment.courierName)}</p>` : ""}
${shipment.trackingNumber ? `<p>Tracking number: ${escapeHtml(shipment.trackingNumber)}</p>` : ""}
${trackingBlock}`,
text: `Hi ${shipment.customerName},\n\nYour shipment${shipment.orderNumber ? ` for order ${shipment.orderNumber}` : ""} is being prepared.${shipment.trackingNumber ? `\nTracking number: ${shipment.trackingNumber}` : ""}${shipment.trackingUrl ? `\nTrack it: ${shipment.trackingUrl}` : ""}`,
headers: { "Idempotency-Key": idempotencyKey }
};
const response = await fetch(VOLANEA_API_URL, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(emailPayload)
});
if (!response.ok) {
const detail = await response.text();
console.error("Volanea send failed", response.status, detail);
return Response.json({ error: "email send failed" }, { status: 502 });
}
return Response.json({ accepted: true, shipmentId: shipment.shipmentId }, { status: 200 });
}
The Volanea request is the important transformation: shipping data becomes a standard transactional message with from, to, subject, html, and text. Check the current email API reference and setup guides before deployment for the active endpoint, authentication format, supported idempotency behavior, and any template-specific fields in your Volanea account.
Keep the Volanea API key on the server side
The Volanea API key belongs in server-side secret storage, not in Easyship shipment fields and not in client-visible configuration. In the example, it is read from process.env.VOLANEA_API_KEY. On a serverless platform, add it through the platform’s encrypted environment-variable or secret manager interface. On a traditional server, store it in the deployment environment or a dedicated secrets manager.
Never place the key in any of these locations:
- JavaScript delivered to a customer’s browser.
- A mobile application bundle.
- A public Git repository, sample
.envfile, or support ticket. - An Easyship order note, shipment custom field, or customer-visible tracking page.
- A webhook URL query string.
- A Zapier/Make text field that is exported, shared broadly, or logged in plain text.
The reason is practical, not merely procedural. A transactional email API key can be used to send email as your domain. Exposure can create unwanted sending costs, phishing risk, damage to domain reputation, and a difficult incident response involving key rotation and message investigations.
Use separate keys by environment where possible. Your development webhook should send only to a controlled test inbox and use a development sender domain. Production should have a separate key, verified production sender identity, and access limited to the minimum scope needed for sending.
Secure the inbound side too
Protecting the outbound Volanea credential is only half the job. Your webhook endpoint must also defend against arbitrary third parties posting fake shipping events. Use the authentication or signature method supported by your Easyship webhook configuration, reject requests that fail verification, and avoid relying only on an obscure URL.
If your configuration supports a static shared secret, send it in a header and compare it using a timing-safe comparison. If it supports signed payloads, validate the signature against the raw request body before parsing or modifying it. Record the event identifier, timestamp, and outcome, but redact recipient addresses and tracking details from logs where they are not needed.
Build an email that matches the shipping state
The email copy must be truthful at the moment the event occurs. This is especially important in shipping workflows because terms such as “created,” “packed,” “label printed,” “shipped,” and “delivered” have distinct operational meanings.
For shipment.created, a safe message says that the shipment is being prepared. If you have proof that the carrier has accepted the parcel, you can use stronger language such as “has shipped.” Avoid saying “on its way” merely because an internal shipment record was created.
Use a stable transactional template
A production implementation should normally use a transactional template rather than building raw HTML inside the webhook handler. Templates make brand updates, localization, and approval easier. The handler then supplies a small, typed set of variables such as first_name, order_number, tracking_number, and tracking_url.
Keep the template defensive. A tracking URL may not exist on the event that creates a shipment. The template should hide the tracking button when no safe URL exists rather than showing a broken button. Likewise, do not show a carrier field if the carrier is not yet selected.
Use a clear sender identity, a useful reply-to mailbox, and a recognizable subject line. Shipping notices often generate support replies, especially when a tracking link is delayed or a carrier scan has not appeared. A monitored reply address turns a confusing edge case into a recoverable support conversation.
Validate recipients before sending
An order record can contain a typo, a placeholder address, or an address collected before checkout validation. Validate syntax in your application and consider checking uncertain addresses before allowing them into an automated delivery-notification flow. Volanea’s free email address verification tool can help assess an address before it becomes a repeated source of bounces.
Do not silently substitute an internal warehouse address when the customer email is absent. That creates misleading operational evidence: the system will look as though a customer notice was sent when it was not. Mark the workflow as skipped, alert the relevant team if needed, and preserve the shipment ID for reconciliation.
When this breaks: failures specific to this hop
A shipping-to-email automation can fail in ways that a normal website contact form does not. The event source may retry, shipment data may be incomplete, and a single carrier journey can generate several related updates. Design for these cases before enabling customer sends.
Easyship retries can cause duplicate sends
Webhook providers commonly retry a delivery when they do not receive a timely successful HTTP response. A retry does not necessarily mean the first attempt failed completely. Your handler may have sent the Volanea request and then crashed, timed out, or lost the response before returning 200 to Easyship.
Use idempotency at your own persistence layer. Create a deterministic key from the event type and immutable Easyship shipment ID, for example:
easyship:shipment.created:ES_SHIPMENT_ID
Store it with a unique database constraint before sending. If a second request arrives with the same key, return a successful response without sending again. Provider-level idempotency can be an additional safeguard, but your database remains the clearest source of truth because it records your business decision.
Do not use only a timestamp as the duplicate key. Retries can have different timestamps. Do not use only an order number either, because one order can legitimately become multiple shipments.
Webhook timeouts create ambiguous outcomes
A webhook handler that waits for database writes, remote API calls, template rendering, and logging can exceed the sender’s timeout. Once that happens, Easyship may retry even if the message provider eventually accepts the send.
The robust pattern is an inbox/outbox flow:
- Verify and store the raw event with its idempotency key.
- Respond with
2xximmediately after durable storage. - Process the stored event from a queue or worker.
- Mark it sent only after Volanea accepts the request.
- Retry transient failures using controlled backoff.
This also separates webhook availability from email-provider availability. If Volanea has a temporary API error, your receiver can still acknowledge the Easyship event and retry the outbound email without asking Easyship to replay the whole shipment notification.
Fields can be absent, delayed, or plan-dependent
Shipping data is not uniform. A shipment can lack a customer email because the order source did not provide it. A tracking number may appear only after label purchase or carrier assignment. A tracking URL can be absent, changed, or represented differently across carrier services. API and webhook availability may also depend on the Easyship account’s enabled features and plan.
Make missing fields an expected branch, not an exception. Define a minimum-send contract for each template. For example, a preparation email may need only shipmentId and customerEmail, while a tracking email must require a valid tracking URL or tracking number. If the required fields are absent, defer the message until a later relevant event or enrich the data from your order system.
Event names and payloads must be verified in your account
Do not deploy based solely on a copied event name or a generic JSON sample. In Easyship, select the event in your webhook settings, generate a test shipment in a non-customer workflow where possible, and inspect the raw request. Confirm exact event naming, headers, nesting, identifiers, and optional fields.
Then write contract tests using sanitized fixtures from those real events. A fixture should cover at least a complete shipment, a shipment without tracking, a shipment without recipient email, and a duplicate delivery. This is how you catch a payload change before it becomes a customer-facing failure.
Testing the workflow without emailing customers
Start with a development environment and a controlled recipient address. Use a development sender identity and make the recipient override explicit in code. Never rely on an informal convention such as “test orders use a test email”; people eventually use a real customer address in a test scenario.
A sensible test sequence is:
- Capture a real or sandbox Easyship webhook payload and redact personal data before saving it as a fixture.
- Send that fixture to the middleware locally or in a staging deployment.
- Confirm the parser recognizes the selected shipment event.
- Verify required fields and template fallback behavior.
- Confirm exactly one Volanea API request is made for repeated delivery of the same fixture.
- Inspect the received message in a test inbox on desktop and mobile.
- Trigger the same workflow in production with an internal order before enabling it for customers.
Test the negative cases as carefully as the happy path. Send a request with an invalid webhook secret. Send malformed JSON. Omit the recipient email. Submit an event that your route should ignore. Simulate a Volanea 429 or 5xx response and confirm that your worker retries without creating a new customer-visible message on each attempt.
Observability, deliverability, and support operations
A “200 OK” from your webhook route is not proof that a customer received the email. It only proves that the receiver accepted the request. Keep separate records for the Easyship event, your processing result, the Volanea send response, and downstream delivery events where available.
At minimum, attach these fields to an internal log or database record:
- Easyship event type and shipment ID.
- Your idempotency key.
- Internal order reference, if available.
- Recipient address in appropriately protected/redacted form.
- Volanea message identifier or API response identifier.
- Selected template and version.
- Final processing status and failure reason.
This data gives support staff a direct answer when a customer says they did not receive a tracking email. They can distinguish “no email was attempted because the order had no recipient address,” “the email API rejected the request,” “the provider accepted the message,” and “the message was delivered or bounced.”
Deliverability also depends on sender setup. Use a verified sending domain, align the From address with your brand, and avoid sending shipping notifications from an unrelated consumer mailbox. Keep transactional content focused on the shipment. A delivery notice is not the place to add large promotional sections that can change recipient expectations and complicate consent handling.
Alternatives when a direct webhook receiver is not practical
If you cannot deploy a custom endpoint, an automation platform can bridge Easyship and Volanea. The conceptual model remains identical: a shipment event triggers a workflow, a filter checks the required data, and an HTTP action makes a server-side API request to Volanea.
A no-code implementation should still include the same controls:
- Filter only the intended shipment event or trigger.
- Require a non-empty, valid recipient email.
- Use a stable shipment ID as the deduplication key if the platform offers storage or dedupe features.
- Store the Volanea credential in the platform’s protected connection or secret facility.
- Add an error path that alerts your team rather than silently discarding failures.
- Test with a controlled mailbox before turning on customer notifications.
The trade-off is control. A custom receiver can verify raw signatures, persist raw events, run database transactions, and implement nuanced idempotency. An automation platform can be faster to launch for low volume, but review its retry behavior, task history retention, secret-sharing model, and error notifications before making it part of fulfillment communications.
A practical production checklist
Before switching on the workflow, confirm all of the following:
- The Easyship webhook is subscribed to the shipment event that matches your actual customer promise.
- The endpoint is HTTPS, publicly reachable, and protected by the available webhook verification method.
- The Volanea API key exists only in server-side or automation-platform secret storage.
- The sender domain and From address are verified for transactional sending.
- Your route validates event type, shipment ID, recipient address, and any required tracking fields.
- A unique idempotency record prevents retries from producing another send.
- Missing email or tracking data follows a documented skip, enrichment, or defer path.
- The template does not claim a parcel has shipped before your selected event supports that claim.
- Failure alerts reach an owner who can investigate delayed or rejected sends.
- Staging and production use separate credentials and controlled test recipients.
With those controls in place, the integration is simple to operate: Easyship remains the shipping event source, Volanea remains the sending layer, and your middleware makes the business decision between them.
FAQ
Can Easyship send directly to Volanea without middleware?
Not as a native Volanea app or plugin. Use an Easyship webhook to notify a server-side endpoint, then have that endpoint call Volanea’s REST API. An automation platform can act as the intermediary when you do not maintain a server.
Which Easyship event should send a tracking email?
Use the event that corresponds to your real dispatch milestone, not automatically shipment.created. A creation event can be suitable for a preparation notice, while a tracking or carrier-confirmed shipment event is more appropriate for a “shipped” message.
Where should the Volanea API key be stored?
Store it in server-side environment variables or a secrets manager used by your middleware. If using an automation platform, use its protected credential storage. Never expose it in browser code, public configuration, shipment fields, or webhook URLs.
How do I stop duplicate emails after a webhook retry?
Create and persist an idempotency key based on the Easyship event type and immutable shipment ID before sending. If the same key arrives again, acknowledge it without sending another message.
What happens if a shipment webhook does not include an email address?
Do not send. Record the skipped event and either look up the customer email in your order system or wait for a later event with the required data. Sending to a guessed or fallback address is not a safe substitute.