Emailing Plotly Graphs with Python in Python/v3
How to email Plotly graphs in HTML reports with Python.
See our Version 4 Migration Guide for information about how to upgrade.
Emailing Plotly Graphs¶
In the Plotly Webapp you can share your graphs over email to your colleagues who are also Plotly members. If your making graphs periodically or automatically, e.g. in Python with a cron job, it can be helpful to also share the graphs that you're creating in an email to your team.
This notebook is a primer on sending nice HTML emails with Plotly graphs in Python. We use:
- Plotly for interactive, web native graphs
- IPython Notebook to create this notebook, combining text, HTML, and Python code
smtplib
andemail
libraries included in the Python standard library
Part 1 - An email template¶
# The public plotly graphs to include in the email. These can also be generated with `py.plot(figure, filename)`
graphs = [
'https://plotly.com/~christopherp/308',
'https://plotly.com/~christopherp/306',
'https://plotly.com/~christopherp/300',
'https://plotly.com/~christopherp/296'
]
from IPython.display import display, HTML
template = (''
'<a href="{graph_url}" target="_blank">' # Open the interactive graph when you click on the image
'<img src="{graph_url}.png">' # Use the ".png" magic url so that the latest, most-up-to-date image is included
'</a>'
'{caption}' # Optional caption to include below the graph
'<br>' # Line break
'<a href="{graph_url}" style="color: rgb(190,190,190); text-decoration: none; font-weight: 200;" target="_blank">'
'Click to comment and see the interactive graph' # Direct readers to Plotly for commenting, interactive graph
'</a>'
'<br>'
'<hr>' # horizontal line
'')
email_body = ''
for graph in graphs:
_ = template
_ = _.format(graph_url=graph, caption='')
email_body += _
display(HTML(email_body))
Looks pretty good!
Part 2 - Sending the email¶
Email server settings. This example will use the common settings for gmail
me = 'chris@plot.ly'
recipient = 'chris@plot.ly'
subject = 'Graph Report'
email_server_host = 'smtp.gmail.com'
port = 587
email_username = me
email_password = 'xxxxx'
Send the email
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os
msg = MIMEMultipart('alternative')
msg['From'] = me
msg['To'] = recipient
msg['Subject'] = subject
msg.attach(MIMEText(email_body, 'html'))
server = smtplib.SMTP(email_server_host, port)
server.ehlo()
server.starttls()
server.login(email_username, email_password)
server.sendmail(me, recipient, msg.as_string())
server.close()
Notes¶
Sharing Private Images¶
Plotly graphs are public by default. This means that they will appear on your profile, the plotly feed, google search results.
To share private images in an email, make your graphs "secret". The graphs will be unlisted from your profile but will still be accessible by the email server via a direct link - no login authentication is required.
Secret links have the form: https://plotly.com/~<username>/<id>?share_key=<share_key>. Secret images have ".png" after "id" and before the "?". For example:
This graph: https://plotly.com/~chelsea_lyn/17461?share_key=3kCBg9awEny15vobuAP5Up
Has the secret unlisted image url: https://plotly.com/~chelsea_lyn/17461.png?share_key=3kCBg9awEny15vobuAP5Up
from IPython.display import display, HTML
template = (''
'<a href="{graph_url}" target="_blank">' # Open the interactive graph when you click on the image
'<img src="{graph_url}">' # Use the ".png" magic url so that the latest, most-up-to-date image is included
'</a>'
'{caption}' # Optional caption to include below the graph
'<br>' # Line break
'<a href="{graph_url}" style="color: rgb(190,190,190); text-decoration: none; font-weight: 200;" target="_blank">'
'Click to comment and see the interactive graph' # Direct readers to Plotly for commenting, interactive graph
'</a>'
'<br>'
'<hr>' # horizontal line
'')
email_body = ''
graph = 'https://plotly.com/~chelsea_lyn/17461.png?share_key=3kCBg9awEny15vobuAP5Up'
_ = template
_ = _.format(graph_url=graph, caption='')
email_body += _
display(HTML(email_body))
The graph images¶
The HTML template that we used includes the images by their URL on the Plotly server. The viewers of the email must have permission on Plotly to view your graph. Graphs sent in emails by Chart Studio Enterprise users on private networks will not be able to be viewed outside of the network.
The reader of your email will always see the latest verison of the graph! This is great - if you tweak your graph or add an annotation, you don't need to resend the email out. If your graph updates regularly, e.g. every hour, the reader will see the latest, most updated version of the chart.
For some email clients, you can download the image and include it inline the email. This allows you to share the graph outside of your network with Chart Studio Enterprise, and keep the graph entirely private. Note that this is not widely supported. Here is the support from a few years ago:
Here is how to embed images inline in HTML:
import requests
import base64
template = (''
'<img src="data:image/png;base64,{image}">'
'{caption}' # Optional caption to include below the graph
'<br>'
'<hr>'
'')
email_body = ''
for graph_url in graphs:
response = requests.get(graph_url + '.png') # request Plotly for the image
response.raise_for_status()
image_bytes = response.content
image = base64.b64encode(image_bytes).decode("ascii")
_ = template
_ = _.format(image=image, caption='')
email_body += _
display(HTML(email_body))
Alternatively, you can create the image on the fly, without a URL using py.image.get
. (Learn more about py.image
by calling help(py.image)
)
import plotly.plotly as py
# A collection of Plotly graphs
figures = [
{'data': [{'x': [1,2,3], 'y': [3,1,6]}], 'layout': {'title': 'the first graph'}},
{'data': [{'x': [1,2,3], 'y': [3,7,6], 'type': 'bar'}], 'layout': {'title': 'the second graph'}}
]
# Generate their images using `py.image.get`
images = [base64.b64encode(py.image.get(figure)).decode("ascii") for figure in figures]
email_body = ''
for image in images:
_ = template
_ = _.format(image=image, caption='')
email_body += _
display(HTML(email_body))
The graph URLs¶
We hard-coded the graph URLs above, but we can also generate the URLs with py.plot
:
import plotly.plotly as py
url = py.plot([{'x': [1,2,3], 'y': [3,1,6], 'type': 'bar'}], auto_open=False, filename='email-report-graph-1')
print(url)
Updating graphs¶
If we use the same filename
, the graph will save to the same URL. So, if we include a graph in an email by it's URL, we can update that graph by calling py.plot
with the same filename.