E-Commerce Order Emails: From Trigger to Delivery
A complete implementation of e-commerce order confirmation emails, covering async triggering, idempotency, template requirements, and common mistakes.

Order Emails for E-Commerce: From Trigger to Delivery
Every order confirmation email needs to land in seconds. Delays erode trust. This guide walks through the full implementation using Node.js and the Rovela API.
When to trigger
Don't send email synchronously inside a payment webhook — webhooks can fire more than once, and a slow send blocks your response. The right pattern is to enqueue a job after payment confirmation and let a worker handle it asynchronously.
// After payment succeeds
await queue.add('send-order-email', {
orderId: order.id,
userId: order.userId,
type: 'order_confirmed',
});
Sending with Rovela
const { Rovela } = require('@rovela/sdk');
const rovela = new Rovela({ apiKey: process.env.ROVELA_API_KEY });
async function sendOrderConfirmed(order, user) {
await rovela.emails.send({
from: 'orders@yourdomain.com',
to: user.email,
subject: `Order confirmed #${order.id}`,
html: renderOrderTemplate(order),
});
}
What the template needs
At minimum: order number, line items (name, quantity, unit price), shipping address, estimated delivery, and a support contact. Total amount and payment method should also be explicit — users do get confused without them.
Idempotency
Queue retries can trigger duplicate sends. Log sent order IDs in the database and check before sending:
const sent = await db.query(
'SELECT 1 FROM email_log WHERE order_id = $1 AND type = $2',
[order.id, 'order_confirmed']
);
if (sent.rows.length > 0) return; // already sent
Common mistakes
- Don't use
display:nonein inline styles to hide content — some email clients ignore it. - Images need absolute URLs — email clients can't resolve relative paths.
- Always include a plain-text fallback in the
textfield in case HTML is filtered. - Send more than just the confirmation — ship notification, delivery, and refund emails all matter.
Rovela's template feature lets you store the HTML structure once and pass variables each time, which is far easier to maintain than string-interpolated HTML in application code.