diff --git a/_posts/python/report-generation/2015-06-30-email-reports.html b/_posts/python/report-generation/2015-06-30-email-reports.html index 9d4ef83804ff..153e96436def 100755 --- a/_posts/python/report-generation/2015-06-30-email-reports.html +++ b/_posts/python/report-generation/2015-06-30-email-reports.html @@ -1,18 +1,15 @@ --- -permalink: python/email-reports/ +permalink: /python/email-reports description: How to email Plotly graphs in HTML reports with Python. name: Emailing Plotly Graphs with Python -has_thumbnail: true -thumbnail: thumbnail/ipython_10_email_report.jpg +has_thumbnail: false +thumbnail: /images/static-image layout: user-guide -page_type: example_index -display_as: report_generation -order: 3 +page_type: u-guide language: python --- -{% raw %} -
-
+{% raw %} +
@@ -27,8 +24,7 @@

Emailing Plotly Graphs

-
-
+
-
-
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 = ''
+
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='')
+    _ = _.format(graph_url=graph, caption='')
     email_body += _
-
+    
 display(HTML(email_body))
 
@@ -92,7 +88,11 @@

Part 1 - An email template -
+
+ +
+ +

Click to comment and see the interactive graph


Click to comment and see the interactive graph


Click to comment and see the interactive graph


Click to comment and see the interactive graph

@@ -104,8 +104,7 @@

Part 1 - An email template -
+
@@ -114,8 +113,7 @@

Part 1 - An email template -
+
-
me  = 'chris@plot.ly'
-recipient = 'chris@plot.ly'
-subject = 'Graph Report'
+
me  = 'chris@plot.ly'
+recipient = 'chris@plot.ly'
+subject = 'Graph Report'
 
-email_server_host = 'smtp.gmail.com'
+email_server_host = 'smtp.gmail.com'
 port = 587
 email_username = me
-email_password = 'xxxxx'
+email_password = 'xxxxx'
 
@@ -144,8 +142,7 @@

Part 2 - Sending the email -
+
@@ -156,20 +153,20 @@

Part 2 - Sending the email
-
In [4]:
+
In [5]:
-
import smtplib
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
+
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 = MIMEMultipart('alternative')
+msg['From'] = me
+msg['To'] = recipient
+msg['Subject'] = subject
 
-msg.attach(MIMEText(email_body, 'html'))
+msg.attach(MIMEText(email_body, 'html'))
 
 server = smtplib.SMTP(email_server_host, port)
 server.ehlo()
@@ -184,8 +181,7 @@ 

Part 2 - Sending the email -
+
@@ -194,16 +190,76 @@

Part 2 - Sending the email -
+ +
+
+
In [6]:
+
+
+
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://plot.ly/~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: embedded image support in emails from 2003

@@ -214,27 +270,27 @@

The graph images
-
In [5]:
+
In [7]:
-
import requests
+
import requests
 import base64
 
-template = (''
-    '<img src="data:image/png;base64,{image}">'
-    '{caption}'                              # Optional caption to include below the graph
-    '<br>'
-    '<hr>'
-'')
+template = (''
+    '<img src="data:image/png;base64,{image}">' 
+    '{caption}'                              # Optional caption to include below the graph
+    '<br>'
+    '<hr>'
+'')
 
-email_body = ''
+email_body = ''
 for graph_url in graphs:
-    response = requests.get(graph_url + '.png') # request Plotly for the image
+    response = requests.get(graph_url + '.png') # request Plotly for the image
     response.raise_for_status()
     image_bytes = response.content
-    image = base64.b64encode(image_bytes)
+    image = base64.b64encode(image_bytes).decode("ascii")
     _ = template
-    _ = _.format(image=image, caption='')
+    _ = _.format(image=image, caption='')
     email_body += _
 
 display(HTML(email_body))
@@ -248,7 +304,11 @@ 

The graph images -
+
+ +
+ +








@@ -260,8 +320,7 @@

The graph images -
+
@@ -272,26 +331,26 @@

The graph images
-
In [6]:
+
In [8]:
-
import plotly.plotly as py
+
import plotly.plotly as py
 
