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;">
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">
h1 {
font-size: 24px;
font-weight: 400;
font-style: normal;
font-family: "Roboto", sans-serif;
}
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>
Here’s how it looks in the browser:
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)
It's also quite common for older email clients to block image domains, which is why images don’t always load properly.
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 😅
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
Very helpful!
Cool!
Awesome!
That is what I needed for a long time! Thx!
Wow, that is cool, Thx!
will read this soon, saving for now