A Shopify shipping confirmation email with tracking in n8n fires the moment an order is fulfilled, pulling the tracking number and carrier straight from the fulfillment and sending a branded message your customer actually opens. This guide builds the whole workflow: a fulfillment trigger, an order lookup for the customer email, a clean HTML email through Gmail, and a shipment log in Google Sheets. No paid app, no monthly fee, full control over the wording.
What it does
When you mark an order as fulfilled in Shopify and attach a tracking number, Shopify sends its own shipping notification. It works, but it looks like every other Shopify store and you cannot change much about it. This workflow replaces that generic message with one you own end to end.
The flow listens for the fulfillments/create event. As soon as a shipment is created, n8n reads the tracking number, tracking URL, and carrier from the fulfillment, looks up the matching order to get the customer name and email, then sends a branded HTML email through your own Gmail account. Every shipment also gets logged to a Google Sheet so you have a running record of what shipped, when, and with which carrier.
Because the whole thing runs in n8n, you decide the subject line, the tone, the layout, and what extra content rides along, such as a review request link or a discount for the next order.
Why it beats the default
Shopify’s built-in shipping confirmation is fine for a hobby store. Once you care about brand and repeat purchases, its limits show:
- The template lives inside Shopify’s notification editor with rigid Liquid blocks. Real layout changes are painful.
- You cannot easily branch on order value, product type, or destination country to change the message.
- You get no side record of shipments unless you pay for an app or export by hand.
- Adding a post-purchase upsell, a review ask, or a support link means fighting the template.
With n8n you write plain HTML, insert any field you want, and add steps such as a Google Sheets log or a Slack ping to your ops channel without touching Shopify’s editor. You also keep the sending under your own domain through Gmail, which many small stores prefer over Shopify’s shared sending infrastructure.
What you need
- A Shopify store where you can create an app and read orders and fulfillments.
- An n8n instance, either self-hosted (free) or n8n Cloud.
- A Gmail or Google Workspace account for sending, connected to n8n with the Gmail OAuth2 credential.
- A Google Sheet with a header row for the shipment log (optional but recommended).
- Your Shopify connection set up the current way. Follow how to connect Shopify to n8n in 2026 first. It uses the Shopify Dev Dashboard custom-app method and an Admin API access token, which is the only method that still works. The old in-admin custom-app screen was removed.
All API calls in this build target Admin API version 2026-04.
Node-by-node list
- Shopify Trigger — subscribes to the
fulfillments/createtopic. Fires once per shipment, carrying the tracking number, tracking URL, carrier, line items, and the parentorder_id. - IF (has tracking number) — checks that
tracking_numberis not empty. Fulfillments created without a tracking number take the false branch and stop, so customers never get an email with a blank tracking link. - HTTP Request (get order) — a GET to
/admin/api/2026-04/orders/{order_id}.jsonto read the order name, the customer email, and the customer first name. The fulfillment payload alone is not a reliable source for the customer email, so we fetch the order. - Edit Fields (build email data) — normalizes everything into clean fields: recipient email, first name, order name, tracking number, tracking URL, and carrier. This keeps the Gmail node readable.
- Gmail (send confirmation) — sends the branded HTML shipping confirmation to the customer.
- Google Sheets (append log) — writes one row per shipment: date, order name, email, carrier, tracking number.
Step-by-step build
- Create the Shopify Trigger. Add a Shopify Trigger node, select your Shopify credential from the connect guide, and set the topic to
fulfillments/create. Save and activate the workflow later so n8n registers the webhook with Shopify. - Add the IF gate. Connect an IF node. Add one condition: value 1 =
{{ $json.tracking_number }}, operator is not empty. Wire only the true output onward. This drops fulfillments that carry no tracking, such as digital or manual ones. - Look up the order. Add an HTTP Request node. Method GET, URL
https://YOUR-STORE.myshopify.com/admin/api/2026-04/orders/{{ $json.order_id }}.json. Under Query Parameters addfields=name,email,customerto keep the response small. For authentication use your Shopify header-auth credential that sendsX-Shopify-Access-Token. This returns the order name (like #1002), the order email, and the customer object. - Normalize the fields. Add an Edit Fields node (Set). Add string assignments:
to_email={{ $json.email }}first_name={{ $json.customer.first_name }}order_name={{ $json.name }}tracking_number={{ $('Shopify Trigger').item.json.tracking_number }}tracking_url={{ $('Shopify Trigger').item.json.tracking_url }}carrier={{ $('Shopify Trigger').item.json.tracking_company }}
The tracking values come from the trigger node, the customer values from the HTTP Request. Referencing the trigger node by name keeps them intact.
- Compose and send the Gmail message. Add a Gmail node, resource Message, operation Send. Set To to
{{ $json.to_email }}. Set the subject toYour order {{ $json.order_name }} has shipped. In Message, switch to HTML and paste a short template, for example:Hi {{ $json.first_name }}, Good news, order {{ $json.order_name }} is on its way. Carrier: {{ $json.carrier }} Tracking number: {{ $json.tracking_number }} Track it here: {{ $json.tracking_url }} Thanks for shopping with us.Wrap it in your own HTML and inline styles for a branded look. Keep the tracking link visible as text too, so it survives email clients that strip buttons.
- Log the shipment. Add a Google Sheets node, operation Append. Point it at your log sheet and map the columns to
date,order_name,to_email,carrier, andtracking_number. Use{{ $now.toISO() }}for the date. - Activate and test. Turn the workflow on. In Shopify, fulfill a test order and add any tracking number. Within seconds the email should land and a new row should appear in your sheet. Check the IF branch by fulfilling one order without a tracking number, it should send nothing.
Common mistakes
- Reading tracking from the order instead of the fulfillment. The tracking number lives on the fulfillment, which is the trigger payload. Pull it from the Shopify Trigger node, not the HTTP Request response.
- Skipping the IF gate. Manual and digital fulfillments often have no tracking. Without the gate you send emails with an empty tracking link and confuse customers.
- Using an outdated API version. Old version strings return deprecation warnings or drop fields. Keep the URL on
2026-04. - Wrong Gmail scope. If sending fails, reconnect the Gmail credential and make sure the send scope is granted. The Google account you authorize is the one the email comes from.
- Firing on the wrong topic. Use
fulfillments/create, notorders/fulfilledororders/updated. Only the fulfillment event carries tracking cleanly. - Not activating the workflow. Shopify only registers the webhook when the workflow is active. A saved-but-inactive workflow never receives events.
Cost at realistic volume
This build is close to free at small and mid volume:
- Shopify: no extra cost, apps and webhooks are included in every plan.
- n8n: self-hosted is free on your own server. n8n Cloud starts around 20 to 24 dollars a month if you prefer managed hosting, and one email plus one log per shipment is a light load.
- Gmail: free Gmail allows about 500 sends a day, Google Workspace about 2000. A store shipping 20 to 50 orders a day sits well inside the free limit.
- Google Sheets: free.
At 30 shipments a day, that is roughly 900 emails and 900 log rows a month for zero marginal cost on a self-hosted setup. Compare that to shipping-notification apps that charge a monthly fee for the same job with less control.
Ready-to-import template
Want this built for you instead of wiring it by hand? We package tested n8n workflows and set them up on your store. See the done-for-you automation services to get this shipping confirmation flow, plus the Google Sheets log and any branding, installed and running on your account.
FAQ
Does this replace Shopify’s own shipping email?
It runs alongside it. Many stores turn off Shopify’s default shipping confirmation in the notification settings so customers get only your branded n8n version. If you leave both on, the customer receives two emails, so pick one to keep.
Where does the tracking number come from?
Straight from the fulfillment that Shopify creates when you ship an order. The fulfillments/create webhook carries the tracking number, tracking URL, and carrier, so n8n reads them directly without any extra lookup or third-party app.
Can I send from my store domain instead of Gmail?
Yes. Swap the Gmail node for an SMTP node and point it at your provider, or set up Gmail send-as with your domain. The rest of the workflow stays the same. Gmail is used here because it is the fastest free option to get running.
What if an order ships in two packages?
Shopify creates a separate fulfillment for each package, so the workflow fires once per shipment. The customer gets one email per tracking number, which is usually what you want for split shipments. Add an IF branch if you need different wording for partials.
Do I need to know how to code?
No. Every step uses standard n8n nodes with fields you fill in. The only text you write is the email body, which is plain HTML you can copy from the example above and adjust to match your brand and tone.
Related guides
- Connect Shopify to n8n in 2026
- Shopify post-purchase follow-up email in n8n
- Sync Shopify fulfillments to Google Sheets
- Shopify back-in-stock email notifications
- More in the Shopify automation category