Skip to main content
RapidDev - Software Development Agency
API AutomationsShopifyBearer Token

How to Automate Shopify Customer Emails using the API

Shopify does not send emails via its own API — pair the GraphQL `customers` query and `customers/create` webhook with an external ESP (SendGrid, Resend) to automate customer emails. Query customer segments using tags and order history, manage opt-in consent with `customerEmailMarketingConsentUpdate`, then trigger personalized sends via your ESP. GraphQL budget on Standard plans: 1,000 points, 50 pts/sec restore.

Need help automating? Talk to an expert
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read15-30 minutesShopifyMay 2026RapidDev Engineering Team
TL;DR

Shopify does not send emails via its own API — pair the GraphQL `customers` query and `customers/create` webhook with an external ESP (SendGrid, Resend) to automate customer emails. Query customer segments using tags and order history, manage opt-in consent with `customerEmailMarketingConsentUpdate`, then trigger personalized sends via your ESP. GraphQL budget on Standard plans: 1,000 points, 50 pts/sec restore.

API Quick Reference

Auth

OAuth 2.0 / Access Token

Rate limit

1,000-point bucket, 50 pts/sec restore

Format

JSON

SDK

Available

Understanding Shopify Customer Emails via the API

Shopify's Admin API gives you full access to customer data — email addresses, tags, order history, and marketing consent status — but it does not provide an endpoint to send emails directly. Shopify Email (the native feature) is limited to 10,000 free emails/month and offers no programmable API access. For custom automated email flows, you must export customer data from Shopify and deliver emails through an external Email Service Provider (ESP).

The automation flow uses Shopify webhooks (`customers/create`, `orders/create`) to detect trigger events in real time, then queries the GraphQL `customers` object to fetch full customer data and context (recent orders, tags, lifetime value). This data is sent to your ESP (SendGrid, Resend, Mailchimp, etc.) to trigger a pre-built email template.

For GDPR compliance and customer trust, check `emailMarketingConsent` before adding customers to marketing lists — only customers with `subscribed` consent status should receive marketing emails. Transactional emails (order confirmations, shipping notifications) do not require marketing consent. See https://shopify.dev/docs/api/admin-graphql/2026-04/objects/Customer for the full customer object reference.

Base URLhttps://{shop}.myshopify.com/admin/api/2026-04/graphql.json

Setting Up Shopify API Authentication for Customer Emails

This automation needs read access to customer data and the ability to update email marketing consent. Create a custom app via the Shopify Dev Dashboard with `read_customers` and `write_customers` scopes. You will also need an API key from your ESP (SendGrid, Resend, etc.) stored separately in environment variables.

  1. 1Go to dev.shopify.com and log in with your Partner account.
  2. 2Click 'Create app', choose 'Custom app' for single-store automation.
  3. 3Under 'Admin API access scopes', enable: read_customers, write_customers, read_orders.
  4. 4Click 'Save', then 'Install app' and copy the generated access token.
  5. 5Store Shopify token in environment variable: export SHOPIFY_ACCESS_TOKEN='shpat_...'
  6. 6Also store your ESP API key: export SENDGRID_API_KEY='SG...'
  7. 7Register webhooks for customers/create and orders/create via the `webhookSubscriptionCreate` GraphQL mutation.
auth.py
1import os
2import requests
3
4SHOP_DOMAIN = os.environ['SHOPIFY_SHOP_DOMAIN']
5ACCESS_TOKEN = os.environ['SHOPIFY_ACCESS_TOKEN']
6
7GRAPHQL_URL = f'https://{SHOP_DOMAIN}/admin/api/2026-04/graphql.json'
8HEADERS = {
9 'X-Shopify-Access-Token': ACCESS_TOKEN,
10 'Content-Type': 'application/json',
11}
12
13# Test: fetch first 3 customers
14query = '{ customers(first: 3) { edges { node { id email displayName emailMarketingConsent { marketingState } } } } }'
15resp = requests.post(GRAPHQL_URL, json={'query': query}, headers=HEADERS)
16print(resp.json())

