Skip to content

Send emails in HTML format

In this tutorial, we will create a flow to send welcome emails to users who have subscribed to a list.

In this tutorial we'll:

  • Create a base template to be used in all emails.
  • Create a welcome template to be sent to new users.
  • Create a flow that sends a welcome email.

Sources

Sources for this tutorial can be found in the examples/email folder of this repository.

Getting Started

Python setup

Requires an installation of Python 3.7+.

We recommend using a Python virtual environment manager such as pipenv, conda or virtualenv.

This flow is designed to work with Prefect 2.0. For more information about how to use Prefect, please refer to the Prefect documentation.

prefect-email

This tutorial requires the prefect-email collection installed to send emails.

Installation

Install prefect-jinja and prefect-email with pip:

pip install prefect-jinja prefect-email

Then, register to view blocks on Prefect Cloud:

prefect block register -m prefect_jinja.blocks

prefect block register -m prefect_email.credentials

Project Structure

Let's consider the following project structure:

├── flows
│   ├── templates
│   │    ├── base.html
│   │    └── welcome.html
│   └── send_welcome.py
└── requirements.txt

Run the command below to create the required directories:

mkdir -p flows/templates 

Blocks

Open the Prefect UI and navigate to the Blocks page.

To create a new block, select the + button on this page, or if you haven't previously created any blocks, New Block. Prefect displays a page of available block types.

For this tutorial, we will use the Jinja Environment and Email Server Credentials blocks.

Jinja Environment

Scroll down the list of blocks and find the Jinja Environment block, then select Add + to configure a new block.

Previewing the creation of the Jinja Environment block in the Prefect UI.

Enter the configuration for your Jinja Environment:

  • Block Name is the name by which your block is referenced. The name must only contain lowercase letters, numbers, and dashes.
  • Namespace contains the variables that are available in every template loaded by the block.
  • Search Path is the name of the directory where the templates are stored. Can be relative or absolute. Relative paths are relative to the running flow directory.

In this tutorial, we will use the following settings:

  • Block Name: email-templates
  • Namespace:
    {
        "logo": "https://d33wubrfki0l68.cloudfront.net/504beb80ec8dfc980a28612dd72249b413897927/8118e/assets/prefect-logo-gradient-navy.svg",
        "slack": "https://prefect.io/slack",
        "discourse": "https://discourse.prefect.io"
    }
    
  • Search Path: templates

Select Create to create the block. Prefect displays the details of the new block, including a code example to use in your flow code.

Email Server Credentials

Navigate back to the Blocks page and select the + button on this page to create a new block. Scroll down the list of blocks and find the Email Server Credentials block, then select Add + to configure a new block.

Previewing the creation of the Email Server Credentials block in the Prefect UI.

Enter the configuration for your email server:

  • Block Name is the name by which your block is referenced. The name must only contain lowercase letters, numbers, and dashes.
  • Username: The username to use for authentication to the server.
  • Password: The password to use for authentication to the server.
  • SMTP Server: Either the hostname of the SMTP server, or one of the keys from the built-in SMTPServer Enum members, like "gmail".
  • SMTP Type: Either "SSL", "STARTTLS", or "INSECURE".
  • SMPT Port: If provided, overrides the smtp_type's default port number.

In this tutorial, we will use the following settings:

  • Block Name: outgoing-mail-server

Username, Password and SMTP Server

The values of these fields were not displayed for security reasons. Check with your email provider for the correct values for these fields.

Select Create to create the block. Prefect displays the details of the new block, including a code example to use in your flow code.

Templates

As this repository may contain other email flows, let's create a base template to standardize the layout of all emails. Next, let's create the welcome template.

Base

Create a file named base.html inside the flows/templates directory with the following content:

<!DOCTYPE html>
<html>
<head><title>{% block title %}{% endblock %}</title>
<body>
<table width="100%">
    <tr>
        <td align="center">
            <img alt="Logo" src="{{ logo }}" width="200px" height="50px">
        </td>
    </tr>
    <tr>
        <td>
            {% block content %}{% endblock %}
        </td>
    </tr>
</table>
</body>
</html>

Welcome

Create a file named welcome.html inside the flows/templates directory with the following content:

{% extends "base.html" %}

{% block title %}Welcome to Prefect{% endblock %}

{% block content %}
<p>Hi {{ username }}!</p>
<p>
    Having any trouble upgrading to Prefect 2.0 at all? Try out our 
    <a href="https://www.youtube.com/watch?v=YyAQ61eRGhI&list=PLZfWmQS5hVzF3u9FY4-43U4UoTblFgC2l">
        full YouTube playlist
    </a> of migration content!
</p>
<p>
    If you need any help, please don't hesitate to reach out in our 
    <a href="{{ slack }}">Slack community</a>
    or 
    <a href="{{ discourse }}">Discourse forum</a>!
</p>
<p>Happy Engineering,</p>
<p>Prefect Customer Success Team</p>
{% endblock %}

Flow

Create the send_welcome.py inside the flows directory with the following content:

from prefect import flow
from prefect_email import EmailServerCredentials, email_send_message
from prefect_jinja import JinjaEnvironmentBlock, jinja_render_from_template

@flow
def send_welcome_flow(username: str, email_to: str):
    jinja_environment = JinjaEnvironmentBlock.load("email-templates")
    email_body = jinja_render_from_template(
        "welcome.html", 
        jinja_environment, 
        username=username
    )

    email_server_credentials = EmailServerCredentials.load("outgoing-mail-server")
    email_send_message(
        email_server_credentials=email_server_credentials,
        subject="Welcome to Prefect",
        msg=email_body,
        email_to=email_to,
    )

if __name__ == '__main__':
    result = send_welcome_flow(username="Jeronimo", email_to="jeronimo@example.com")
    print(result)

Running

Enter the flows directory. Then run the send_welcome.py flows with python:

cd flows

python send_welcome.py

The template will be rendered and send by the prefect-email with the following content:

<!DOCTYPE html>
<html>
<head><title>Welcome to Prefect</title>
<body>
<table width="100%">
    <tr>
        <td align="center">
            <img alt="Logo" src="https://d33wubrfki0l68.cloudfront.net/504beb80ec8dfc980a28612dd72249b413897927/8118e/assets/prefect-logo-gradient-navy.svg" width="200px" height="50px">
        </td>
    </tr>
    <tr>
        <td>
            <p>Hi Jeronimo!</p>
            <p>
                Having any trouble upgrading to Prefect 2.0 at all? Try out our 
                <a href="https://www.youtube.com/watch?v=YyAQ61eRGhI&list=PLZfWmQS5hVzF3u9FY4-43U4UoTblFgC2l"> 
                    full YouTube playlist
                </a> of migration content!
            </p>
            <p>
                If you need any help, please don't hesitate to reach out in our 
                <a href="https://prefect.io/slack">Slack community</a>
                or 
                <a href="https://discourse.prefect.io">Discourse forum</a>!
            </p>
            <p>Happy Engineering,</p>
            <p>Prefect Customer Success Team</p>
        </td>
    </tr>
</table>
</body>
</html>

That's it 🥳. Now emails sent through Prefect flows will look more elegant.

I hope this helps you.