DEV Community

Cover image for How to create layouts and style emails for web application
Mykhailo Toporkov 🇺🇦
Mykhailo Toporkov 🇺🇦

Posted on

How to create layouts and style emails for web application

Hi! Today I'm going to show you everything you need to know to create and use your own emails in your web applications. Recently, I had a task to integrate mail services, so I decided to share some key insights on the requirements for creating emails.

Most modern web applications include features like registration confirmation, password reset emails, and weekly newsletters. These emails typically match the application's theme, which makes sense, but how do you properly create and style them? Today, I'll show you how.

In this article I will cover:


Emails Layout

I should probably start by mentioning that there are many SaaS applications that provide email delivery services, and you'll usually be working with them instead of setting up your own SMTP server. These services often offer email templates where you can pass your metadata, and then an email with your data will be sent to the specified email address, which typically depends on the application.

However today, I’ll focus on sending HTML directly from your application’s API to some SMTP, as using HTML is the only way to create the specific email layouts required by your application. However, it's important to keep in mind the restrictions imposed on HTML when creating these layouts.

Generally in emails used a subset of HTML 4.01 or XHTML 1.0 due to the broad compatibility needs across email clients. While modern web browsers support HTML5, many email clients (especially desktop clients like Outlook) do not fully support the latest HTML5 features or CSS3 styles. Therefore, I typically stick to older, more widely supported HTML standards, which include tags below:

Tag Function
<head> Stores service information, such as styles or title
<p> Defines a paragraph
<span> Defines an inline element
<h1>, <h2>, <h3>, <h4>, <h5>, <h6> Define 1-6 level headings
<img> Inserts an image
<a> Adds a link
<hr> Creates a horizontal line
<br> Sets a line break
<b>, strong Makes a text bold
<i> Italicizes a text
<u> Underlines a text
<s>, strike Applies the strikethrough formatting
<label> Specifies a text label for the input tag
<font> Specifies font styles
<small> Decreases the font size by one compared to plain text
<li> Creates a list item
<ol> Creates a numbered (ordered) list
<ul> Creates a bulleted (unordered) list
<table> Creates a table
<tr> Defines a table row
<td> Defines a table cell
<th> Defines a table header cell

As you can see the most reliable way to structure email content is to use table-based layouts, as they are universally supported across all email clients.

When it comes to images, we can't use SVGs via the <svg> element—only as an image using the <img> tag. However, there’s a catch: some email clients may block image URLs ( Always include alt text for accessibility and fallback ). For example, my corporate email often prevents images in emails from loading.

Modern HTML attributes alos out of scope for usage, though It is relatively occasion when you need to use something else but: id, class, href or style.


Emails Styling

When it comes to styling, there are two options available: internal styling, where all styles and class names are defined within a style element in the head section of the HTML document, or inline styling, where styles are applied directly to HTML elements using the style attribute.

Of course, just like with HTML tags, there are compatibility issues to consider. Below is a table of CSS properties that are supported for styling emails:

Property Function
background Sets the background style properties
background-color Sets the background color
border Sets all border style properties at once
border-color Sets the border color
border-width Sets the width of all borders
border-style Sets the line style for all borders
border-bottom Sets all style properties of the bottom border at once
border-bottom-color Sets the bottom border color
border-bottom-style Sets the bottom border line style
border-bottom-width Sets the bottom border line width
border-left Sets all style properties of the left border at once
border-left-color Sets the left border color
border-left-style Sets the left border line style
border-left-width Sets the left border line width
border-right Sets all style properties of the right border at once
border-right-color Sets the right border color
border-right-style Sets the right border line style
border-right-width Sets the right border line width
border-top Sets all style properties of the top border at once
border-top-color Sets the top border color
border-top-style Sets the top border line style
border-top-width Sets the top border line width
border-radius Sets the border radius
display Specifies the element output and visual display on the page
height Sets the element height
width Sets the element width
margin Sets the element margin
padding Sets the element padding
color Sets the text color
font Sets all font style properties at once
font-family Sets the text font family
font-size Sets the font size
font-style Sets the font style, for example, normal or italic
font-variant Determines how lowercase letters should be represented, i.e., normal or small-caps
font-weight Sets the font weight
list-style-type Sets the marker type for each list element
table-layout Sets the width of the table cells based on the content
letter-spacing Sets the letter spacing in text
line-height Sets the line spacing in text
text-align Sets the horizontal text alignment
text-decoration Specifies the text decoration, such as underlining, strikethrough, or blinking
text-indent Sets the indent size before a line in a text block
text-transform Converts text to uppercase or lowercase characters
vertical-align Sets the vertical text alignment

For the <table>, <tr>, <td>, <th> and <a> tags, I recommend duplicating the style styles with the appropriate attributes. In the example below, in addition to the style styles, the align, width, bgcolor, cellpadding, cellspacing, and border attributes are specified.

<table align="center" width="100%" bgcolor="#ffffff" cellpadding="0" cellspacing="0" border="0" style="background-color: #ffffff; width: 100%; max-width: 600px; margin: 0px auto; padding: 0px; border-collapse: collapse; border-spacing: 0; border: 0 none;">
Enter fullscreen mode Exit fullscreen mode

There is also limited support for absolute and fixed positioning, as well as Flexbox and grid layouts. The same applies to CSS animations—while you may not often need them, it's still important to keep this in mind.