Security notes

  • Store all API keys in environment variables — both Shopify token and ESP key.
  • Validate webhook HMAC using base64(HMAC-SHA256(rawBody, appSecret)) before processing any webhook payload.
  • Never send marketing emails to customers with emailMarketingConsent.marketingState other than 'SUBSCRIBED'.
  • Customer email addresses are PII — do not log them in plain text in production logs.
  • Use HTTPS endpoints for all webhooks.
  • Rate-limit your ESP calls to avoid triggering spam filters from burst sends.

Key endpoints

POST/admin/api/2026-04/graphql.json

GraphQL query for `customers` — fetch customers with their email, tags, marketing consent, and order history for segmentation.

ParameterTypeRequiredDescription
querystringoptionalShopify search query for filtering (e.g., 'tag:vip', 'email_marketing_consent_state:subscribed', 'orders_count:>5')
firstnumberrequiredNumber of customers per page (max 250)

Request

json
1{"query": "{ customers(first: 50, query: \"tag:vip AND email_marketing_consent_state:subscribed\") { edges { node { id email displayName tags numberOfOrders totalSpentV2 { amount currencyCode } emailMarketingConsent { marketingState } } } pageInfo { hasNextPage endCursor } } }"}

Response

json
1{"data": {"customers": {"edges": [{"node": {"id": "gid://shopify/Customer/11223344", "email": "jane@example.com", "displayName": "Jane Smith", "tags": ["vip"], "numberOfOrders": 12, "totalSpentV2": {"amount": "458.75", "currencyCode": "USD"}, "emailMarketingConsent": {"marketingState": "SUBSCRIBED"}}}], "pageInfo": {"hasNextPage": false}}}}
POST/admin/api/2026-04/graphql.json

GraphQL mutation `customerEmailMarketingConsentUpdate` — updates a customer's email marketing consent status. Required before adding to marketing lists.

ParameterTypeRequiredDescription
customerIdstringrequiredCustomer global ID
marketingStatestringrequiredSUBSCRIBED, UNSUBSCRIBED, PENDING, INVALID, NOT_SUBSCRIBED

Request

json
1{"query": "mutation customerEmailMarketingConsentUpdate($input: CustomerEmailMarketingConsentUpdateInput!) { customerEmailMarketingConsentUpdate(input: $input) { customer { id emailMarketingConsent { marketingState } } userErrors { field message } } }", "variables": {"input": {"customerId": "gid://shopify/Customer/11223344", "emailMarketingConsent": {"marketingState": "SUBSCRIBED", "marketingOptInLevel": "SINGLE_OPT_IN", "consentUpdatedAt": "2026-04-15T10:00:00Z"}}}}

Response

json
1{"data": {"customerEmailMarketingConsentUpdate": {"customer": {"id": "gid://shopify/Customer/11223344", "emailMarketingConsent": {"marketingState": "SUBSCRIBED"}}, "userErrors": []}}}
POST/admin/api/2026-04/graphql.json

GraphQL mutation `webhookSubscriptionCreate` — registers webhooks for customers/create and orders/create events.

ParameterTypeRequiredDescription
topicstringrequiredCUSTOMERS_CREATE or ORDERS_CREATE

Request

json
1{"query": "mutation { webhookSubscriptionCreate(topic: CUSTOMERS_CREATE, webhookSubscription: {callbackUrl: \"https://yourapp.com/webhooks/customers-create\", format: JSON}) { userErrors { field message } webhookSubscription { id } } }"}

Response

json
1{"data": {"webhookSubscriptionCreate": {"userErrors": [], "webhookSubscription": {"id": "gid://shopify/WebhookSubscription/445566"}}}}

Step-by-step automation

1

Register Webhooks for Customer and Order Events

