Skip to main content

Implementing emails in 2025: Basics & how to test generated emails

We set out to refresh our emails so they would match our product’s new design and brand style. Outlook had other plans. So, what did we learn about email formatting? And did we manage to make it work in the end?

Written by Martin Hejtmanek

If you’ve ever been asked to develop an email that works consistently across different email clients, you know what kind of nightmare that can be. But, despite almost giving up halfway through, we did it! We learned a lot and even found some new ways to cope with the tough parts of the desired email design.

In this article, I’ll share a summary of what we found. Hopefully, it will make your day—or at least your emails—a bit brighter.

We redesigned the UI of our product, giving it a shiny new look:

New UI in Kentico Kontent

The email notifications sent by the system were the final missing piece of that redesign. As our solution is a SaaS content management system, it generates not only basic user account emails but also workflow and review notifications for things like comments, mentions, and tasks associated with specific content items.

All these emails are generated in the .NET back end with Razor templates, so, unlike some one-off marketing email, we couldn’t just stitch a bunch of images together using any design we liked. We actually needed to generate some layout on the fly and populate it with various content.

Why is developing robust emails such a big deal?

You’d think it would be a simple task for a web developer—after all, emails support HTML, right?

Well, if you’ve ever wanted to experience time travel, this is about as close as you can get. The moment you try to make HTML emails work across clients (even recent ones) you’ll find yourself transported straight back to the year 2000. It’s Internet Explorer all over again… or worse.

The main culprit? Outlook and its HTML rendering engine which doesn’t really render HTML but rather imports it.

A real example, our own emails

Here’s an example of an email design from our UX team. It may look simple in the browser world, but becomes surprisingly complex once you try to implement it reliably in email clients.

Some of the features we needed included:

  • Containers with rounded corners
  • Rounded buttons with shadow
  • Rounded tags aligned vertically with the text
  • Some images
  • Global email layout centered with max-width.

Here is an example of what we got from our UX designers:

New email design

Spoiler alert: We managed to implement all of these. By the end of this series, you’ll know how to do it too.

Outlook is still your biggest enemy, so keep it close

As much as I love Microsoft technologies, I can sincerely say I hate Outlook even though I’ve conquered it.

The problem is that Outlook uses MS Word as its rendering engine. Yes, you read that right—Word! I can guess why: they already had a rich text editor. But the cost? Massive.

This applies only to Outlook on Windows. On macOS, it uses a browser-based engine.

To give you an idea, here’s what Outlook produces when Outlook-specific hacks are missing. It’s not completely broken, but it doesn’t match the intended design at all.

No Outlook hacks

Essentially, it can’t handle most of the modern HTML and CSS you’re used to. It should have been replaced with a proper rendering engine over a decade ago. But here we are, still working around it using obsolete technologies like VML.

As the saying goes: Keep your friends close, and your enemies closer. Outlook is here to stay, so you might as well learn its quirks and beat it with your knowledge.

Knowing how VML works and what it can and can’t do is half the battle.

Quick and bulk testing: PaperCut SMTP for help

To start, you’ll need an efficient way to test and preview your emails.

PaperCut SMTP is a great tool that creates a localhost SMTP server to capture your emails.

We configured our test instance so that unit tests automatically send generated emails to localhost using new SmtpClient("localhost"). This dramatically speeds up validation during development.

PaperCut provides a pretty good view of the email with an HTML rendering engine, so it is a good starting point to check that your email looks the way you expect it to.

BUT...it doesn’t validate the Outlook view at first glance. Luckily, you can open the PaperCut target folder and open the .eml files from there in Outlook. Manually, one by one—or with a script.

My Outlook is connected to an Exchange server that automatically syncs all the emails in the Inbox with all the other devices, which is handy for cross-device testing. You just need to connect them to the same email account.

By adjusting the SmtpClient config, we dump the same set of emails to Gmail for testing through its SMTP.

new SmtpClient("smtp.gmail.com") {
  EnableSsl = true,
  Credentials = new System.Net.NetworkCredential(userName, password),
  Port = 587
}

HTML files for quick experiments