-# A collection of Plotly graphs
+# 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'}}
+    {'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)) for figure in figures]
+# Generate their images using `py.image.get`
+images = [base64.b64encode(py.image.get(figure)).decode("ascii") for figure in figures]
 
-email_body = ''
+email_body = ''
 for image in images:
     _ = template
-    _ = _.format(image=image, caption='')
+    _ = _.format(image=image, caption='')
     email_body += _
-
+    
 display(HTML(email_body))
 
@@ -303,10 +362,14 @@

The graph images -
+
+ +
+ +
-



+



@@ -315,8 +378,7 @@

The graph images -
+
@@ -327,13 +389,13 @@

The graph URLs
-
In [7]:
+
In [9]:
-
import plotly.plotly as py
+
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
+url = py.plot([{'x': [1,2,3], 'y': [3,1,6], 'type': 'bar'}], auto_open=False, filename='email-report-graph-1')
+print(url)
 
@@ -344,9 +406,13 @@

The graph URLs -
+
+ +
+ +
-
https://plot.ly/~christopherp/474
+
https://plot.ly/~PythonPlotBot/3079
 
@@ -355,8 +421,7 @@

The graph URLs -
+
@@ -365,13 +430,12 @@

Updating graphs -
+ + + +{% endraw %} \ No newline at end of file diff --git a/_posts/python/report-generation/email-reports.ipynb b/_posts/python/report-generation/email-reports.ipynb index 1d894d015b95..fdf862e174fd 100755 --- a/_posts/python/report-generation/email-reports.ipynb +++ b/_posts/python/report-generation/email-reports.ipynb @@ -24,9 +24,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# The public plotly graphs to include in the email. These can also be generated with `py.plot(figure, filename)`\n", @@ -41,9 +39,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -102,9 +98,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "me = 'chris@plot.ly'\n", @@ -126,10 +120,8 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 5, + "metadata": {}, "outputs": [], "source": [ "import smtplib\n", @@ -173,10 +165,58 @@ "\n", "Secret links have the form: [https://plot.ly/~<username>/<id>?share_key=<share_key>](). Secret images have \".png\" after \"id\" and before the \"?\". For example:\n", "\n", - "This graph: https://plot.ly/~christopherp/809?share_key=hvNqw1G8ghFzSmsXzFojw0\n", + "This graph: https://plot.ly/~chelsea_lyn/17461?share_key=3kCBg9awEny15vobuAP5Up\n", + "\n", + "Has the secret unlisted image url: https://plot.ly/~chelsea_lyn/17461.png?share_key=3kCBg9awEny15vobuAP5Up" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Click to comment and see the interactive graph

" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display, HTML\n", + "\n", + "template = (''\n", + " '' # Open the interactive graph when you click on the image\n", + " '' # Use the \".png\" magic url so that the latest, most-up-to-date image is included\n", + " ''\n", + " '{caption}' # Optional caption to include below the graph\n", + " '
' # Line break\n", + " ''\n", + " 'Click to comment and see the interactive graph' # Direct readers to Plotly for commenting, interactive graph\n", + " ''\n", + " '
'\n", + " '
' # horizontal line\n", + "'')\n", "\n", - "Has the secret unlisted image url: https://plot.ly/~christopherp/809.png?share_key=hvNqw1G8ghFzSmsXzFojw0\n", + "email_body = ''\n", + "graph = 'https://plot.ly/~chelsea_lyn/17461.png?share_key=3kCBg9awEny15vobuAP5Up'\n", + "_ = template\n", + "_ = _.format(graph_url=graph, caption='')\n", + "email_body += _\n", "\n", + "display(HTML(email_body))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "### The graph images\n", "\n", "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.\n", @@ -190,10 +230,8 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": 7, + "metadata": {}, "outputs": [ { "data": { @@ -224,7 +262,7 @@ " response = requests.get(graph_url + '.png') # request Plotly for the image\n", " response.raise_for_status()\n", " image_bytes = response.content\n", - " image = base64.b64encode(image_bytes)\n", + " image = base64.b64encode(image_bytes).decode(\"ascii\")\n", " _ = template\n", " _ = _.format(image=image, caption='')\n", " email_body += _\n", @@ -241,15 +279,13 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, + "execution_count": 8, + "metadata": {}, "outputs": [ { "data": { "text/html": [ - "



" + "



" ], "text/plain": [ "" @@ -269,7 +305,7 @@ "]\n", "\n", "# Generate their images using `py.image.get`\n", - "images = [base64.b64encode(py.image.get(figure)) for figure in figures]\n", + "images = [base64.b64encode(py.image.get(figure)).decode(\"ascii\") for figure in figures]\n", "\n", "email_body = ''\n", "for image in images:\n", @@ -291,16 +327,14 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, + "execution_count": 9, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "https://plot.ly/~christopherp/474\n" + "https://plot.ly/~PythonPlotBot/3079\n" ] } ], @@ -308,7 +342,7 @@ "import plotly.plotly as py\n", "\n", "url = py.plot([{'x': [1,2,3], 'y': [3,1,6], 'type': 'bar'}], auto_open=False, filename='email-report-graph-1')\n", - "print url" + "print(url)" ] }, { @@ -335,18 +369,14 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[33mYou are using pip version 7.1.0, however version 7.1.2 is available.\r\n", - "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\r\n", - "Requirement already up-to-date: publisher in /Users/chriddyp/Repos/venvpy27/lib/python2.7/site-packages\r\n" + "Requirement already up-to-date: publisher in c:\\anaconda\\anaconda3\\lib\\site-packages (0.13)\n" ] } ], @@ -363,32 +393,30 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.10" + "pygments_lexer": "ipython3", + "version": "3.6.8" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 }