Why: Webhooks give you real-time triggers for the most valuable email moments: new customer signup and post-purchase.

Register `CUSTOMERS_CREATE` for welcome email sequences and `ORDERS_CREATE` for post-purchase follow-ups. Your endpoint must respond within 5 seconds — queue email processing asynchronously.

request.sh
1# Register customers/create webhook
2curl -X POST 'https://mystore.myshopify.com/admin/api/2026-04/graphql.json' \
3 -H 'X-Shopify-Access-Token: shpat_your_token' \
4 -H 'Content-Type: application/json' \
5 -d '{"query": "mutation { webhookSubscriptionCreate(topic: CUSTOMERS_CREATE, webhookSubscription: {callbackUrl: \\"https://yourapp.com/webhooks/customers-create\\", format: JSON}) { userErrors { field message } webhookSubscription { id } } }"}'

Pro tip: For the orders/create webhook, filter for first-time buyers in your handler (`order.customer.orders_count === 1`) to differentiate between first-purchase and repeat-purchase email sequences.

Expected result: Two webhook subscriptions created — one for new customer signups, one for new orders.

2

Fetch Customer Data and Check Marketing Consent

Why: You need full customer context (order history, tags, LTV) to personalize the email, and must verify marketing consent before sending marketing messages.

When a webhook fires with a customer ID, query the GraphQL `customer` object to enrich the data. Check `emailMarketingConsent.marketingState` — only send marketing emails to customers with state `SUBSCRIBED`. Transactional emails (welcome, order confirmation) can go to all customers regardless of marketing consent.

request.sh
1curl -X POST 'https://mystore.myshopify.com/admin/api/2026-04/graphql.json' \
2 -H 'X-Shopify-Access-Token: shpat_your_token' \
3 -H 'Content-Type: application/json' \
4 -d '{"query": "{ customer(id: \\"gid://shopify/Customer/11223344\\") { id email displayName firstName tags numberOfOrders totalSpentV2 { amount currencyCode } emailMarketingConsent { marketingState } orders(first: 1, sortKey: CREATED_AT, reverse: true) { edges { node { id name totalPriceV2 { amount } } } } } }"}'

Pro tip: Cache customer data for 30 minutes if you're sending multi-step sequences — fetching the full customer object on each step is wasteful.

Expected result: Full customer object with marketing consent status. Use `isSubscribed` flag to gate marketing email delivery.

3

Send Personalized Email via External ESP

Why: Shopify has no email sending API — you must route through SendGrid, Resend, Mailchimp, or similar to actually deliver the email.

Use the customer data from Step 2 to build a personalized email payload and send via your ESP's API. The example uses SendGrid's `POST /v3/mail/send`. For Resend users, the endpoint is `POST https://api.resend.com/emails`. Use dynamic template IDs and pass Shopify customer data as template variables.

request.sh
1# SendGrid dynamic template email
2curl -X POST 'https://api.sendgrid.com/v3/mail/send' \
3 -H 'Authorization: Bearer $SENDGRID_API_KEY' \
4 -H 'Content-Type: application/json' \
5 -d '{
6 "from": {"email": "hello@yourstore.com", "name": "Your Store"},
7 "personalizations": [{
8 "to": [{"email": "jane@example.com", "name": "Jane"}],
9 "dynamic_template_data": {
10 "first_name": "Jane",
11 "orders_count": 12,
12 "total_spent": "458.75"
13 }
14 }],
15 "template_id": "d-your-sendgrid-template-id"
16 }'

Pro tip: For Resend (modern alternative to SendGrid), use `POST https://api.resend.com/emails` with `{ from, to, subject, react }` — it's simpler and cheaper at low volumes (free tier: 3,000 emails/month).

Expected result: SendGrid returns HTTP 202 Accepted when the email is queued for delivery. The customer receives the personalized welcome email within seconds.

4

