Marketing Email Template Development
Adaptive marketing emails are a headache for any layout designer. Outlook trims CSS, Gmail merges rows, and Apple Mail supports dark mode. Promotions, digests, reactivation — every email must look perfect in 90+ clients. Otherwise, conversion drops and profits are lost. Even a small typo in styles can break the email in a popular client, and subscribers will see a broken layout, leading to loss of trust.
We solve this problem: layout with MJML, dynamic content via Handlebars, testing in Litmus. Over 7 years of experience ensures your template won't break for any subscriber. Imagine: email opens in Outlook — everything in place, buttons clickable, links working. In Gmail — the same. This is reality, not fantasy. According to Litmus, Outlook and Gmail account for over 60% of the market, so cross-client compatibility is critical. We spend up to 30% of development time on testing to ensure no subscriber sees a broken template.
How to ensure Outlook compatibility?
Outlook uses Word to render HTML. It does not support block layout, media queries, or many CSS properties. The solution is table-based structure with explicit widths. MJML generates such tables automatically. Additionally, we use conditional comments for margins/padding. A typical promotion email structure in MJML:
<mjml>
<mj-head>
<mj-preview>30% off until Friday — don't miss out</mj-preview>
<mj-attributes>
<mj-all font-family="'Helvetica Neue', Helvetica, Arial, sans-serif" />
<mj-text font-size="16px" line-height="1.6" color="#374151" />
</mj-attributes>
</mj-head>
<mj-body background-color="#f3f4f6">
<!-- Hero banner -->
<mj-section background-color="#1e40af" padding="48px 32px">
<mj-column>
<mj-image src="{{ logoUrl }}" width="140px" align="left" />
<mj-text font-size="36px" font-weight="800" color="#ffffff" padding-top="24px">
Final Sale
</mj-text>
<mj-text font-size="18px" color="#bfdbfe">
Up to 50% off on the entire range — only until {{endDate}}
</mj-text>
<mj-button href="{{ saleUrl }}" background-color="#f59e0b"
color="#111827" font-weight="700" border-radius="8px">
Shop Now
</mj-button>
</mj-column>
</mj-section>
<!-- Three products in a row -->
<mj-section background-color="#ffffff" padding="32px">
{{#each products}}
<mj-column width="33%">
<mj-image src="{{ this.imageUrl }}" border-radius="8px" />
<mj-text font-weight="600" color="#111827">{{ this.name }}</mj-text>
<mj-text>
<s style="color:#9ca3af">{{ this.oldPrice }}</s>
<span style="color:#dc2626;font-weight:700">{{ this.newPrice }}</span>
</mj-text>
<mj-button href="{{ this.url }}" background-color="#3b82f6" border-radius="6px">
Buy
</mj-button>
</mj-column>
{{/each}}
</mj-section>
<!-- Footer -->
<mj-section padding="16px 32px">
<mj-column>
<mj-text font-size="12px" color="#9ca3af" align="center">
You received this email because you subscribed to our newsletter.<br/>
<a href="{{ unsubscribeUrl }}" style="color:#9ca3af">Unsubscribe</a>
·
<a href="{{ preferencesUrl }}" style="color:#9ca3af">Preferences</a>
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Why MJML is better than manual table layout?
Manual table layout takes up to 3 days per template and often contains errors. MJML reduces time to 1 day by automating media queries, image compression, and preview generation. Additionally, MJML reduces testing load — we spend 70% less time finding bugs. Savings on testing can reach $500 per month when using Litmus instead of manual checks.
Rendering and sending
import mjml2html from 'mjml';
import Handlebars from 'handlebars';
import { readFileSync } from 'fs';
function renderMarketingEmail(
templateName: string,
data: Record<string, unknown>
): string {
const template = readFileSync(`./email-templates/${templateName}.mjml`, 'utf-8');
const compiled = Handlebars.compile(template)(data);
const { html, errors } = mjml2html(compiled, { minify: true });
if (errors.length) throw new Error(errors[0].formattedMessage);
return html;
}
How to personalize emails with Handlebars?
Personalization increases click-through rates by 30%. Handlebars inserts variables:
-
{{firstName}}with fallback "Dear Subscriber" -
{{#each products}}for cart items -
{{#if location}}for geo-offers -
{{unsubscribeUrl}}and{{preferencesUrl}}for GDPR compliance
Data is loaded via REST API or SQL queries to your CRM. All links are automatically tagged with UTM parameters ?utm_source=email&utm_campaign=spring_sale. For example, integration with Bitrix24 allows fetching current prices and stock via REST request to /crm/product.list and rendering them with Handlebars. This provides dynamic display without manual updates.
Example of CRM integration via API
Personalization data is loaded into the template via a REST request to your CRM. For example, when using Bitrix24, we get a list of products via the crm.product.list method, pass it to Handlebars, and render. This automatically updates prices and stock without manual intervention.
Process
- Analysis — study the layout (Figma, PSD), identify variables and dynamic blocks.
- Design — create MJML structure, configure Handlebars.
- Implementation — layout adapted for 90+ clients, insert conditional comments.
- Testing — check in Litmus and Mailtrap, spam test, adjust.
- Deployment — integrate with ESP, configure DKIM/SPF/DMARC, final QA.
How do we test email templates?
| Tool | Checks | Cost (per month) |
|---|---|---|
| Litmus | 90+ clients, spam test | ~$99 |
| Email on Acid | 80+ clients | ~$149 |
| Mailtrap | Test sending | free up to 500 emails |
We use Litmus: upload the template, view screenshots in Outlook, Gmail Web/iOS/Android, Apple Mail, Yahoo, AOL. SpamAssassin score must not exceed 2.0 — we check for spam triggers.
Comparison of layout methods
| Characteristic | Manual table layout | MJML |
|---|---|---|
| Template development time | 2–3 days | 1–2 days |
| Client support | ~30–40 | 90+ |
| Risk of errors | High | Low |
| Maintenance complexity | High | Low |
Timelines and pricing
One promo template with banner and product block — 1–2 days. A set of 5 templates (promo, digest, reactivation, notification, holiday) — 5–7 days. Pricing is calculated individually — we will analyze your layout and provide a final quote. Contact us for a consultation to get an accurate estimate. On average, savings due to MJML automation are 30–50% of the budget compared to manual layout.
What's included in the work
- Layout based on your design (Figma, PSD)
- Integration with ESP (Mailchimp, SendPulse, UniSender, SendGrid)
- CRM integration via API (AmoCRM, Bitrix24)
- UTM setup, DKIM/SPF/DMARC
- Testing in Litmus, Mailtrap
- Guaranteed correct rendering in all clients
Order turnkey template development — get stable conversion without headaches. Contact us to discuss your project. Get a consultation on your layout right now.