We can still link external fonts via the <link> tag in the HTML <head> section. However, instead of using em or rem for font sizes, it's generally better to use px for consistency across email clients.

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
Enter fullscreen mode Exit fullscreen mode

h1 {
  font-size: 24px;
  font-weight: 400;
  font-style: normal;
  font-family: "Roboto", sans-serif;
}

Enter fullscreen mode Exit fullscreen mode

Email Showcase

Taking into account all the limitations and rules mentioned above, I created a simple email template for password reset:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Reset Password</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
  <style>
      * {
        font-size: 18px;
        font-weight: 400;
        font-style: normal;
        font-family: "Roboto", sans-serif;
        color: rgba(78, 78, 78, 1);
      }

      .small-text {
        font-size: 14px;
      }

      .normal-text {
        font-size: 18px;
      }

      .big-text {
        font-size: 24px;
      }

      .logo-link {
        font-weight: 700;
        font-style: normal;
        font-family: "Roboto", sans-serif;
        text-decoration: none;
        color: rgba(255, 255, 255, 1);
      }

      .support-link {
        text-decoration: none;
        color: rgba(20, 114, 183, 1);
      }

      .reset-password-link {
        font-weight: 700;
        font-style: normal;
        font-family: "Roboto", sans-serif;
        text-decoration: none;
        padding: 8px 20px;
        border-radius: 30px;
        color: rgba(255, 255, 255, 1);
        background-color: rgba(20, 114, 183, 1);
      }
  </style>
</head>
<body>
  <table role="presentation" width="100%"  cellpadding="0" cellspacing="0">
    <tr align="center">
      <td>
        <table width="100%" cellpadding="8px" bgcolor="rgba(20, 114, 183, 1)" style="max-width: 500px; background-color: rgba(20, 114, 183, 1)">
          <tr align="justify">
            <td align="left">
              <a 
                href="/" 
                class="logo-link" 
                style="display: block; width: 32px; height: 32px; font-weight: 700; font-style: normal; font-family: 'Roboto', sans-serif; text-decoration: none; color: rgba(255, 255, 255, 1);">
                <img width="32px" height="32px" src="https://icon.icepanel.io/Technology/svg/HTML5.svg" alt="logo">
              </a>
            </td>
            <td align="right">
              <a 
                href="/" 
                class="logo-link" 
                style="font-weight: 700; font-style: normal; font-family: 'Roboto', sans-serif; text-decoration: none; color: rgba(255, 255, 255, 1);">
                Name of the app
              </a>
            </td>
          </tr>
        </table>

      </td>
    </tr>
    <tr align="center">
     <td>
      <table cellpadding="8px">
        <tr align="center">
          <td>
            <h1 style="max-width: 500px;">Hi, John Doe,</h1>
            <p style="max-width: 500px;">We're sending you this email because you requested a password reset. Click on this link to create a new password:</p>
          </td>
        </tr>
        <tr align="center">
          <td>
            <a 
              href="/" 
              id="reset-password-link" 
              class="reset-password-link big-text"
              style="font-size: 24px; font-weight: 700; font-style: normal; font-family: 'Roboto', sans-serif; text-decoration: none; padding: 8px 20px; border-radius: 30px; color: rgba(255, 255, 255, 1); background-color: rgba(20, 114, 183, 1);">
              Reset password
            </a>
          </td>
        </tr>
      </table>
     </td>
    </tr>
    <tr align="center">
      <td>
        <table cellpadding="8px">
          <tr>
            <td>
              <hr class="separator">
              <p class="small-text" style="text-align: center; max-width: 500px;">
                If you didn't request password reset, please contact 
                <a
                  href="/" 
                  id="support-link" 
                  class="support-link small-text" 
                  style="text-decoration: none; color: rgba(20, 114, 183, 1);">
                  support</a>,
                your account may be accessed by someone else.
              </p>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Here’s how it looks in the browser:

email-showcase


Conclusion

To sum up, the main criteria for creating emails are as follows: all layouts must be built using tables, and modern tags or attributes should be avoided. It's better to stick to older CSS and duplicate styles within the style attribute for better compatibility.

Since you read till the very end, here is a useful URL that leads to Ethereal, a fake SMTP service primarily aimed at EmailEngine users (but not limited to them). It's a completely free anti-transactional email service where messages never get delivered.

Top comments (9)

Collapse
 
gad profile image
Vladislav

It's also quite common for older email clients to block image domains, which is why images don’t always load properly.

Collapse
 
cookiemonsterdev profile image
Mykhailo Toporkov 🇺🇦

Yeah, Actually you reminded me that JavaScript doesn’t work in emails and can also be blocked by email clients. I’m not sure how I forgot to mention that 😅

Collapse
 
keizzmann profile image
The_Keizzmann😁🎹🎹💻

This is a life saver post for me. Been struggling with this for email services in my applications. Will definitely put this into use.

Thank you for sharing

Collapse
 
svitlana_toporkova_ee618a profile image
Svitlana

Very helpful!

Collapse
 
__e437799 profile image
ANATOLII

Cool!

Collapse
 
wisepanda profile image
Wise Panda

Awesome!

Collapse
 
benderrodriguez profile image
Bender rodriguez

That is what I needed for a long time! Thx!

Collapse
 
hasanabi profile image
Hasan Abi

Wow, that is cool, Thx!

Collapse
 
devabhi404 profile image
DevAbhi

will read this soon, saving for now