Segment and Batch Win-Back Campaigns

Why: Beyond real-time triggers, you can query Shopify for churned customers to send targeted re-engagement campaigns on a scheduled basis.

Use the `customers` GraphQL query with filter parameters to find customers who haven't ordered in 90+ days but were previously active. Paginate through results and batch-send via your ESP. Check `emailMarketingConsent.marketingState === 'SUBSCRIBED'` before including in any marketing campaign.

request.sh
1# Query customers with marketing consent who haven't ordered in 90 days
2curl -X POST 'https://mystore.myshopify.com/admin/api/2026-04/graphql.json' \
3 -H 'X-Shopify-Access-Token: shpat_your_token' \
4 -H 'Content-Type: application/json' \
5 -d '{"query": "{ customers(first: 100, query: \\"email_marketing_consent_state:subscribed AND last_order_date:<2026-01-07\\") { edges { node { id email firstName numberOfOrders } } pageInfo { hasNextPage endCursor } } }"}'

Pro tip: Rate-limit your ESP sends when batching large segments — SendGrid has a 600 emails/minute limit on free plans. Use a delay of 100ms between sends to stay within limits.

Expected result: Paginated list of subscribers who haven't purchased in 90+ days, ready for win-back campaign sends.

Complete working code

This script handles the full welcome email flow: receives the `customers/create` webhook, validates the HMAC, fetches enriched customer data, checks marketing consent, and sends a personalized welcome email via SendGrid.

automate_shopify_emails.py
1import os, hmac, hashlib, base64, logging, requests
2from flask import Flask, request, abort
3
4logging.basicConfig(level=logging.INFO)
5app = Flask(__name__)
6
7SHOP_DOMAIN = os.environ['SHOPIFY_SHOP_DOMAIN']
8ACCESS_TOKEN = os.environ['SHOPIFY_ACCESS_TOKEN']
9APP_SECRET = os.environ['SHOPIFY_APP_SECRET']
10SENDGRID_KEY = os.environ['SENDGRID_API_KEY']
11TEMPLATE_ID = os.environ['SENDGRID_WELCOME_TEMPLATE_ID']
12
13SHOPIFY_URL = f'https://{SHOP_DOMAIN}/admin/api/2026-04/graphql.json'
14SHOPIFY_HEADERS = {'X-Shopify-Access-Token': ACCESS_TOKEN, 'Content-Type': 'application/json'}
15
16def gql(query):
17 resp = requests.post(SHOPIFY_URL, json={'query': query}, headers=SHOPIFY_HEADERS)
18 resp.raise_for_status()
19 return resp.json()
20
21def get_customer(customer_id):
22 q = f'{{ customer(id: "gid://shopify/Customer/{customer_id}") {{ id email firstName numberOfOrders totalSpentV2 {{ amount currencyCode }} emailMarketingConsent {{ marketingState }} }} }}'
23 return gql(q)['data']['customer']
24
25def send_email(customer):
26 payload = {
27 'from': {'email': 'hello@yourstore.com'},
28 'personalizations': [{
29 'to': [{'email': customer['email'], 'name': customer.get('firstName', '')}],
30 'dynamic_template_data': {
31 'first_name': customer.get('firstName', 'there'),
32 'total_spent': customer.get('totalSpentV2', {}).get('amount', '0')
33 }
34 }],
35 'template_id': TEMPLATE_ID
36 }
37 resp = requests.post('https://api.sendgrid.com/v3/mail/send', json=payload, headers={'Authorization': f'Bearer {SENDGRID_KEY}'})
38 return resp.status_code == 202
39
40@app.route('/webhooks/customers-create', methods=['POST'])
41def customer_created():
42 hmac_header = request.headers.get('X-Shopify-Hmac-Sha256', '')
43 computed = base64.b64encode(hmac.new(APP_SECRET.encode(), request.get_data(), hashlib.sha256).digest()).decode()
44 if not hmac.compare_digest(computed, hmac_header):
45 abort(401)
46
47 data = request.get_json()
48 customer_id = data['id']
49 customer = get_customer(customer_id)
50
51 if not customer or not customer.get('email'):
52 return '', 200
53
54 # Always send transactional welcome (no consent check needed)
55 success = send_email(customer)
56 logging.info(f'Welcome email for {customer_id}: {"sent" if success else "failed"}')
57 return '', 200
58
59if __name__ == '__main__':
60 app.run(port=3000)

