How to Send Shipping Confirmation Emails Automatically
Email customers automatically when their orders ship with tracking information.
What This Integration Does
Shipping confirmation is the most-opened transactional email a store sends. A well-branded one builds trust and cuts "where's my order" support tickets in half. This workflow listens for fulfillment events from your store, builds a personalised email with the tracking number, ETA, and order line items, and sends it through Resend or SMTP. It runs per-order so customers get their notice within seconds of the package being scanned out of the warehouse.
The workflow is webhook-driven and idempotent on the fulfillment ID, so a webhook retry will not double-send. Failed sends route to a Slack channel for the support team to follow up on manually rather than disappearing silently.
Prerequisites
- A Shopify or WooCommerce connection with order read access.
- A Resend connection with a verified sending domain, or an SMTP connection (host, port, user, password).
- An email template (HTML, with handlebars placeholders) approved by marketing.
- A from address on the verified domain.
Step 1: Webhook Trigger on Fulfillment
Add a Trigger node and set its type to Webhook. Configure your store to send fulfillment events to this URL - on Shopify, that's the fulfillments/create webhook. The trigger emits the fulfillment payload, including the tracking number, carrier, and order ID.
Step 2: Hydrate the Order
The webhook gives you the fulfillment, but you typically want fuller order context for the email. Add a Connector node on shopify with the get-order tool (or woocommerce get-order) using {{ trigger.body.order_id }}. Capture the response as order so the email template can read line items, totals, and the customer's first name.
Step 3: Compute the Estimated Delivery
Add a Transform node to derive a friendly ETA. A simple rule: add 3 business days to fulfillment.created_at for domestic, 7 for international. Use the date connector's add tool with unit: "day". Format it for the email with the date format tool (e.g. "dddd, MMMM Do").
Step 4: Build the Email Body
Add a Transform node that renders your HTML template with the order context. Variables your template should use:
{{ order.customer.first_name }}{{ trigger.body.tracking_number }}{{ trigger.body.tracking_url }}{{ trigger.body.tracking_company }}(carrier name){{ etaFormatted }}(from Step 3){{ order.line_items }}(looped in the template to render each item)
Output should be { subject, html, text }. Including a plain-text fallback keeps deliverability scores high.
Step 5: Send the Email
Add a Connector node on resend with the send-email tool. Configure:
from:orders@yourdomain.comto:{{ order.email }}subject:{{ emailBody.subject }}html:{{ emailBody.html }}text:{{ emailBody.text }}tags:[{"name": "type", "value": "shipping_confirmation"}]for analytics
If you're on SMTP instead, use a Connector node on smtp with the send-email tool and the same payload (no tags). The built-in Send Email node is a thin shortcut over the same connectors.
Step 6: Confirm or Alert
Add a Condition node on the send result. On success, the workflow ends. On failure (bounce, invalid address, provider rejection), route to a slack send-message call in your support channel with the order number, customer email, and provider error so the team can reach out by phone or alternative channel.
Tips
- Set
headersfor replies - on Resend, add aReply-Toheader pointing at your support inbox so customer replies don't black-hole. - Tag for analytics - Resend's tags let you measure open/click rates on shipping emails specifically, separate from marketing.
- Batch backfills - if you need to resend yesterday's confirmations, use Resend's
send-batch-emailstool instead of loopingsend-email- one API call instead of N.
Common Pitfalls
- Unverified sending domain - Resend silently rejects emails from unverified domains. Run the
verify-domaintool once during setup and confirm the SPF and DKIM records are live. - Webhook duplicates - fulfillment webhooks can fire twice on partial shipments. Key the email on
fulfillment.idand either store it in a small mongodb collection or rely on Spojit's per-trigger dedupe to avoid sending twice. - Tracking URL missing - some carriers populate
tracking_numberwithouttracking_url. Build a fallback URL by carrier code in Step 4 so the email still has a click-through. - HTML rendering in Outlook - flexbox and modern CSS break in Outlook. Stick to table layouts and inline styles in the template.
Testing
Fulfill a small test order in your store with your own email on the customer record. Confirm the email lands, the tracking link works, and the ETA reads sensibly. Then check the Resend dashboard (or your SMTP logs) for the delivery event. Once that round-trip looks right, leave the webhook subscribed.