> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shoppex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Email Templates and Variables

> Change the subject and text of the emails buyers get from your store, and see which variables each email can use.

Shoppex sends your buyers an email when they order, pay, receive their items, or when a payment runs into trouble, and for subscriptions, gifts, licenses, warranties and your reseller program. Every email has a default design with your shop name and logo, drawn in [your Brand](#your-brand). You can change the subject and the body of the emails listed under **Storefront → Buyer Emails** (`/store/emails`). The list is grouped by topic, and each row says whether the email sends and which switch decides.

## Customize an email

1. Open **Store → Emails** and click an email.
2. Pick the **Language** you want to write in. See [Languages](#languages).
3. Change the **Subject** and the **Body**. The body is the part between the header and the footer, in HTML. Write `{{variable}}` where order details go, for example `{{invoice_id}}`. Click a variable in the **Variables** panel to insert it at the cursor.
4. Check the **Preview**. It renders on the server with sample data from your shop and shows the whole email: your body inside your Brand's header and footer.
5. Click **Save Email**.

Your logo, colors, fonts and footer are not part of the body: they come from [your Brand](#your-brand) and wrap every email, customized or not. A Brand change or a Shoppex design update of the header and footer reaches your customized emails too. **Reset** returns the open language to the current default body and deletes your version in that language.

**Send Test** sends your draft in the open language to your verified account email, with sample data. Bounced or complained addresses cannot receive tests. Each shop can send 5 test emails per hour.

Things to know about the body:

* A variable is written `{{name}}`. A variable the email does not receive stays in the email as written, so copy names from the table below. Values go in as they are: a shop name that contains `{{…}}` is not filled in again.
* Save only the body. A whole HTML document (`<html>`, `<head>`, `<body>` or a doctype) is refused, and so is an empty body.
* Shoppex removes `<script>` tags, `on…` event attributes, and `javascript:` links when you save. A body longer than 512 KB is cut off, and the preview refuses it.
* The **Customer Sign-in Code** must show `{{code}}` as visible text, written exactly like that.
* The **Reseller Invitation** must contain `{{accept_url}}` in a link or in the text, not only in an HTML comment. It is the one-time link that lets the reseller join.
* Text that someone typed is HTML-escaped: the buyer's address and the tracking code in the **Shipping Confirmation**, a gift message, your note on a warranty decision, a reason you give for declining a reseller, and the names and links in the subscription, gift, license, warranty, reseller, refund, partial payment and resent-order emails. Line breaks become `<br>`. A missing tracking code, renewal date or gift recipient shows as a dash.
* A **block** (the Blocks column below) is a part of the email that only shows for some orders, such as the rows of a details table, a note you wrote, or the delivered goods. Shoppex fills it in ready-made when it sends the email, and leaves it empty when there is nothing to show. Move or delete a block like any other variable, but you cannot change what is inside.
* The **Delivery Email**, **Order Details Resent** and **Gift Received** emails carry the purchased keys, files and instructions in the `{{delivery_content_html}}` block, which shows only what the order has. The Delivery Email and Order Details Resent also offer each kind on its own as a `{{delivery_…}}` variable. If your body has none of them, Shoppex adds the delivery block at the end of the body, so the buyer always gets what they paid for. The gift recipient has no order page, so **Gift Received** gets the goods added unless your body has `{{delivery_content_html}}` itself.
* The **Plain Text** field is the plain text of your body, for inboxes that block HTML. Shoppex adds the shop name above it and the footer below it. Write `{{variable}}` there too. Leave it empty and Shoppex builds it from your body. In the **Delivery Email**, **Order Details Resent** and **Gift Received**, plain text without any delivery variable gets the goods added at the end, like the body. In the **Customer Sign-in Code**, the plain text must show `{{code}}` on its own, never inside a link, and `{{sign_in_url}}` only on its own. In the **Reseller Invitation**, it must contain `{{accept_url}}`.

## Your logo

Every email shows your shop logo next to the shop name at the top, customized or not. The logo is the image you set as your shop avatar. If your shop has no logo, the email shows your shop name only.

## Your Brand

The Brand sets the accent color, button shape, fonts and footer text of the emails buyers get from your store. Open it with the **Brand** row on **Store → Emails**, or from **Settings → Branding → Email Brand** (`/store/emails/brand`). You need the Design permission to change it.

| Setting | What it changes |
| - | - |
| **Accent Color** | Links in the email. Buttons too, unless you turn on **Own Button Color**. |
| **Button Shape** | Sharp, Rounded or Pill buttons. The button text turns dark or white, whichever reads better on the button color. |
| **Headings** and **Text** | The fonts: Geist, Inter, Manrope, Plus Jakarta Sans, DM Sans, Space Grotesk, Sora, IBM Plex Sans, Arial or System UI. Email apps that block web fonts, like Gmail and Outlook, show a similar system font. |
| **Own Button Color** | Email buttons in a color other than your accent color. |
| **Footer Text** | Plain text above "Powered by Shoppex", up to 4 lines and 300 characters. HTML is refused. |

The preview next to the settings shows a sample order email with your changes before you save. A store that never saved a Brand sends the Shoppex design. The Brand changes buyer emails only; your own order notices and Shoppex account emails keep the Shoppex design.

### The Brand in customized emails

A customized email gets the header, fonts, footer text and "Powered by Shoppex" line from your Brand when it is sent, like the default. Inside the body, three variables carry the Brand colors:

| Variable | Value |
| - | - |
| `{{brand_color}}` | Your accent color, for example `#0f766e`. |
| `{{button_color}}` | The email button color: **Own Button Color**, or the accent color. |
| `{{button_text_color}}` | `#ffffff` or `#18181b`, whichever reads better on the button color. |

A body you start customizing uses these variables for its buttons and links, so later color changes reach it. The fonts and the button shape inside the body are written in as they are when you start; after you change them, click **Reset** to get the current ones.

<Note>
  Emails you customized before bodies were stored apart from the layout are moved to the new model by Shoppex. Until yours has moved, buyers get the Shoppex default of that email, and the editor says so. Saving the email in the editor replaces your earlier version.
</Note>

## Languages

The default emails go out in the buyer's language, the language they used at checkout. Shoppex translates their subjects, headings, buttons and labels into German, Spanish, French, Italian, Dutch, Portuguese, Polish, Russian, Finnish, Lithuanian, Turkish and Chinese; some longer sentences stay in English. Other languages get English. For a fully translated email, customize it in that language.

Each language has its own customized version. Pick it under **Language** at the top of the editor. The list next to each language shows **Customized** or **Default**. A language you open for the first time starts from the Shoppex default in that language.

Which version a buyer gets:

1. Your version in the buyer's language, if you saved one.
2. Otherwise your English version, if you saved one.
3. Otherwise the Shoppex default in the buyer's language.

So after you customize English, buyers in German get your English version until you customize German too. The editor tells you when this applies. Emails you customized before languages existed are English versions and keep going to every buyer as before.

Blocks are in English in every version, so a German version shows English labels inside its blocks. The list under **Buyer Emails** shows the English version, and its **Reset to Default** works on English. It shows only on emails with an edited English version. Send tests from the editor.

## Turn emails on or off

Three switches at the top of **Buyer Emails** turn groups of order emails on or off. A switch acts at once, and **Undo** in the confirmation puts it back.

| Switch | Emails |
| - | - |
| **Order Placed** | Invoice Created |
| **Payment Received** | Developer API completion notice, Gift Sent (the buyer's receipt for a gift), Invoice Refunded, Subscription Created, Subscription Paid, Subscription Renewed |
| **Payment Problems** | Invoice Cancelled, Partial Payment, Subscription Payment Failed, Subscription Cancelled |

These emails do not depend on the switches:

* **Delivery** and **Gift Received** carry the goods and bypass the three switches and buyer notification opt-outs. Developer API completion notices carry no goods and still follow **Payment Received** and buyer preferences.
* **Shipping Confirmation**. You decide per shipment with **Notify customer by email**. See [Physical products](/selling/physical-products#emails).
* **Customer Sign-in Code**, sent when a buyer signs in to your store.
* **Abandoned Cart**. See [Abandoned carts](/selling/abandoned-checkouts#email-template).
* **Feedback Review Request** and **Back in Stock** have their own settings.
* **Subscription Trial Ending** and **Subscription Renewal Reminder**, which tell the buyer about a coming charge.
* **License Expiry Reminder**, the **Warranty** emails and the **Reseller** emails.
* Replies to a buyer's question or review, and **Reward Granted Customer**.
* Emails you send yourself, such as **Order Details Resent**.

Buyer opt-outs stop order notifications and receipts, including Developer API completion notices. They do not stop delivery emails with goods or the steps needed to receive them. Explicit send suppression and bounce/complaint blocking still apply. Headless orders also follow their separate order-email settings; gift-recipient delivery is exempt from that policy.

## Changelog

* **September 28, 2026:** Delivery emails now bypass **Payment Received** and buyer notification opt-outs so buyers can receive their goods. Receipts and Developer API completion notices still respect both preferences. Test emails can only go to your verified account email, subject to bounce/complaint blocking and the shop's five-per-hour limit.

## Variables per email

Each row lists the variables the editor offers for that email and the ones its default design uses, and the email's blocks. `{{shop_name}}` is your store name. Every email also gets the three [Brand variables](#the-brand-in-customized-emails), which the table leaves out. A few emails receive more; the [Shipping Confirmation](/selling/physical-products#emails) is one.

Some variables are empty for some orders, for example `{{customer_name}}` when the buyer gave no name. Stored templates have no conditions, so write your text so that it reads well without them.

| Email | Key | Variables | Blocks |
| - | - | - | - |
| Abandoned Cart | `abandoned_cart` | `{{cart_items}}`, `{{cart_total}}`, `{{cta_label}}`, `{{cta_url}}`, `{{currency}}`, `{{email_subject}}`, `{{offer_discount_code}}`, `{{offer_headline}}`, `{{shop_name}}`, `{{unsubscribe_url}}` | — |
| Back in Stock | `back_in_stock` | `{{product_title}}`, `{{product_url}}`, `{{shop_name}}`, `{{unsubscribe_url}}` | `{{details_html}}` |
| Customer Sign-in Code | `customer_sign_in_otp` | `{{code}}`, `{{expires_minutes}}`, `{{shop_name}}`, `{{sign_in_url}}` | — |
| Delivery | `order_completed_customer` | `{{currency}}`, `{{delivery_download_links_text}}`, `{{delivery_dynamic_response}}`, `{{delivery_external_links_text}}`, `{{delivery_license_keys_text}}`, `{{delivery_serials_count}}`, `{{delivery_serials_html}}`, `{{delivery_service_text}}`, `{{delivery_text}}`, `{{delivery_tracking_codes_text}}`, `{{invoice_id}}`, `{{invoice_url}}`, `{{payment_method}}`, `{{product_title}}`, `{{shop_name}}`, `{{total}}` | `{{delivery_content_html}}`, `{{delivery_intro}}` |
| Feedback Review Request | `feedback_review_request` | `{{invoice_id}}`, `{{product_title}}`, `{{review_url}}`, `{{shop_name}}` | — |
| Gift Received | `gift_received_customer` | `{{invoice_id}}`, `{{product_title}}`, `{{shop_name}}` | `{{delivery_content_html}}`, `{{details_html}}`, `{{gift_message_html}}`, `{{sender_label}}` |
| Gift Sent | `gift_sent_customer` | `{{gift_recipient_email}}`, `{{invoice_id}}`, `{{invoice_url}}`, `{{product_title}}`, `{{shop_name}}` | `{{details_html}}` |
| License Expiry Reminder | `license_expiry_reminder` | `{{expiry_date}}`, `{{license_key}}`, `{{portal_url}}`, `{{product_title}}`, `{{renewal_available}}` | `{{renewal_cta_label}}`, `{{renewal_intro}}` |
| Order Cancelled | `invoice_cancelled` | `{{currency}}`, `{{invoice_id}}`, `{{product_title}}`, `{{shop_name}}`, `{{total}}` | — |
| Order Details Resent | `invoice_resend` | `{{currency}}`, `{{delivery_download_links_text}}`, `{{delivery_dynamic_response}}`, `{{delivery_external_links_text}}`, `{{delivery_license_keys_text}}`, `{{delivery_serials_count}}`, `{{delivery_serials_html}}`, `{{delivery_service_text}}`, `{{delivery_text}}`, `{{delivery_tracking_codes_text}}`, `{{invoice_id}}`, `{{invoice_url}}`, `{{product_title}}`, `{{shop_name}}`, `{{total}}` | `{{delivery_content_html}}` |
| Order Placed | `invoice_created` | `{{currency}}`, `{{invoice_id}}`, `{{invoice_url}}`, `{{product_title}}`, `{{shop_name}}`, `{{total}}` | — |
| Partial Payment | `partial_payment_customer` | `{{crypto_amount}}`, `{{crypto_received}}`, `{{invoice_id}}`, `{{invoice_url}}`, `{{percent_paid}}`, `{{shop_name}}` | — |
| Refund Receipt | `invoice_refunded` | `{{currency}}`, `{{invoice_id}}`, `{{product_title}}`, `{{shop_name}}`, `{{total}}` | `{{refund_amount_label}}`, `{{refund_timing}}` |
| Reseller Application Approved | `reseller_application_approved` | `{{portal_url}}`, `{{shop_name}}` | `{{details_html}}` |
| Reseller Application Declined | `reseller_application_rejected` | `{{shop_name}}` | `{{details_html}}` |
| Reseller Invitation | `reseller_invite` | `{{accept_url}}`, `{{shop_name}}` | `{{expiry_note}}`, `{{invitation_intro}}` |
| Reseller Tier Reached | `reseller_tier_advanced` | `{{portal_url}}`, `{{shop_name}}`, `{{tier_name}}` | `{{details_html}}` |
| Review Reply | `feedback_replied` | `{{feedback_id}}`, `{{feedback_message}}`, `{{feedback_rating}}`, `{{order_id}}`, `{{product_name}}`, `{{reply_message}}` | — |
| Reward Granted | `reward_granted_customer` | `{{portal_url}}`, `{{reward_name}}`, `{{reward_value}}` | `{{reward_details_html}}` |
| Shipping Confirmation | `order_shipped_customer` | `{{invoice_id}}`, `{{invoice_url}}`, `{{shipping_address}}`, `{{shop_name}}`, `{{tracking_code}}` | — |
| Subscription Cancelled | `subscription_cancelled` | `{{product_title}}`, `{{shop_name}}`, `{{subscription_id}}` | — |
| Subscription Created | `subscription_created` | `{{product_title}}`, `{{shop_name}}`, `{{subscription_id}}` | — |
| Subscription Paid | `subscription_paid` | `{{currency}}`, `{{invoice_id}}`, `{{product_title}}`, `{{shop_name}}`, `{{subscription_id}}`, `{{total}}` | — |
| Subscription Payment Failed | `subscription_payment_failed` | `{{product_title}}`, `{{shop_name}}`, `{{subscription_id}}` | — |
| Subscription Renewal Reminder | `subscription_renewal_reminder` | `{{product_title}}`, `{{renewal_date}}`, `{{shop_name}}`, `{{subscription_id}}` | — |
| Subscription Renewed | `subscription_renewed` | `{{currency}}`, `{{product_title}}`, `{{renewal_date}}`, `{{shop_name}}`, `{{subscription_id}}`, `{{total}}` | — |
| Subscription Trial Ending | `subscription_trial_ending` | `{{product_title}}`, `{{shop_name}}`, `{{subscription_id}}`, `{{trial_end}}` | — |
| Support Reply | `query_replied` | `{{query_id}}`, `{{query_title}}`, `{{reply_message}}`, `{{ticket_url}}` | — |
| Warranty Claim Approved | `warranty_claim_approved_customer` | `{{order_uniqid}}`, `{{portal_url}}`, `{{product_title}}`, `{{shop_name}}` | `{{message_html}}` |
| Warranty Claim Declined | `warranty_claim_denied_customer` | `{{order_uniqid}}`, `{{portal_url}}`, `{{product_title}}`, `{{shop_name}}` | `{{message_html}}` |
| Warranty Expiring | `warranty_expiring_customer` | `{{expires_at}}`, `{{order_uniqid}}`, `{{portal_url}}`, `{{product_title}}`, `{{shop_name}}` | — |

### Locked emails

Shoppex manages these emails itself. You cannot customize, preview or reset them, because they carry statements about payment and account security that must stay exactly as written:

* `order_completed_pending_custom_fields_customer`: Sent after payment when the buyer still has to fill in your custom fields before delivery.
* `order_completed_manual_api_customer`: Sent when you complete an order through the Developer API. It says that Shoppex did not verify the payment.
* `order_completed_merchant`: Your own notice of a completed order.
* `feedback_appeal_decided`: Tells you whether Shoppex upheld or declined your appeal of a review, with Shoppex's note when there is one. An upheld appeal hides the review and revokes its points and unspent reward.
* `reward_rules_paused_merchant`: Notifies you that every-order reward rules are paused and asks you to review them in Loyalty & Rewards. Existing grants remain available.
* `referral_payout_status`: Tells you whether Shoppex completed or refused your referral payout, with the transaction reference or refusal reason.
* `auth_discord_link_confirmation`: Asks a buyer to allow Discord sign-in for their customer account.
* `wallet_otp`: The code a buyer enters to pay with their store credit. It tells them not to share it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.