Error handling

202SendGrid: emails bounced (hard bounce logged in Activity)
Cause

Email address is invalid, domain doesn't exist, or the recipient server permanently rejected the message.

Fix

Subscribe to SendGrid's Event Webhook to receive bounce notifications. On hard bounce, update the customer's `emailMarketingConsent` to UNSUBSCRIBED via `customerEmailMarketingConsentUpdate` to comply with email best practices.

Retry strategy

Do not retry hard bounces — the address is invalid. Log and remove from future sends.

429Throttled
Cause

GraphQL point bucket exhausted when batch-querying large customer segments.

Fix

Add a sleep between page fetches during batch operations. Monitor `extensions.cost.throttleStatus.currentlyAvailable` and pause when below 100 points.

Retry strategy

Wait for bucket to restore: `sleep((requestedCost - currentlyAvailable) / 50)` on Standard plans.

403SendGrid: Forbidden — sender identity not verified
Cause

The From email address or domain has not been verified in your SendGrid account.

Fix

Go to SendGrid Settings > Sender Authentication and verify your sending domain or single sender email address. Domain authentication (SPF/DKIM) is required for production sends.

Retry strategy

No retry until domain is verified.

200 with userErrorscustomerId is invalid
Cause

The customer ID from the webhook payload was passed without the `gid://shopify/Customer/` prefix.

Fix

Always wrap numeric IDs in the global ID format: `gid://shopify/Customer/{numeric_id}`. The webhook payload contains numeric IDs; GraphQL queries require global IDs.

Retry strategy

Fix the ID formatting — no retry needed.

401Webhook: HMAC validation failed
Cause

Using hex digest instead of base64, or computing the digest against the parsed JSON body instead of the raw bytes.

Fix

Use `hmac.new(secret.encode(), raw_body_bytes, hashlib.sha256).digest()` and then `base64.b64encode(...)`. Never decode the JSON before computing the HMAC.

Retry strategy

Fix the HMAC computation logic — all future webhooks will fail until corrected.

Rate Limits for Shopify Customer API

ScopeLimitWindow
GraphQL Admin API — Standard plan1,000 pointsRestores at 50 points/second
Customer query cost5-20 points per queryVaries based on fields and connections requested
SendGrid free tier100 emails/dayResets daily; 600 emails/minute rate limit
retry-handler.ts
1import time
2
3def gql_paginate_customers(url, headers, filter_query, max_retries=3):
4 cursor, customers = None, []
5 while True:
6 after = f', after: "{cursor}"' if cursor else ''
7 q = f'{{ customers(first: 100{after}, query: "{filter_query}") {{ edges {{ node {{ id email firstName }} }} pageInfo {{ hasNextPage endCursor }} }} }}'
8 for attempt in range(max_retries):
9 resp = requests.post(url, json={'query': q}, headers=headers)
10 if resp.status_code == 429:
11 time.sleep(2 ** attempt)
12 continue
13 break
14 data = resp.json()['data']['customers']
15 customers.extend(e['node'] for e in data['edges'])
16 available = resp.json().get('extensions', {}).get('cost', {}).get('throttleStatus', {}).get('currentlyAvailable', 1000)
17 if available < 100:
18 time.sleep(2)
19 if not data['pageInfo']['hasNextPage']:
20 break
21 cursor = data['pageInfo']['endCursor']
22 return customers
  • Request only the customer fields you need — each additional connection (orders, addresses) adds query cost.
  • Cache customer segments for scheduled campaigns — don't re-query Shopify for each individual send.
  • Use the `query` parameter to filter customers server-side rather than fetching all and filtering client-side.
  • Add 100ms delays between ESP sends when batch-processing large segments to avoid triggering spam filters.
  • Monitor both Shopify GraphQL quota and ESP daily send limits — either can bottleneck large campaigns.

