Development
Building production-ready email receipts can be challenging, especially when you need to handle multiple scenarios like guest vs. logged-in customers, different shipping methods, discounts, and multi-currency support. This comprehensive guide will show you how to create a responsive, dynamic email receipt template using MJML for layout and Mailjet’s templating language for email personalization.
By the end of this tutorial, you’ll have a fully functional receipt template that can handle complex order data, attach PDF invoices, and deliver reliably through Mailjet’s Send API v3.1.
Before diving into the implementation, let’s understand why this approach is superior to creating one-off HTML emails:
Your final email receipt template will include:
Before starting, ensure you have:
Let’s start by creating the basic structure of our receipt template using MJML. This will ensure our email is responsive and renders consistently across different email clients.
<mjml>
<mj-head>
<mj-title>Your receipt</mj-title>
<mj-attributes>
<mj-text font-family="Montserrat, Arial, sans-serif" />
<mj-class name="muted" color="#6b7280" font-size="13px" />
<mj-class name="total" font-weight="700" font-size="16px" />
</mj-attributes>
</mj-head>
<mj-body background-color="#f6f7fb">
<mj-section background-color="#ffffff" padding="24px">
<mj-column>
<mj-image width="120px" src="https://yourcdn.com/logo.png" alt="Brand" />
<mj-text font-size="20px" font-weight="700">Thanks for your purchase!</mj-text>
<mj-text css-class="muted">
Order {{var:order_id}} • {{var:order_date}} • {{var:currency}}
</mj-text>
<!-- Shipping notice (rendered conditionally in Step 2) -->
<mj-text css-class="muted">
Delivery to: {{var:shipping.name}}, {{var:shipping.address1}}, {{var:shipping.city}}
</mj-text>
<mj-divider border-color="#e5e7eb" />
<!-- Line items table (rendered via loop in Step 2) -->
<mj-table>
<tr style="text-align:left;">
<th style="padding:8px 0;">Item</th>
<th style="padding:8px 0;">Qty</th>
<th style="padding:8px 0; text-align:right;">Price</th>
</tr>
<!-- row loop here -->
</mj-table>
<mj-divider border-color="#e5e7eb" />
<mj-text>
Subtotal <span style="float:right;">{{var:money.subtotal}}</span>
</mj-text>
<mj-text>
Tax <span style="float:right;">{{var:money.tax}}</span>
</mj-text>
{{var:money.discount_row}} <!-- optional discount row via condition -->
<mj-text css-class="total">
Total <span style="float:right;">{{var:money.total}}</span>
</mj-text>
<mj-divider border-color="#e5e7eb" />
<mj-text css-class="muted">
Paid with {{var:payment.brand}} ending {{var:payment.last4}}. Need a PDF? It's attached.
</mj-text>
<mj-text css-class="muted">
Questions? Reply to this email or visit your order page: {{var:order_url}}
</mj-text>
</mj-column>
</mj-section>
<mj-section>
<mj-column>
<mj-text css-class="muted" align="center">
© {{var:year}} Your Company • {{var:support_email}}
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Important Notes:
Now we’ll enhance our template with Mailjet’s templating language to handle dynamic content. This includes variables, conditions, and loops that will be processed when the email is sent.
Mailjet’s templating language supports several variable types:
Insert this code inside your MJML table to loop through order items:
{% for item in var:items %}
<tr>
<td style="padding:6px 0;">{{item.name}}</td>
<td style="padding:6px 0;">{{item.qty}}</td>
<td style="padding:6px 0; text-align:right;">{{item.price}}</td>
</tr>
{% endfor %}
Add conditional blocks to show shipping details only when relevant:
{% if var:has_shipping %}
<mj-text css-class="muted">
Delivery to: {{var:shipping.name}}, {{var:shipping.address1}}, {{var:shipping.city}}
</mj-text>
{% endif %}
Once you’ve compiled your MJML to HTML and added templating tags, you need to save it as a template in Mailjet. You have two options:
Paste your compiled HTML into a new template in the Mailjet app (Passport).
Create a new template:
curl -s -X POST \
--user "$MJ_APIKEY_PUBLIC:$MJ_APIKEY_PRIVATE" \
https://api.mailjet.com/v3/REST/template \
-H 'Content-Type: application/json' \
-d '{
"Name":"Receipt v1",
"OwnerType":"user",
"IsTextPartGenerationEnabled":"true",
"Locale":"en_US"
}'
Add your HTML content to the template:
curl -s -X POST \
--user "$MJ_APIKEY_PUBLIC:$MJ_APIKEY_PRIVATE" \
https://api.mailjet.com/v3/REST/template/TEMPLATE_ID/detailcontent \
-H 'Content-Type: application/json' \
-d '{
"Html-part":"<html>...your compiled MJML with templating tags...</html>",
"Text-part":"Your plain text fallback"
}'
Now comes the exciting part – sending your dynamic receipt email. Here’s a complete example that includes template variables, PDF attachment, and proper configuration:
curl -s -X POST \
--user "$MJ_APIKEY_PUBLIC:$MJ_APIKEY_PRIVATE" \
https://api.mailjet.com/v3.1/send \
-H 'Content-Type: application/json' \
-d '{
"Messages":[
{
"From":{"Email":"billing@yourbrand.com","Name":"Your Brand Billing"},
"To":[{"Email":"customer@example.com","Name":"{{data:firstname:\"Customer\"}}"}],
"TemplateID": TEMPLATE_ID,
"TemplateLanguage": true,
"Subject": "Your receipt {{var:order_id}}",
"Variables": {
"order_id": "ORD-98765",
"order_date": "2025-08-27",
"currency": "USD",
"items": [
{"name":"Sneakers","qty":1,"price":"$99.00"},
{"name":"Socks","qty":2,"price":"$10.00"}
],
"money":{"subtotal":"$119.00","tax":"$9.52","discount":"$0.00","total":"$128.52"},
"has_shipping": true,
"shipping":{"name":"A. Smith","address1":"10 Market St","city":"Austin"},
"payment":{"brand":"Visa","last4":"4242"},
"order_url":"https://yourapp.com/orders/ORD-98765",
"support_email":"support@yourbrand.com",
"year":"2025"
},
"Attachments":[
{
"ContentType":"application/pdf",
"Filename":"Invoice-ORD-98765.pdf",
"Base64Content":"<base64-encoded-pdf>"
}
]
}
]
}'
URLTags: Add “utm_source=receipt&utm_medium=email” for tracking
Monitoring your email delivery is crucial for maintaining customer trust and debugging issues.
Register your webhook endpoint to receive real-time events:
For global businesses, proper localization is essential:
Ensure your receipts reach the inbox and comply with regulations:
For teams deploying at scale, consider these optimizations:
Here are some issues to troubleshoot if you run into problems with the above.
You now have a complete, production-ready email receipt system! Here are some ways to enhance it further:
For additional resources and code samples, check out the Mailjet templating samples repository which includes a complete working example you can use as a starting point.
This guide walked you through creating a professional email receipt template using MJML for responsive design and Mailjet’s templating language for dynamic content. You learned how to handle complex order data, attach PDF invoices, ensure reliable delivery, and monitor performance; all essential components for a production ecommerce email system that scales with your business.