Building an automated newsletter

How we created a fully automated newsletter for free

And how you can too

Janne Holopainen
Geek Culture

--

This tutorial covers how to start an automated newsletter for free. To follow along you need a Github account and basic knowledge of Python and Git.

I did not want to create a dry listing of code, so I’ve wrapped the tutorial into a true story about a kitesurfing newsletter that I recently started with my friend Joris. This also gives a bit of insight into why these specific technologies are covered in this tutorial. Let’s dive in.

A laptop displaying a pipeline from Github Actions to Python to Gmail
This tutorial covers how Github Actions, Python, and Gmail can be combined to create a free automated newsletter.

“WindSiren”, Joris started, “An app that gives you a notification when good kitesurfing weather is forecasted near you. I’d like us to build it, are you in?”

I did like the concept. It solves a specific problem, it’s easily replicated to other sports, it’s easy to automate, and it can be monetized in a few different ways.

But, building a mobile app requires many hours of upfront coding and publishing one requires a lot of hassle. No way. We needed something simpler.

Choosing to create a newsletter

Fundamentally, we only needed to deliver notifications to our users when the weather conditions are good. This we could do without a mobile app.

After considering a few different notification options, we settled on email for a couple of reasons: Basically, everyone has an email account (whereas for example with WhatsApp that’s no longer the case). It’s easy to send emails through code (SMS would not be so simple). And, it’s possible to track how many users are opening our newsletter (which we eventually did —but that’s for a future post).

To send emails one needs an email provider. We chose Gmail, mostly because we are familiar with it, but also since it’s free and allows us to send 500 emails per day.

Accessing Gmail automatically requires a login method other than the Gmail website. For quick testing, we decided to enable the “less secure apps” login option that allows our script to use the email address and password to login to the Gmail account—but as it goes, we never switched away from that.

If you’re going to start a newsletter, do create a new email account —the email address you use may end on a spam list. We wouldn’t want that for your personal account.

Steps for setting up a newsletter ready Gmail account

1 Create a new Gmail account. This account will be the ‘sender’ of your future newsletter.

2Follow this link to enable ‘less secure apps’ login for Gmail account.

This option does allow any script with your email address and password to log into your account. However, as long as you don’t share the password with anyone, you should be relatively safe.

Send email from Python

For our newsletter, we fetched weather forecasts for the Amsterdam area (we’re based in the Netherlands), and sent an email when good weather conditions would be available during the upcoming week.

This process we wanted to be fully automated using code.

Since Python is my go-to language and it can fetch weather forecasts, send emails, and is supported by Github Actions (more on that later), we chose it as our scripting language.

In short, we used Python strings to generate an HTML email (to make it prettier ✨) and a text-based fallback email (not all email readers show HTML). Then, using the Gmail address and password, we authenticated Python’s smtplib-library to use our Gmail account. And finally, we looped over all the subscriber email addresses and send the newly generated email to everyone.

An email from WindSiren newsletter displaying weather information for Paal 17 Texel
WindSiren newsletter delivered on 1st of November. Quite minimal, but functional.

Editing the emails in Python strings gets tedious quickly. We switched to Jinja2 templates, which improved the situation considerably. But it’s much easier to get started with Python strings, so will stick to them here.

Steps to send an email with Python

1Create a new Python script and a file called .env in your project folder.

Files called .env and newsletter.py stored under automated-newsletter folder.
Visual Studio Code’s view of the project folder (called automated-newsletter) after creating .env and newsletter.py files.

2 Use the format from below and add your new Gmail email address and password into the .env-file.

Example content of the .env-file. Do change the address and password to match your new Gmail account.

Having the Gmail credentials in .env-file allows you to conveniently run the emailing script from your computer. But do not add this file to Git — everyone with access to your repository can read it.

3 Install load_dotenv library by running pip install python-dotenv

4Use load_dotenv to load your Gmail credentials from the .env-file to the Python script.

Loading environmental variables to Python script.

Conveniently, the os.getenv also loads Github secrets — we will need them in a moment.

5 Create the (HTML) email.

6Pass your Gmail credentials to smtplib, login to Gmail’s SMTP (Simple Mail Transfer Protocol) server, and send the email.

It’s a good idea to first send the email to yourself to A: See that the email looks OK, and B: to see if the email is marked as spam — this happened to us initially, but clicking “mark as not spam” fixed the situation and we’ve since ended up consistently on the inbox.

Here’s the entire Python script that loads the Gmail credentials, constructs the email and blasts the newsletter to the subscribers.

Python script for constructing and sending the email. Change the email alternative and content to your content, and add subscriber emails to the subscriber_email_addresses list.

Send the emails automatically

As we prefer projects to cause as little stress as possible, we wanted our newsletter script to run daily without us having to lift a finger. Therefore, we turned to Github Actions.

Github Actions are a tool for developers to automatically test and publish their code. They can be used to execute complex and almost arbitrary scripts, and importantly for us, they can be configured to run periodically at set times. The tool is free for public repositories, and private repositories receive 2,000 minutes of free runtime every month. Which is plenty for generating and sending a daily newsletter.

Every morning around 7:15, our Github Action workflow wakes up and checks out our latest code from our Github repository. It installs the necessary requirements and runs a Python script that fetches the weather forecasts and digests them into a kitesurfing newsletter.

The only thing left for me was to check my personal email for any failures in the workflow. But, after the initial setup, there have not been any. Hell, I even went on a 3-week trip without my laptop while Github Actions was managing our project. Really makes me appreciate automation.

Steps to automate the newsletter

1Create a folder .github on the root of your project folder. Inside the .github-folder create another folder called workflows, inside which create a new file called newsletter.yml.

Files called .env, newsletter.py, and .github/workflow/newsletter.yml stored under automated-newsletter folder.
Visual Studio Code’s view of the project folder after creating newsletter.yml.

The .yml files in this specific folder store the instructions to run your Github Actions.

2 Copy the workflow from below to newsletter.yml, or follow Github’s documentation to create a cron-triggered workflow. Commit newsletter.yml to your Git.

3 In your Github repository’s settings, go to secrets and add your Gmail email address and passwords as secrets. The names of the secrets need to match the variable names that you load using os.getenv in the Python script.

Github secrets containing Gmail address, password, and API key for OpenWeatherMap
Here’s our secrets page. Yes, we use OpenWeatherMap API for fetching the weather reports. We had a good experience with their API.

Storing your credentials here is safe, as you can only see the name of the secret — not the value that is stored within the secret.

4 Push your project folder to your Github repository.

Voilà, you’re all set up with an automated newsletter.

What happened to our newsletter?

We wanted to be data-driven on this project, so we decided to track how many people open our newsletter. We created a custom solution to track how often subscribers open our newsletters. And that’s where we started to rack up some ‘expenses’ (well, Google Cloud Platform gives you 300$ of trial credits, so not really ‘expenses’ 🤷‍♂️).

Graph of WindSiren newsletter opening rates, showing a downward trend
The percentage of users that opened the daily newsletter, with a rather clear downwards trend. Do people kitesurf in November? I don’t know, but I’d rather not spam the mailbox of our subscribers.

By tracking the opening rate, we learned that fewer and fewer users were opening our newsletter, and as our tracking solution costs about 50$/month the dream of a passive income did not quite manifest itself through this project. So at least until next summer, our newsletter is gonna be in winter hibernation.

--

--

Janne Holopainen
Geek Culture

Serial experimenter and Machine Learning enthusiast | Data Scientist | Trying to make complicated ideas simple