Security checklist

  • Validate every webhook HMAC using base64(HMAC-SHA256(rawBody)) — never use hex digest.
  • Store both SHOPIFY_ACCESS_TOKEN and SENDGRID_API_KEY in environment variables or a secrets manager.
  • Check emailMarketingConsent.marketingState before adding customers to any marketing list.
  • Never log customer email addresses in plain text production logs.
  • Respect unsubscribe events from your ESP — update customerEmailMarketingConsentUpdate to UNSUBSCRIBED when a customer opts out.
  • Use HTTPS for all webhook callback endpoints.
  • Implement rate limiting on your webhook endpoint to prevent abuse from replay attacks.
  • Honor GDPR/CCPA data deletion requests by responding to Shopify's customers/redact compliance webhook.

Automation use cases

Welcome Email Series

beginner

Send a 3-part welcome sequence to new customers: immediate welcome, product highlights on day 2, and a discount on day 7.

Post-Purchase Follow-Up

beginner

7 days after an order ships, send a review request email with the order details linked from Shopify data.

Win-Back Campaign

intermediate

Weekly cron queries customers who haven't ordered in 90 days and sends a targeted re-engagement offer.

VIP Tier Upgrade Notifications

intermediate

When a customer's total_spent crosses a threshold, add a tag in Shopify and trigger a VIP welcome email.

No-code alternatives

Don't want to write code? These platforms can automate the same workflows visually.

Zapier

Free tier available; Starter $19.99/month

Zapier connects Shopify's new customer event directly to Mailchimp, SendGrid, or ActiveCampaign to send welcome emails without any code.

Pros
  • + Zero code setup
  • + Native Shopify + Mailchimp integration
  • + Easy multi-step flows
Cons
  • - Limited customer data access vs GraphQL
  • - Per-task pricing expensive at scale
  • - No complex segmentation logic

Make (formerly Integromat)

Free tier (1,000 ops/month); Core $9/month

Make supports Shopify webhooks and can send personalized emails via SendGrid or Mailchimp with customer data transformations.

Pros
  • + Affordable for moderate volumes
  • + Visual workflow builder
  • + Better data transformation than Zapier
Cons
  • - Less beginner-friendly
  • - No GraphQL support natively
  • - Limited debugging tools

n8n

Self-hosted free; Cloud Starter €20/month

n8n with the Shopify node and SendGrid/Resend node can handle the full welcome email automation self-hosted.

Pros
  • + Self-hosted for free
  • + Good email node support
  • + Flexible scheduling
Cons
  • - Requires hosting setup
  • - No native GraphQL node
  • - Less documentation

Best practices

  • Shopify does not send emails via API — always use an external ESP (SendGrid, Resend, Mailchimp) for delivery.
  • Distinguish transactional emails (welcome, order confirmation) from marketing emails — only marketing emails require explicit opt-in consent.
  • Check emailMarketingConsent.marketingState === 'SUBSCRIBED' before sending any promotional email.
  • Use the `query` filter parameter when fetching customers for campaigns — avoid pulling all customers and filtering client-side.
  • Build an unsubscribe handler that calls `customerEmailMarketingConsentUpdate` to sync opt-outs back to Shopify.
  • For Shopify Email's built-in 10,000 free monthly emails, use it for simple transactional sends; switch to an ESP when you need custom logic.
  • Test email templates with Shopify's native preview feature before automating sends at scale.
  • Always include an unsubscribe link in marketing emails — CAN-SPAM and GDPR compliance requirement.

