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.
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.
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
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