Email API

Order Confirmation Emails via API: What to Include and When to Send

Send order confirmation emails from your app through an email API: what to include, the exact moment to send, which from address to use, and a working request.

The order confirmation is the most opened email your business will ever send, and it is also the one customers screenshot when something goes wrong. Sending it from your own app through an API lets you control every line instead of settling for a platform template. Here is what to include, when exactly to fire it, and the request that sends it.

Quick answer

Send the confirmation once the payment is captured (or authorised, if you capture on shipment), never on checkout submit. Include the order number in the subject, an itemised list with prices and totals, the shipping address as you will print it, the expected delivery window, and a way to reach a human. Send it from orders@yourdomain.com with a monitored reply path, and send it from a job triggered by the payment webhook, not from the checkout request.

When to send

The trigger should be the event that makes the order real. If you use Stripe, that is the payment_intent.succeeded or checkout.session.completed webhook. If you use PayPal, it is the capture completed event. Sending on the "Place order" click means you will email confirmations for payments that later fail, and then have to send an awkward cancellation. A 10 to 30 second delay behind a webhook is invisible to the customer; a confirmation for an order that did not happen is not.

What the email must contain

  • Subject with the order number: "Order #10482 confirmed". Customers search their inbox for it.
  • Item lines: name, variant, quantity, unit price, line total. Use a table.
  • Totals: subtotal, discount with the code that was used, shipping, tax, grand total, and currency code, not just a symbol.
  • Payment method, masked: "Visa ending 4242".
  • Shipping address exactly as entered, so typos are caught now rather than after the parcel bounces.
  • Expected delivery window as a date range, and the words "we will email you when it ships".
  • A link to the order page and a support address. Not a phone number only.
  • For digital goods: the download or access link, and how long it stays valid.

The send request

Build the HTML from your order object, then POST it. This example uses the text field too so the itemised list survives plain text clients:

const res = await fetch("https://api.oqumail.com/api/v1/emails", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + process.env.OQUMAIL_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    from: "orders@yourdomain.com",
    to: order.email,
    subject: "Order #" + order.number + " confirmed",
    html: renderOrderHtml(order),
    text: renderOrderText(order)
  })
});
if (!res.ok) throw new Error("send failed: " + res.status);

Choosing the from address

Use orders@ or shop@ on your real domain, with a from name that is your brand, not a person. Do not use noreply@: customers reply to confirmations to change an address or ask about sizing, and those replies are revenue. On OquMail the same domain can carry the API sending and a normal orders@ mailbox that your team opens in webmail or any IMAP app, so replies land somewhere a human reads them. That mailbox also gets the SPF, DKIM and DMARC records set up during domain verification, which is what keeps confirmations out of the Promotions tab.

Implementation checklist

  1. Store an order_confirmation_sent_at timestamp on the order. Send only if it is null, then set it. Webhooks are delivered more than once.
  2. Render prices from stored values, not live product prices. The customer must see what they paid.
  3. Escape every user-supplied string (names, addresses) when building HTML.
  4. Send to the checkout email, not the account email, if they differ. Guest checkouts have no account.
  5. Keep the rendered HTML under about 100 KB so Gmail does not clip it.
  6. Log the API response id next to the order so support can find the delivery log later.

Mistakes to avoid

  • Marketing blocks ("You may also like") in the confirmation. It is a transactional email; keep it factual and it stays out of spam filters.
  • Sending the invoice PDF as an attachment. Link to it instead; attachments from new senders are a spam signal.
  • Missing currency. "Total: 49.00" means nothing to a customer with cards in two currencies.
  • Using a different domain than the storefront. Confirmations from a third-party sender domain look like phishing.

Common questions

Should I send a separate receipt email?

For most shops the confirmation is the receipt. Send a separate invoice only for B2B customers who need a numbered tax document, and link it rather than attaching it.

What if the payment is authorised but not captured?

Send the confirmation on authorisation, and word the total as "will be charged when your order ships". Customers expect an immediate confirmation; a silent 24-hour gap causes duplicate orders.

Does the confirmation need an unsubscribe link?

No. It is a transactional message triggered by a purchase, not marketing. Adding an unsubscribe link to it confuses customers into thinking they can opt out of order updates.

Free business email on your own domain

OquMail gives you up to 15 mailboxes on your domain — free — with guided SPF/DKIM/DMARC, webmail, IMAP/SMTP for any mail app, and a send API. Most teams are live in under fifteen minutes. Start at oqumail.com.

Get started free

Ready for business email on your domain?

Up to 15 free mailboxes, guided DNS, webmail, and a transactional API — start in minutes.

Create your free workspace