Ask AI to help

Copy one of these prompts to get a personalized, working implementation.

ChatGPT / Claude Prompt

I'm building a Shopify customer email automation using the GraphQL Admin API (2026-04). I'm subscribing to the customers/create webhook and sending welcome emails via SendGrid. My problem is: [describe issue]. Here's my webhook handler: [paste code]. The Shopify response I'm seeing is: [paste]. Help me fix this and ensure I'm checking marketing consent correctly before sending marketing vs transactional emails.

Lovable / V0 Prompt

Build a Shopify customer email automation dashboard with Supabase as the backend. It should show recent webhook events (customer created, order created), allow configuring email templates and trigger rules, and display sent email history with open/click rates from SendGrid. Use shadcn/ui with Tailwind CSS. Include a segment preview that calls the Shopify API to show how many customers match each filter.

Frequently asked questions

Can I send emails directly through the Shopify API?

No. Shopify's API does not have an email sending endpoint. Shopify Email (the native feature) is only accessible via the Shopify admin UI, not the API. To automate email sending, you must connect Shopify to an external ESP like SendGrid, Resend, Mailchimp, or Klaviyo. Use Shopify webhooks and the customers GraphQL query to get data, then trigger sends via your ESP's API.

What is the difference between transactional and marketing emails in Shopify?

Transactional emails (order confirmation, shipping notification, password reset) are service communications — they can be sent to all customers regardless of marketing consent. Marketing emails (promotions, newsletters, win-back campaigns) require explicit opt-in. Check `emailMarketingConsent.marketingState === 'SUBSCRIBED'` before sending marketing emails. Sending marketing emails to unsubscribed customers violates CAN-SPAM, GDPR, and CASL.

What happens when I hit the Shopify GraphQL rate limit while querying customers?

You receive HTTP 429 or a GraphQL response with throttling data in `extensions.cost.throttleStatus`. On Standard plans, the 1,000-point bucket restores at 50 pts/sec. For large customer queries with order history included, cost can be 10-20 points per page. Monitor `currentlyAvailable` and sleep when it drops below 100 points. Alternatively, use `bulkOperationRunQuery` for large exports — it has no rate-limit cost.

How do I sync Shopify unsubscribes back from Mailchimp/Klaviyo?

Subscribe to your ESP's unsubscribe webhook. When a customer unsubscribes in your ESP, call Shopify's `customerEmailMarketingConsentUpdate` mutation with `marketingState: UNSUBSCRIBED`. This keeps Shopify's consent record in sync. Example: Klaviyo sends a webhook on profile unsubscribe → your handler calls the Shopify mutation.

Can I use Shopify's built-in flow automation instead?

Shopify Flow (available on Shopify and Shopify Plus plans) handles basic email triggers without code, but uses Shopify Email which is limited to 10,000 free emails/month and lacks advanced personalization. For more than 10,000 emails/month, custom ESP integration, or complex multi-step sequences, the API approach gives you full control.

Is the Shopify API free?

Yes — the Admin API is free for apps installed on Shopify stores. Email delivery costs depend on your ESP: SendGrid is free for 100 emails/day, Resend free for 3,000/month, Mailchimp free for 500 contacts. At scale, ESP costs vary from $15 to $300+/month depending on volume.

Can RapidDev help build a custom Shopify email automation?

Yes. RapidDev has built 600+ apps including complete Shopify customer lifecycle email systems integrated with SendGrid, Klaviyo, and Resend. We handle webhook setup, customer segmentation, ESP integration, and compliance (GDPR opt-in management). Book a free consultation at rapidevelopers.com.

RapidDev

Need this automated?

Our team has built 600+ apps with API automations. We can build this for you.

Book a free consultation

Skip the coding — we'll build it for you

Our experts have built 600+ API automations. From prototype to production in days, not weeks.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.