Shopify sends a detailed order confirmation email for every purchase, but extracting line items, totals, and fulfillment state from HTML templates across dozens of store themes is fragile work. MailFrame normalizes every Shopify order confirmation into the same typed JSON shape regardless of the store’s branding or template customizations.
It works on order confirmation emails, shipping notification emails, and shipment status update emails — any raw MIME email you send to the API.
Fields MailFrame extracts
| Field | Type | Example | Notes |
|---|---|---|---|
order_number | string | #1001 | Human-readable order identifier including the # prefix |
reference_id | string | gid://shopify/Order/5678901234 | Shopify internal GID when present in email headers |
customer_email | string | alex@example.com | Email address on the order |
customer_name | string | Alex Rivera | Full name as entered at checkout |
total_cents | integer | 8997 | Order total in minor units |
currency | string | usd | ISO 4217, lower-cased |
line_items | array | see output | Each item: title, quantity, price_cents |
shipping_status | enum | shipped | One of pending, shipped, delivered, returned |
fulfillment_status | enum | fulfilled | One of unfulfilled, fulfilled, partial, cancelled |
date | string | 2026-05-21 | Order date normalized to ISO 8601 |
Sample input
A typical Shopify order confirmation email looks like this:
From: orders@myawesomestore.myshopify.com
Subject: Order confirmation #1001 - My Awesome Store
Date: Wed, 21 May 2026 14:22:00 -0500
To: alex@example.com
Hi Alex,
Thank you for your purchase! We're getting your order ready.
Order #1001
Placed on May 21, 2026
Items ordered:
Classic Logo Tee (Size M, Black) x2 $29.99 each
Canvas Tote Bag x1 $14.99
Subtotal: $74.97
Shipping: $4.99 (Standard)
Taxes: $9.99
Total: $89.97 USD
Ship to:
Alex Rivera
123 Maple St
Austin, TX 78701
Payment: Visa ending in 5678
Structured JSON output
{
"order_number": "#1001",
"reference_id": "gid://shopify/Order/5678901234",
"customer_email": "alex@example.com",
"customer_name": "Alex Rivera",
"total_cents": 8997,
"currency": "usd",
"line_items": [
{ "title": "Classic Logo Tee (Size M, Black)", "quantity": 2, "price_cents": 2999 },
{ "title": "Canvas Tote Bag", "quantity": 1, "price_cents": 1499 }
],
"shipping_status": "pending",
"fulfillment_status": "unfulfilled",
"date": "2026-05-21"
}
JSON Schema definition
Every field is validated against the schema before delivery. You can copy this as a starting point and tighten it for your own use case:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "shopify_order",
"type": "object",
"required": ["order_number", "customer_email", "total_cents", "currency", "line_items"],
"properties": {
"order_number": { "type": "string", "pattern": "^#[0-9]+" },
"reference_id": { "type": "string" },
"customer_email": { "type": "string", "format": "email" },
"customer_name": { "type": "string" },
"total_cents": { "type": "integer", "minimum": 0 },
"currency": { "type": "string", "minLength": 3, "maxLength": 3 },
"line_items": {
"type": "array",
"items": {
"type": "object",
"required": ["title", "quantity", "price_cents"],
"properties": {
"title": { "type": "string" },
"quantity": { "type": "integer", "minimum": 1 },
"price_cents": { "type": "integer", "minimum": 0 }
}
}
},
"shipping_status": { "type": "string", "enum": ["pending", "shipped", "delivered", "returned"] },
"fulfillment_status": { "type": "string", "enum": ["unfulfilled", "fulfilled", "partial", "cancelled"] },
"date": { "type": "string", "format": "date" }
}
}
Use-case examples
The parsed Shopify order output fits naturally into common e-commerce workflows:
- Order reconciliation — match
order_numberagainst your internal order system to confirm every storefront order is accounted for. - Fulfillment tracking — monitor
fulfillment_statusandshipping_statuschanges across order confirmations and shipping notifications to drive internal fulfillment pipelines. - Customer analytics — aggregate
total_centsandline_itemsbycustomer_emailto build per-customer spend profiles or lifetime value models. - Inventory impact — sum quantities across
line_itemsto project inventory drawdown from new orders as they arrive. - Cost breakdown — store the raw
line_itemsarray alongsidetotal_centsto track product-level vs aggregate revenue in your data warehouse.
Because the extraction is synchronous and typed, each of these workflows can run inline — parse the email, validate the output, and write to your database in a single request-response cycle.
Parse via the API
POST the raw email (MIME or plain text) to /v1/parse with the schema you want to
extract against:
curl https://api.mailframe.ai/v1/parse \
-H "Authorization: Bearer $MAILFRAME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema": "shopify_order",
"input": { "type": "email", "raw": "<base64-encoded MIME>" }
}'
Prefer automation over manual forwarding? Inbox forwarding — BCC’ing your Shopify
store’s notification email to a unique inbox address MailFrame assigns you — is on the
roadmap. Until it ships, POST the raw email to /v1/parse as shown above.
Planned webhook delivery
Async webhook delivery is in early design. When it ships, MailFrame will POST a signed envelope to your endpoint with an HMAC-SHA256 signature, exponential-backoff retries, a dead-letter queue, replay endpoints, and a delivery dashboard.
The reliable path today is the synchronous
/v1/parseresponse. Signed webhook delivery, DLQ, replay, and the webhook dashboard are planned — gate your critical downstream logic on the synchronous API response returned byPOST /v1/parse.
{
"event": "parse.completed",
"parse_id": "parse_c3d7e9",
"schema": "shopify_order",
"data": {
"order_number": "#1001",
"customer_email": "alex@example.com",
"customer_name": "Alex Rivera",
"total_cents": 8997,
"currency": "usd",
"line_items": [
{ "title": "Classic Logo Tee (Size M, Black)", "quantity": 2, "price_cents": 2999 },
{ "title": "Canvas Tote Bag", "quantity": 1, "price_cents": 1499 }
],
"shipping_status": "pending",
"fulfillment_status": "unfulfilled",
"date": "2026-05-21"
},
"received_at": "2026-05-21T19:22:08Z"
}
Integration tips
Expect schema-validated output
MailFrame validates every extraction against the JSON Schema before returning it. If a required field is missing or a type doesn’t match, the parse returns a validation error instead of malformed data. Your code never needs to check types at runtime.
Handle optional fields gracefully
Fields like reference_id and customer_name depend on the email content and
may not always be present. Your integration should treat optional fields as
nullable and handle missing values — for example, falling back to the sender’s
email domain when no customer name is available.
Send raw email, not a screenshot
The API accepts raw MIME or plain-text email (base64-encoded in the JSON body).
For Shopify emails this means forwarding the actual email content — opening the
.eml file or extracting the raw source from your email provider. Screenshots
and PDF exports are not supported (PDF input is on the roadmap).
Validation checklist
Before using parsed Shopify order data in production:
- Required fields are present —
order_number,customer_email,total_cents,currency, andline_itemsare guaranteed when the parse succeeds. If your workflow depends on optional fields (reference_id,customer_name,shipping_status,fulfillment_status), add explicit null checks. - Currency is consistent — all monetary values are in minor units via
total_cents. Convert to display format (e.g.$89.97) in your UI layer, not before storing. - Line items are non-empty — an order with zero parsed line items may
indicate a Shopify template the parser has not seen before. Gate downstream
processing on
line_items.length > 0. - Dates parse correctly — the
datefield is ISO 8601 (YYYY-MM-DD). Validate that it produces a valid date object in your language of choice. - Enums match your domain model —
shipping_statusandfulfillment_statususe fixed enum values. Map them to your internal status model rather than relying on string comparison against display text. - Test with real emails — Shopify stores use customized templates. Always test against actual emails from the stores you integrate with, not just the sample above. Sign up for a test order on a Shopify store to get a representative input.