Create Responsive HTML Email
Last updated
Last updated
Posted by Chris Moffitt in articles
As part of managing the PB Python newsletter, I wanted to develop a simple way to write emails once using plain text and turn them into responsive HTML emails for the newsletter. In addition, I needed to maintain a static archive page on the blog that links to the content of each newsletter. This article shows how to use python tools to transform a markdown file into a responsive HTML email suitable for a newsletter as well as a standalone page integrated into a pelican blog.
I am a firm believer in having access to all of the content I create in a simple text format. That is part of the reason why I use pelican for the blog and write all content in restructured text. I also believe in hosting the blog using static HTML so it is fast for readers and simple to distribute. Since I spend a lot of time creating content, I want to make sure I can easily transform it into another format if needed. Plain text files are the best format for my needs.
As I wrote in my previous post, Mailchimp was getting cost prohibitive. In addition, I did not like playing around with formatting emails. I want to focus on content and turning it into a clean and responsive email - not working with an online email editor. I also want the newsletter archives available for people to view and search in a more integrated way with the blog.
One thing that Mailchimp does well is that it provides an archive of emails and ability for the owner to download them in raw text. However, once you cancel your account, those archives will go away. Itâs also not very search engine friendly so itâs hard to reference back to it and expose the content to others not subscribed to the newsletter.
With all that in mind, here is the high level process I had in mind:
Before I go through the python scripts, hereâs some background on developing responsive HTML-based emails. Unfortunately, building a template that works well in all email clients is not easy. I naively assumed that the tips and tricks that work for a web site would work in an HTML email. Unfortunately that is not the case. The best information I could find is that you need to use HTML tables to format messages so they will look acceptable in all the email clients. Yuck. I feel like Iâm back in Geocities.
This is one of the benefits that email vendors like Mailchimp provide. They will go through all the hard work of figuring out how to make templates that look good everywhere. For some this makes complete sense. For my simple needs, it was overkill. Your mileage may vary.
Along the way, I found several resources that I leveraged for portions of my final solution. Here they are for reference:
Building responsive email templates - Really useful templates that served as the basis for the final template.
Free Responsive Simple HTML Template - Another good set of simple templates.
Send email written in Markdown - A python repo that had a lot of good concepts for building the markdown email.
Besides having to use HTML tables, I learned that it is recommended that all the CSS be inlined in the email. In other words, the email needs to have all the styling included in the tags using style
:
Once again this is very old school web and would be really painful if not for tools that will do the inlining for you. I used the excellent premailer library to take an embedded CSS stylesheet and inline with the rest of the HTML.
You can find a full HTML template and all the code on github but here is a simple summary for reference. Please use the github version since this one is severely simplified and likely wonât work as is:
This is a jinja template and you will notice that there is a place for email_content
and title
. The next step in the process is to render a markdown text file into HTML and place that HTML snippet into a template.
Now that we know how we want the HTML to look, letâs create a markdown file. The only twist with this solution is that I want to create one markdown file that can be rendered in pelican and used for the HTML email.
Here is what a simple markdown file( sample_doc.md
) looks like that will work with pelican:
The required input file uses standard markdown. The one tricky aspect is that the top 5 lines contain meta-data that pelican needs to make sure the correct url and templates are used when creating the output. Our final script will need to remove them so that it does not get rendered into the newsletter email. If you are not trying to incorporate into your blog, you can remove these lines.
If you are interested in incorporating this in your pelican blog, here is how my content is structured:
All of the newsletter markdown files are stored in the newsletter directory and the blog posts are stored in the articles directory.
The final configuration I had to make in the pelicanconf.py
file was to make sure the paths were setup correctly:
Now the blog is properly configured to render one of the newsletters.
Now that we have HTML template and the markdown document, we need a short python script to pull it all together. I will be using the following libraries so make sure they are all installed:
python-markdown2 - Turn raw markdown into HTML
jinja2 - Template engine to generate HTML
premailer - Inline CSS
BeautifulSoup - Clean up the HTML. This is optional but showing how to use it if you choose to.
Additionally, make sure you are using python3 so you have access to pathlib
and argparse
.
In order to keep the article compact, I am only including the key components. Please look at the github repo for an approach that is a proper python standalone program that can take arguments from the command line.
The first step, import everything:
Setup the input files and output HTML file:
Please refer to the pathlib article if you are not familiar with how or why to use it.
Now that the files are established, we need to read in the markdown file and parse out the header meta-data:
Using readlines
to read the file ensures that each line in the file is stored in a list. This approach works for our small file but could be problematic if you had a massive file that you did not want to read into memory at once. For an email newsletter you should be ok with using readlines
.
Here is what it all_content[0:6]
looks like:
We can clean up the title line for insertion into the template:
Which renders a title PB Python - Newsletter Number 6
The final parsing step is to get the body into a single list without the header:
Convert the raw markdown into a simple HTML string:
Now that the HTML is ready, we need to insert it into our jinja template:
At this point, raw_html
has a fully formed HTML version of the newsletter. We need to use premailerâs transform
to get the CSS inlined. I am also using BeautifulSoup to do some cleaning up and formatting of the HTML. This is purely aesthetic but I think itâs simple enough to do so I am including it:
The final step is to make sure that the unsubscribe link does not get mangled. Depending on your email provider, you may not need to do this:
Here is an example of the final email file:
You should be able to copy and paste the raw HTML into your email marketing campaign and be good to go. In addition, this file will render properly in pelican. See this page for some past examples.
Markdown is a simple text format that can be parsed and turned into HTML using various python tools. In this case, the markdown file can be combined with a responsive HTML email template to simplify the process of generating content for newsletters. The added bonus is that the content can be included in a static blog so that it is searchable and easily available to your readers.
This solution is not limited to just building emails. Now that newer versions of pandas will include a native to_markdown
method, this general approach could be extended to other uses. Using these principles you can build fairly robust reports and documents using markdown then incorporate the dataframe output into the final results. If there is interest in an example, let me know in the comments.
Reference : https://pbpython.com/markdown-email.html