Starter
For your first email program.
$192 billed yearly.
20,000 emails / month
Choose Starter- 5 brands · 3 seats
- 5 custom sending domains
- 500 email verifications/month
- $1.50 / 1,000 extra emails
An order confirmation email is a transactional message sent immediately after a purchase, confirming what was bought, what was paid and what happens next. It fires from an order event rather than being written, so its real specification is which fields must resolve and what renders when one is missing at send time.
Concept emails designed for Glossier, Allbirds, Everlane, LEGO and IKEA using the Nitrosend MCP.1
Make one for your brand
Paste it into Claude, ChatGPT, Cursor or any AI with the Nitrosend MCP connected, and put your own website in place of [your website]. Which assistants work?
Using Nitrosend, design and build an order confirmation email for my brand, in the style of the concept emails on https://nitrosend.com/transactional-email/templates/order-confirmation-email My brand's website is [your website]. Read it for my logo, colours, fonts, products and tone of voice. If Nitrosend is not connected yet, read https://nitrosend.com/SKILL.md and follow it to connect the Nitrosend MCP server (https://api.nitrosend.com/mcp), then ask me to sign in or create a free account at app.nitrosend.com. On Claude.ai use claude.ai/directory/nitrosend; in ChatGPT, install the Nitrosend app. Then write and design the email in Nitrosend and send me a test.
The subject line states that the order is confirmed and carries the order number. Recipients search for these months later, so the number belongs in the subject rather than only in the body.
The order reference is the single most important field. It is what a customer quotes to support, what they search for, and what connects the email to every subsequent message about the same purchase.
Every claim here comes out of the order confirmation emails we collected, so you can check the reading against the emails themselves.
Line items show what was ordered, with quantity and price per item. Totals follow: subtotal, shipping, tax and the amount actually charged, which should match the figure on the customer's statement.
The shipping address is repeated back. This is the last practical moment a customer can catch a mistake, and repeating it converts a support call into a self-service correction.
Delivery expectation follows, whether a date or a range. Absence of this field is the largest single driver of "where is my order" contacts, and it is the field most likely to be absent, since it is the one the checkout does not always know.
Payment method appears in truncated form, showing the card type and last four digits rather than anything more.
A support path closes it. For a message about money, somewhere to reply is the difference between a question and a chargeback.
Send it immediately. A confirmation arriving an hour later has already generated the uncertainty it exists to prevent.
Lead with confirmation rather than with branding. The recipient opened this to verify something happened, so the first screen should answer that.
Keep the layout to one column and include a plain-text alternative, which the transactional message endpoint takes as body alongside the html. Some clients render only the text part, and an image-only confirmation carries no information at all when images are blocked.
State amounts in the currency charged, and include the tax breakdown where the jurisdiction requires it, since this message frequently serves as the customer's receipt for accounting purposes.
Nobody writes an order confirmation. A checkout commits, something emits an order event, and the message renders from it. So the interesting part of an order confirmation template is not its layout, it is the contract between the thing that emits the event and the thing that renders the email.
On our side that contract is an explicit envelope. Your application stays the source of truth, and the Nitrosend Events API documents the boundary plainly: Nitrosend "does not inspect your database or infer an event schema from Supabase, Postgres, or another data store." You post the event, and the flow triggered by it renders the confirmation.
The contact has to exist in the brand before the event arrives, identified by contact_id or contact_email. An order event for an address Nitrosend has never seen does not create the customer on the way past.
Then the part that only matters because a machine is doing the sending. Send the event with an Idempotency-Key header. The first request returns 201 Created. Replaying the same event name and key for the brand returns the existing event with 200 OK rather than starting the flow a second time. The docs are specific about where the key comes from, which is "an immutable source event ID". A key is never reused for changed data.
The reason that header has to exist is in the HTTP specification rather than in anything we invented. RFC 9110 defines an idempotent method as one where the intended effect of multiple identical requests is the same as for a single request, and lists them: PUT, DELETE, and the safe methods. POST is not among them. A send is a POST, so the protocol gives you no safety net, and the key is how you put one back.
That is the whole reason a confirmation written for an agent reads differently from one written for a person. A person clicks send once. A checkout webhook retries on timeout, and it retries without knowing whether the first attempt committed. The order id is the immutable key, so the retry collapses into the original send instead of confirming the same order twice.
The same header covers the direct path. POST /v1/my/messages takes channel, to, subject and one of html, body or template_id, and on a retry "reusing the same key with the same payload returns the original message. Reusing the key with a different payload returns 409 idempotency_conflict." A conflict there is the system telling you that two different confirmations are trying to claim one order.
A template written to be filled in by a person tolerates ambiguity in its placeholders, because the person sees the gap and fixes it. A template written to be filled in by a model does not, because there is no pass where anyone looks. So the template has to state three things: which fields vary, which must not vary, and what renders when one is missing at send time.
What varies comes from two different places and they behave differently. {{ contact.first_name }} reads the contact record, which existed before the order. {{ event.order.id }} reads the envelope that arrived with the trigger, which did not. The second is the one that breaks, because the failure is not a missing surname, it is an entire block of context that is silently empty.
What must not vary is the path itself. The documented rule is that you "keep each event contract stable once a flow uses it," and the example given is exactly an order field: if a flow expects event.order.total, keep sending that path with the same meaning and the same value type. Renaming it in the producer does not error. It renders nothing.
What happens when a field is absent is a decision the template makes, not an accident it suffers. Give the value a default: {{ event.plan | default: "standard" }}. An order confirmation that renders a blank total is worse than no email at all, because it creates a support contact about money.
Some events carry required fields for the same reason. The built-in order_shipped event requires data.tracking_url, and data.carrier and data.tracking_number are optional, because the supplied flow recipe cannot render without the first and can render without the others. That is the shape to copy for a custom order event: name the fields the message cannot be sent without, and give every remaining one a default.
There is a reason to be strict about this that has nothing to do with tidiness. Transactional integrations fail closed and they fail quietly. A producer that stops sending a field, or a send endpoint that starts requiring one, does not light up a dashboard, because there is no dashboard in the path and nobody is reading the response. You find out when a customer asks where their confirmation went. A change to the contract needs a canary, not a changelog entry.
Then test the contract, not the happy path. The docs put it as one instruction, "create and test the event contract before activating the flow," and it is the step that gets skipped, because rendering against a complete order proves nothing about the order that is missing a delivery window.
There is a second machine in this story and most template pages forget it. The confirmation is not only generated by software, it is read by software: an inbox that wants to show the order, an assistant asked where a parcel is, a script filing receipts. Prose is a poor interface for any of them, and regular expressions over a marketing layout are worse.
The standard answer is already there. Google's email markup documentation states that markup "relies on structured data in emails" and that Gmail supports both JSON-LD and Microdata, and that "you can add structured information anywhere inside the <body> element of the email HTML in any of the supported formats." The vocabulary is schema.org/Order, which defines an order as a confirmation of a transaction and carries orderNumber, orderStatus, orderedItem, orderDate and orderDelivery as properties.
Those field names should look familiar, because they are the same fields the visible message has to carry. That is the useful observation: the block of structured data and the block of prose are two renderings of one contract, and they take their values from the same event. If they can disagree, one of them is wrong, and the one nobody proofreads is the one that will be.
So generate both from the same fields rather than writing the markup as a second pass. A confirmation whose visible total and whose orderNumber came from different places is a bug waiting for a support ticket, and it is exactly the bug a template gallery cannot warn you about.
The plain-text part is the same idea one layer down. RFC 2046 defines multipart/alternative as parts that are each an alternative version of the same information, ordered by increasing faithfulness to the original. Three renderings of one set of facts, then, and all three have to agree.
An order confirmation is transactional, which under CAN-SPAM exempts it from the opt-out and physical-address requirements that commercial email carries. The line between the two streams is worth reading properly, because it is the one a generated message crosses by accident: see transactional versus marketing email.
The exemption depends on primary purpose. Adding substantial promotional content, such as a full cross-sell block, can reclassify the message as commercial, at which point the missing unsubscribe link becomes a violation rather than an omission.
Modest related content is generally tolerated and is a judgment call rather than a bright line. The safe construction keeps the transaction above the fold and anything promotional clearly secondary.
One compliance field does not belong in the template at all, and this is the part an agent gets wrong. The physical address required in an email footer lives on the Brand Kit, alongside the company name and description, and Nitrosend applies it when the email is composed. A model asked to write an order confirmation will not think to ask for a postal address, so putting it in the template is asking the model to remember something it has no reason to know.
That is the general arrangement, and it is worth stating as a rule rather than a feature: humans approve, agents operate. The agent composes, renders, tests and queues. The gate is the send, because the send is the only part that cannot be taken back.
Leaving it unset does not ship a non-compliant email. nitro_get_status reports the gap as an issue against the brand and names what it stops, and the account recommendation is a single call to nitro_set_brand_kit. A blocked send is a better failure than a sent violation, which is the general shape of every gate worth having when nobody is watching the outbox.
Headers must be accurate and the subject line must not be deceptive regardless of classification.
Send confirmations through the transactional stream on a sending domain separate from marketing, and reach it through the email API rather than a dashboard. These messages need to arrive, and mixing them into campaign infrastructure exposes them to the complaint rate campaigns generate.
Do not use a no-reply address. A customer replying to an order confirmation has a real problem, and discarding that reply converts it into a chargeback or a public review.
Handle the failure case deliberately. A confirmation that hard bounces means the address captured at checkout was wrong, which is worth surfacing to the merchant rather than silently suppressing, because the order still exists.
Handle the send failure the same way you handle the bounce. If a confirmation cannot go out, what you want is an obvious failure with a fix-and-send action attached, not a silent retry an hour later. A message about money is the worst possible place for a system to fail quietly.
Email dashboards had a good run. Two decades, billions of emails, entire companies built on them, including two of mine. After ten years of building email tools I think the dashboard was never the product. It was the bottleneck.
My position on this is not subtle. Laying out an order confirmation by hand is the obsolete part of the job. The fields are fixed, the order is fixed, the brand is already written down, and the only genuinely variable input is an order that a machine already has in structured form. There is nothing in that description that wants a human in a drag-and-drop editor.
What a person is actually good at here is deciding the contract. Which fields the message cannot be sent without. Which path the producer promises to keep stable. What the email says when the delivery window is unknown. That is a specification, and once it is written, generating the email from it is work for the agent.
Which is why the Brand Kit exists as a separate thing from the template. It holds the company name and description, the brand, background and text colors, the heading and body fonts, the light and dark logo, the physical address, and a brand voice that tells your agent how to write for you. Set it once, from your own site if you like, and the agent composing the confirmation applies it without anyone opening a layout tool. The template stops being a design and becomes a contract, which is the only part worth a person's attention.
The restraint argument survives all of that, and it is worth being clear about. The order number, the total, the delivery expectation and the support path stay the most prominent things on the page. A confirmation exists so the reader can verify what they just did and find their way back if it is wrong. Design serves that or it is decoration on a document people forward to their accounts team.
And make it findable later. A confirmation is retrieved far more often than it is read on arrival, so the subject line carrying the order number matters more than anything clever, because that is the string somebody will search six weeks from now. Put it in the template as a required field with no default, and it cannot go out without one.
1 Glossier, Allbirds, Everlane, LEGO and IKEA are not Nitrosend customers and did not send or endorse these emails. Every image in them is concept artwork.
Every plan includes full stack emailing: Flows, Newsletter Campaigns and Transactional Email, plus our NitroWheel LLM and all agent integrations (Claude, ChatGPT, Codex, Cursor and others). Pay for what you send, not who you store.
Every paid plan includes 3 agent inboxes and no Nitrosend footer.
For your first email program.
$192 billed yearly.
20,000 emails / month
Choose StarterFor a growing audience.
$480 billed yearly.
60,000 emails / month
Choose ProFor teams and agencies.
$1,440 billed yearly.
200,000 emails / month
Choose GrowthFor high-volume sending.
$2,880 billed yearly.
500,000 emails / month
Choose ScaleSending 500,000+ emails a month? Get a custom plan designed for you, with volume pricing for sending, verification and enrichment.
5,000 emails to start, then 500 emails every month. No expiry on your starter emails.
Daily allowances depend on your plan and sender standing. Strong list, domain and delivery evidence can raise standing, including on day one. Trusted receives the full plan allowance; available email credits, safety checks and delivery pacing still apply.
Free forever. No credit card required. See full comparison →