You can also export the emails as HTML files for easier experimentation.

  • Opening them directly in your browser (e.g., file:///c:/temp/emails) lets you tweak markup and CSS quickly.
  • Dragging an HTML file into Outlook’s message list creates a draft message from it. This runs it through Outlook’s HTML import (via Word), giving you an almost exact preview—close enough to catch issues early.

This way, you can easily iterate over all kinds of experiments with the Outlook exceptions and VML.

Note: You can even drag those files into MS Word to open them as Word documents, though that view isn’t identical to Outlook’s rendering.

External validation services

Services such as Email on Acid and Litmus are great for checking how your email looks across various clients and devices.

The absolutely basic stuff you should know

Now that you’ve learned a few pointers on how to effectively test and experiment with emails, it’s time to dive in.

Linked images seem to be the best

We experimented with inline Base64 images, which seemed promising, but found issues:

  • Outlook struggles with PNG transparency in inline images.
  • Gmail blocks inline images entirely.

We reverted to linked images, which proved the most reliable option.

Do not expect custom fonts to work

Let’s keep it real: there’s no reliable way to make custom fonts work across all email clients. If you try, you’ll likely waste hours only to discover that half your audience still sees a fallback font. Some email clients may support linked web fonts, but honestly—is it worth the effort? Probably not.

We are using font-family: "Helvetica", Helvetica, Arial, sans-serif; to best match the app font, which is actually GT Walsheim Pro.

You can read more about email fonts here.

Be a bit bipolar, use conditions (Outlook vs. others)

Outlook plays by its own rules and not in a good way. It renders emails using Microsoft Word’s engine, which makes it behave completely differently from standard HTML email clients.

So, what’s the trick? You basically need to build two versions of the same email: one for “normal” email clients and one just for Outlook—and make sure they don’t interfere with each other.

We use two simple conditional statements to handle this:

  • Outlook-only code:
<!--[if mso]>
<p>Something for Outlook only</p>
<![endif]-->
  • Code for non-Outlook email clients:
<!--[if !mso]><!-->
<p>Something for everything but Outlook</p>                
<!--<![endif]-->

Notice that in the second condition, you need to add an extra layer of comment wrapping. This ensures that non-Outlook clients properly ignore the otherwise invalid markup while Outlook still interprets it correctly.

How to center the content in Outlook

In normal (HTML-mature) clients, you can use standard max-width and margin-auto. For Outlook, you’ll need to use a special wrapper.

Include this part of code under BODY to get a centered email with a maximum of 600px width in all email clients:

<!--[if mso]>
<center>
<table><tr><td width="600">
<![endif]-->
<div style="width: 100%;display:block;margin:0 auto;max-width:600px;">
        HERE COMES THE EMAIL CONTENT
</div>
<!--[if mso]>
</td></tr></table>
</center>
<![endif]-->

You can also see here how you can easily apply a conditional wrapper in the case of Outlook.

Always inline CSS, but with one exception

As most of the email clients do not process styles in HEAD, and only some process styles in BODY (e.g., Outlook—yay!), it is best to inline the CSS into the HTML to make sure everything works.

We use the PreMailer library to do that. But be careful and make sure that:

  • Inlining doesn’t remove comments, as you will need them to drive Outlook exceptions.
  • Inlining doesn’t remove style tag in the body meant for Outlook (see below).

Also, forget about more complex CSS selectors, PreMailer supports some, but in a very limited scope. I think we only used :first and :last. If you don’t inline the CSS, clients won’t support it anyway.

There is one exception to this rule. Outlook needs the font family applied globally, so keep this one style tag within the BODY of the email. With the font of your choice, of course.

<!--[if mso]>
<style type="text/css">
    body, table, td, p, h1, h2, h3, span, a { font-family: "Helvetica", Helvetica, Arial, sans-serif !important; }
</style>
<![endif]-->

VML for Outlook

This is a given. Whatever isn’t possible with HTML code needs to be done in VML in Outlook—unless you want to mimic it with an image or omit it completely.

Make sure to add the namespace directives to your HTML tag before using any of the VML objects in your emails.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">

Proper scaling and compatibility mode for Outlook

In addition to other Outlook things, I recommend using the following two adjustments you place in your HEAD tag.

  • Add compatibility metadata for IE to use the latest version. Without it, advanced stuff like rounded corners would not work if someone opened the email using the browser option, because IE doesn’t know VML and its previous version doesn’t know border radius. Thanks to this compatibility metadata, it uses the latest version as well as the HTML and CSS you have for standard email clients.
<meta http-equiv="X-UA-Compatible" content="IE=edge">
  • Add Office document metadata and viewport to enforce proper scaling. Without this, your image sizes or VML object placements may be distorted and inconsistent.
<!--[if gte mso 15]>
<xml>
    <o:OfficeDocumentSettings>
    <o:AllowPNG/>
    <o:PixelsPerInch>96</o:PixelsPerInch>
    </o:OfficeDocumentSettings>
</xml>
<![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1">
    

Design system & components

Find a way to avoid code repetition and copy-pasting of anything that has some Outlook exceptions. If you don’t, you will soon get lost in tables and HTML conditions duplicated all over the place.

We built a minimalistic design system with a few key components that abstract away the complexity of email client dependencies and customizations for Outlook.

Our own set of components consists of:

  • Box – Think of it as a <div> with all the styling powers you’d expect: borders, backgrounds, inner and outer spacing, and even rounded corners.
  • Stack – A list of items with a defined spacing between them, horizontal or vertical.
  • Button – Simply a button with rounded corners, and even a shadow!
  • Workflow label – “A pill” (tag) with defined color, text, and rounded corners placed inline within the text.
  • Mention – Either just colored text or “a pill” similar to the workflow label if it’s you who’s mentioned.
  • Heading 2 – We only need special handling for H2 as we don’t use smaller headings, and H1 is always at the top of the email body where we don’t need special handling for spacing in Outlook. Everything else related to the normal text is used. 

Here are some examples of how individual components map to the design:

Components and the design
Components and the design version 2

And this is how we typically use them in the Razor code based on whether they represent a container or a standalone entity:

@using (Kontent.BeginBox(new BoxModel(
    padding: Spacing.XL,
    backgroundColor: Color.Desk
) {
    Paddings = { X = Spacing.XL, Y = Spacing.L }
}))
{
    <img width="150" height="46" class="header__img" alt="Kontent.ai" src="@Icons.KontentLogo">
}

@Kontent.Button(Model.GoToActionUrl, "Open subscription details")

On the technical side, we are using Razor partial views or simple helpers returning HTML strings to render their markup.

Useful resources

To win this battle, you need the right knowledge and tools.
Below is a list of resources that proved incredibly helpful during our journey—they’ll help you steer clear of dead ends and point you toward smarter, more reliable solutions.

  • https://www.campaignmonitor.com/css/ – A huge list of features supported by individual email clients, as well as a brief description of each email client and its specifics.
  • https://www.caniemail.com/ – Basically “can I use” for emails. Very useful if you are interested in a specific feature.
  • https://buttons.cm/ – Rounded buttons. But I will tell you even more in one of my next articles.
  • https://backgrounds.cm/ – Background images in emails, we didn’t use these, but still nice to see some concepts, e.g., expanding VML object to the full width.
  • https://www.w3.org/TR/NOTE-VML – Your primary cannon for the Outlook battle. VML is pretty flexible (kinda old-fashioned SVG) and offers much more than you normally see while searching for how to do X and Y in emails. I will show you in my upcoming articles.

There is a lot more, just google the usual suspect keywords (email, Outlook, and the topic you are up to), just expect that most of these will give you the rather specific advice that you may need to bend a bit using the knowledge from the above-mentioned sources.

My best advice overall is: Think about the concepts, not just the final code.

Are we there yet? 

This is just the beginning. The following articles in this series will show you the implementation details of some of those individual components and their specific challenges. Some of them required me to create original solutions I couldn’t google anywhere. Find the respective parts below.

In the next article, I will show you how you can make rounded buttons and, most importantly, how seemingly impossible shadows are actually possible.

Popular articles

Creative team discussing evergreen content
  • For business
The ultimate guide to evergreen content

What if we told you there was a way to make your website a place that will always be relevant, no matter the season or the year? Two words—evergreen content. What does evergreen mean in marketing, and how do you make evergreen content? Let’s dive into it.

Lucie Simonova

A marketer writing a blog post structure
  • For business
7+1 steps to structure a blog post

To structure a blog post, start with a strong headline, write a clear introduction, and break content into short paragraphs. Use descriptive subheadings, add visuals, and format for easy scanning. Don’t forget about linking and filling out the metadata. Want to go into more detail? Dive into this blog.

Lucie Simonova