Skip to main content

Email Results of a Flow

Question

How can I make a Sendgrid email alert from a step in my Metaflow flow?

Solution

You can format a human-readable report as a Metaflow Card. You can then send the card, which is a simple HTML file, as an email attachment.

1Get Sendgrid API Key

Before using the code in this example to send emails from your Python code, you need to get a Sendgrid API key. You can set this as an environment variable:

export SENDGRID_API_KEY=<YOUR KEY>

2Use Sendgrid's Python Library to Send Email

The following code snippet will be called from the flow. It uses Sendgrid's Python library to send an email with HTML attached. The HTML will contain the contents of a Metaflow card, a quick way to visualize flow artifacts in HTML.

You can replace this send_email function with another one that uses an email provider of your choice. The example flow works the same way with any email provider.

emailer.py
import sendgrid
import base64

def send_email(from_email, to_email, subject, html, key):

message = sendgrid.Mail(
from_email=from_email,
to_emails=to_email,
subject=subject,
plain_text_content='Find a Metaflow card attached'
)

encoded_content = base64.b64encode(
html.encode('utf-8')).decode('utf-8')

att = sendgrid.Attachment(
file_content=encoded_content,
file_type='text/html',
file_name='card.html',
disposition='attachment')

message.add_attachment(att)
sendgrid.SendGridAPIClient(key).send(message)

3Run Flow

This flow shows how to:

  • Pull an image with an internet request.
  • Store the image in a Metaflow card.
  • Access the card and attach it to an email sent with Sendgrid.
  • Pull an image with an HTTP request to show how you can include images in the card. The @card decorator packages them in the HTML file, so the recipient of the email will be able to see them too.
send_email_from_flow.py
import os
from metaflow import FlowSpec, step, current, card, Flow
from metaflow.cards import Markdown, Image, get_cards
import requests
from emailer import send_email

CAT = 'https://upload.wikimedia.org' + \
'/wikipedia/commons/b/b9/CyprusShorthair.jpg'

class EmailCardFlow(FlowSpec):

@card(type='blank')
@step
def start(self):
resp = requests.get(CAT,
headers = {'user-agent': 'metaflow-example'})
current.card.append(Markdown("# Meow mail 🐈"))
current.card.append(Image(resp.content))
self.next(self.end)

@step
def end(self):
send_email(
'your-email@company.com', # put your email
'elon@tesla.com', # put receiver's email
'hi Elon', # put message body
get_cards(
Flow(current.flow_name)[
current.run_id]['start'].task)[0]
.get(),
os.environ.get('SENDGRID_API_KEY')
)

if __name__ == '__main__':
EmailCardFlow()
python send_email_from_flow.py run
     Workflow starting (run-id 757):
[757/start/3764 (pid 48660)] Task is starting.
[757/start/3764 (pid 48660)] Task finished successfully.
[757/end/3765 (pid 48667)] Task is starting.
[757/end/3765 (pid 48667)] Task finished successfully.
Done!

2Visualize Artifact

You can use the following command to look at your card and verify the email sent the same in an HTML attachment.

python send_email_from_flow.py card view start

Further Reading