def gchart(data, node, check, metric, start=datetime.now() - timedelta(days=1), end=datetime.now()): d = [] ts = [] for p in data['metrics'][0]['data']: d.append(float(p['avg'])) ts.append(p['ts']) # Chart size of 200x125 pixels and specifying the range for the Y axis max_y = int(max(d)) chart = SimpleLineChart(450, 250, y_range=[0, max_y]) chart.add_data(d) left_axis = range(0, max_y + 1, max_y / 5) left_axis[0] = '' chart.set_axis_labels(Axis.LEFT, left_axis) min_dt = datetime.fromtimestamp(min(ts)) max_dt = datetime.fromtimestamp(max(ts)) chart.set_axis_labels(Axis.BOTTOM, [str(min_dt), str(max_dt)]) title = '%s.%s.%s' % (node['name'], check['type'], metric) chart.set_title(title) return chart.get_url()
class DiceChart: chart = None def __init__(self, data, iter=0, width=300, height=300): self.chart = SimpleLineChart(width, height, y_range=(0, 10)) legend = [] colors = ["cc0000", "00cc00", "0000cc", "990000", "009900", "000099", "0099ff", "FF9900", "9900ff", "ff0099"] title = "die rolls per objective" if iter > 0: title = title + " (%s samples)" % iter for i in data.keys(): self.chart.add_data(data[i]) legend.append(str(i)) logging.debug(legend) logging.debug(colors) self.chart.set_colours(colors) self.chart.set_legend(legend) grid_x_amount = 100 / (len(data[i]) - 1) self.chart.set_grid(grid_x_amount, 10, 5, 5) left_axis = range(0, 11, 1) left_axis[0] = "" self.chart.set_axis_labels(Axis.LEFT, left_axis) bottom_len = len(data[i]) + 2 bottom_axis = range(2, bottom_len, 1) self.chart.set_axis_labels(Axis.BOTTOM, bottom_axis) self.chart.set_title(title) def download(self, name="dicechart.png"): self.chart.download(name)
def getRollingAverageGraph(cursor, colName, rollingWindowDays, title=""): sqlCMD = "SELECT pDate, %s from %s" %(colName, N.JOBS_SUMMARY_TABLENAME) cursor.execute(sqlCMD) results = cursor.fetchall() beginWindowIndex = 0 endWindowIndex = 0 xData = [] yData = [] while endWindowIndex < len(results): while endWindowIndex < len(results) and (results[endWindowIndex][0] - results[beginWindowIndex][0]).days <= rollingWindowDays: endWindowIndex += 1 yData.append( sum(results[i][1] for i in xrange(beginWindowIndex, endWindowIndex, 1)) / float(endWindowIndex - beginWindowIndex)) xData.append(results[endWindowIndex-1][0]) beginWindowIndex = endWindowIndex chart = SimpleLineChart(680, 400, y_range = (min(yData)-1, max(yData)+1)) chart.add_data(yData) yLabels = range(0, int(max(yData)+1), 5) yLabels[0] = '' xLabels = [str(xData[-i]) for i in xrange(1, len(xData)-1, int(0.2*len(xData)))] xLabels.reverse() chart.set_axis_labels(Axis.LEFT, yLabels) chart.set_axis_labels(Axis.BOTTOM, xLabels) chart.set_title("Rolling %i-Day Average %s" % (rollingWindowDays, title)) imgbin = chart.download() toReturn = cStringIO.StringIO(imgbin) toReturn.seek(0) return chart.get_url(), toReturn
def simple_line(): chart = SimpleLineChart(settings.width, settings.height, x_range=(0, 35)) chart.set_colours(['00ff00', 'ff0000','ACff0C','B0ffE0','C0ffFF']) chart.add_data([1,2,3,4,5]) chart.add_data([1,4,9,16,25]) chart.set_title('This is title') chart.set_axis_labels('r', 'str') chart.set_legend( ['a','b','c','d','e']) chart.download('simple-line.png')
def lineGraphFeed(feed): name = feed.getAttribute("name") observations = feed.getElementsByTagName("observation") print " Feed %s has %d observations" % (name,len(observations)) data = [] for obs in observations: value = int(obs.getAttribute("value")) #print " val:%s (%s)" % (value, type(value)) data.insert(0,value/10) #data.reverse # remeber the feed is reversed print "Max Data: %s" % max(data) max_y = int(math.ceil(max(data)/100.0))*100 print "Max_y : %s" % max_y chart = SimpleLineChart(180, 120, y_range=[0, max_y]) chart.add_data(data) lftAxisMax = max_y/100; print "lftAxisMax %s"%lftAxisMax #left_axis = range(0, lftAxisMax,(lftAxisMax/4.0)) left_axis = [] right_axis = [] for i in range(0,4+1): kw = (i*lftAxisMax/4.0) left_axis.append(kw) right_axis.append(kw*24) left_axis[0] = 'kW' # remove the first label right_axis[0] = 'kWh/d' # remove the first label chart.set_axis_labels(Axis.LEFT, left_axis) #chart.set_axis_labels(Axis.RIGHT, right_axis) chart.set_title(name) # facebook colors chart.set_title_style('7f93bc',16) #chart.set_colours(['7f93bc']) chart.set_colours(['3b5998']) #darker blue #Colors colors=False if (colors): # Set the line colour to ... chart.set_colours(['FFFFFF']) # 0 here is the axis index ? 0 works for now chart.set_title_style('FFFFFF',16) chart.set_axis_style(0,'FFFFFF') chart.set_axis_style(1,'FFFFFF') chart.fill_linear_gradient(Chart.BACKGROUND,90,'000000',0.9,'007700',0.1) print chart.get_url() chart.download('%s-line.png'%name)
def printGoogleCharts(X, Y, title, min_y, max_y, output): # Create a chart object of 750x400 pixels chart = SimpleLineChart(750, 400) # Add some data chart.add_data(Y) # Assign the labels to the pie data # chart.set_axis_labels(Axis.BOTTOM, X) chart.set_axis_labels(Axis.LEFT, range(int(min_y)-1, int(max_y)+1, 5)) chart.set_title(title) # Print the chart URL print chart.get_url() # Download the chart chart.download(output+".png")
def gchart(data, node, check, metric, start=datetime.now()-timedelta(days=1), end=datetime.now()): d = [] ts = [] for p in data['metrics'][0]['data']: d.append(float(p['avg'])) ts.append(p['ts']) # Chart size of 200x125 pixels and specifying the range for the Y axis max_y = int(max(d)) chart = SimpleLineChart(450, 250, y_range=[0,max_y]) chart.add_data(d) left_axis = range(0, max_y + 1, max_y/5) left_axis[0] = '' chart.set_axis_labels(Axis.LEFT, left_axis) min_dt = datetime.fromtimestamp(min(ts)) max_dt = datetime.fromtimestamp(max(ts)) chart.set_axis_labels(Axis.BOTTOM, [ str(min_dt), str(max_dt) ]) title = '%s.%s.%s' % (node['name'], check['type'], metric) chart.set_title(title) return chart.get_url()
def users(*args): days = 60 from django.db import connection cursor = connection.cursor() cursor.execute( "SELECT date_joined, COUNT(*) from auth_user where date_joined > NOW() - INTERVAL %i DAY group by DATE(date_joined) order by DATE(date_joined) desc" % days) data = {} max_y = 0 for dt, num in cursor.fetchall(): if num > max_y: max_y = num data[dt.date()] = num data2 = [] dt = date.today() - timedelta(days - 1) for i in xrange(days): data2.append((dt, data.get(dt, 0))) dt = dt + timedelta(1) chart = SimpleLineChart(800, 125, y_range=[0, max_y]) chart.add_data([row[1] for row in data2]) chart.set_colours(['0000FF']) ticks = (max_y % 25) + 1 left_axis = range(0, max_y, 25) left_axis[0] = '' chart.set_axis_labels(Axis.RIGHT, left_axis) bottom_axis = [ dt[0].strftime("%b") if dt[0].day == 1 else '' for dt in data2 ] chart.set_axis_labels(Axis.BOTTOM, bottom_axis) chart.set_title("Daily Registrations") data2.reverse() return chart
def linegraph(self,days,bars,output,title = ""): data = [] min_count = 0 max_count = 0 date = lambda i:datetime.date.today() + datetime.timedelta(-days + i) for i in range(0,days+1): count = bars[date(i)] max_count = max(count,max_count) min_count = min(count,min_count) data.append(count) chart = SimpleLineChart(800,350,y_range=[min_count, 60000]) chart.add_data(data) # Set the line colour to blue chart.set_colours(['0000FF']) # Set the vertical stripes d = max(1/float(days),round(7/float(days),2)) chart.fill_linear_stripes(Chart.CHART, 0, 'CCCCCC', d, 'FFFFFF', d) fmt="%d/%m" chart.set_axis_labels(Axis.BOTTOM, \ [date(i).strftime(fmt) for i in range(0,days,7)]) # Set the horizontal dotted lines chart.set_grid(0, 25, 5, 5) # The Y axis labels contains 0 to 100 skipping every 25, but remove the # first number because it's obvious and gets in the way of the first X # label. delta = float(max_count-min_count) / 100 skip = int(delta) / 5 * 100 left_axis = range(0, 60000 + 1, skip) left_axis[0] = '' chart.set_axis_labels(Axis.LEFT, left_axis) if len(title) > 0: chart.set_title(title % days) chart.download(output)
def linegraph(self, days, bars, output, title=""): data = [] min_count = 0 max_count = 0 date = lambda i: datetime.date.today() + datetime.timedelta(-days + i) for i in range(0, days + 1): count = bars[date(i)] max_count = max(count, max_count) min_count = min(count, min_count) data.append(count) chart = SimpleLineChart(800, 350, y_range=[min_count, 60000]) chart.add_data(data) # Set the line colour to blue chart.set_colours(['0000FF']) # Set the vertical stripes d = max(1 / float(days), round(7 / float(days), 2)) chart.fill_linear_stripes(Chart.CHART, 0, 'CCCCCC', d, 'FFFFFF', d) fmt = "%d/%m" chart.set_axis_labels(Axis.BOTTOM, \ [date(i).strftime(fmt) for i in range(0,days,7)]) # Set the horizontal dotted lines chart.set_grid(0, 25, 5, 5) # The Y axis labels contains 0 to 100 skipping every 25, but remove the # first number because it's obvious and gets in the way of the first X # label. delta = float(max_count - min_count) / 100 skip = int(delta) / 5 * 100 left_axis = range(0, 60000 + 1, skip) left_axis[0] = '' chart.set_axis_labels(Axis.LEFT, left_axis) if len(title) > 0: chart.set_title(title % days) chart.download(output)
def users(*args): days = 60 from django.db import connection cursor = connection.cursor() cursor.execute("SELECT date_joined, COUNT(*) from auth_user where date_joined > NOW() - INTERVAL %i DAY group by DATE(date_joined) order by DATE(date_joined) desc" % days) data = {} max_y = 0; for dt, num in cursor.fetchall(): if num > max_y: max_y = num; data[dt.date()] = num data2 = [] dt = date.today() - timedelta(days-1) for i in xrange(days): data2.append((dt, data.get(dt, 0))) dt = dt + timedelta(1) chart = SimpleLineChart(800, 125, y_range=[0, max_y]) chart.add_data([row[1] for row in data2]) chart.set_colours(['0000FF']) ticks = (max_y % 25) + 1 left_axis = range(0, max_y, 25) left_axis[0] = '' chart.set_axis_labels(Axis.RIGHT, left_axis) bottom_axis = [dt[0].strftime("%b") if dt[0].day == 1 else '' for dt in data2] chart.set_axis_labels(Axis.BOTTOM, bottom_axis) chart.set_title("Daily Registrations") data2.reverse() return chart
def getRollingAverageGraph(cursor, colName, rollingWindowDays, title=""): sqlCMD = "SELECT pDate, %s from %s" % (colName, N.JOBS_SUMMARY_TABLENAME) cursor.execute(sqlCMD) results = cursor.fetchall() beginWindowIndex = 0 endWindowIndex = 0 xData = [] yData = [] while endWindowIndex < len(results): while endWindowIndex < len(results) and ( results[endWindowIndex][0] - results[beginWindowIndex][0]).days <= rollingWindowDays: endWindowIndex += 1 yData.append( sum(results[i][1] for i in xrange(beginWindowIndex, endWindowIndex, 1)) / float(endWindowIndex - beginWindowIndex)) xData.append(results[endWindowIndex - 1][0]) beginWindowIndex = endWindowIndex chart = SimpleLineChart(680, 400, y_range=(min(yData) - 1, max(yData) + 1)) chart.add_data(yData) yLabels = range(0, int(max(yData) + 1), 5) yLabels[0] = '' xLabels = [ str(xData[-i]) for i in xrange(1, len(xData) - 1, int(0.2 * len(xData))) ] xLabels.reverse() chart.set_axis_labels(Axis.LEFT, yLabels) chart.set_axis_labels(Axis.BOTTOM, xLabels) chart.set_title("Rolling %i-Day Average %s" % (rollingWindowDays, title)) imgbin = chart.download() toReturn = cStringIO.StringIO(imgbin) toReturn.seek(0) return chart.get_url(), toReturn
def email_report(email, download_link, daily_report, weekly_report, host, port, login=None, password=None, dry_run=False, verbose=False): daily = [v[0] for k, v in daily_report.items()] if daily_report else [] weekly = [v[0] for k, v in weekly_report.items()] if weekly_report else [] cumulative_data = daily_report if daily_report else weekly_report if cumulative_data is None: raise Exception("No data given to generate a cumulative report!") cumulative = [v[1] for k, v in cumulative_data.items()] width, height = 700, 300 # Create the charts daily_chart = SimpleLineChart(width, height) weekly_chart = SimpleLineChart(width, height) cumulative_chart = SimpleLineChart(width, height) # Titles daily_chart.set_title('Daily Downloads') weekly_chart.set_title('Weekly Downloads') cumulative_chart.set_title('Cumulative Downloads') # Add data if daily: daily_chart.add_data(daily) daily_chart.set_axis_range(Axis.LEFT, 0, max(daily)) daily_chart.set_axis_labels(Axis.RIGHT, [min(daily), max(daily)]) if weekly: weekly_chart.add_data(weekly) weekly_chart.set_axis_range(Axis.LEFT, 0, max(weekly)) weekly_chart.set_axis_labels(Axis.RIGHT, [min(weekly), max(weekly)]) cumulative_chart.add_data(cumulative) cumulative_chart.set_axis_range(Axis.LEFT, 0, max(cumulative)) cumulative_chart.set_axis_labels( Axis.RIGHT, [min(cumulative), max(cumulative)]) # Set the styling marker = ('B', 'C5D4B5BB', '0', '0', '0') colors = ['3D7930', 'FF9900'] daily_chart.markers.append(marker) weekly_chart.markers.append(marker) cumulative_chart.markers.append(marker) daily_chart.set_colours(colors) weekly_chart.set_colours(colors) cumulative_chart.set_colours(colors) grid_args = 0, 10 grid_kwargs = dict(line_segment=2, blank_segment=6) daily_chart.set_grid(*grid_args, **grid_kwargs) weekly_chart.set_grid(*grid_args, **grid_kwargs) cumulative_chart.set_grid(*grid_args, **grid_kwargs) #daily_chart.fill_linear_stripes( # Chart.CHART, 0, 'CCCCCC', 0.2, 'FFFFFF', 0.2) daily_chart_url = daily_chart.get_url() if daily else None weekly_chart_url = weekly_chart.get_url() if weekly else None cumulative_chart_url = cumulative_chart.get_url() # Create recent versions of the charts if daily: recent_daily = daily[-90:] # Get last year's daily data. First, get the first date for the daily # data. start = daily_report.items()[-90][0] dt = datetime.datetime.strptime(start, '%Y/%m/%d') dt = dt - datetime.timedelta(weeks=52) last_year_datestr = datetime_to_str(dt) # Get the index in the data for the datestr try: i = daily_report.keys().index(last_year_datestr) recent_daily_comparison = daily[i:i + 90] except ValueError: recent_daily_comparison = [] if recent_daily_comparison: daily_chart.data = [recent_daily, recent_daily_comparison] else: daily_chart.data = [recent_daily] # Reset the axes daily_chart.axis = [] min_daily = min(recent_daily + recent_daily_comparison) max_daily = max(recent_daily + recent_daily_comparison) daily_chart.set_axis_range(Axis.LEFT, 0, max_daily) daily_chart.set_axis_labels(Axis.RIGHT, [min_daily, max_daily]) daily_chart.set_title('Recent Daily Downloads (filled is now)') daily_recent_chart_url = daily_chart.get_url() else: daily_recent_chart_url = None if verbose: print('Daily: ' + daily_chart_url) if daily_chart_url else None print('Weekly: ' + weekly_chart_url) if weekly_chart_url else None print('Cumulative: ' + cumulative_chart_url) print('Daily Recent: ' + daily_recent_chart_url) if daily_recent_chart_url else None # Create the body of the message (a plain-text and an HTML version). text = "Get an HTML mail client." html = """\ <html> <body> <h2>Latest download count: {latest_daily}</h2> <h2>Latest weekly download count: {latest_weekly}</h2> <h2>Latest cumulative total: {cumulative}</h2> <p><a href="{download}">Download today's report</a>.</p> <p><img src="cid:daily.png" width="{width}" height="{height}" alt="Daily Downloads" /></p> <p><img src="cid:weekly.png" width="{width}" height="{height}" alt="Weekly Downloads" /></p> <p><img src="cid:cumulative.png" width="{width}" height="{height}" alt="Cumulative Downloads" /></p> <p><img src="cid:daily-recent.png" width="{width}" height="{height}" alt="Recent Daily Downloads" /></p> </body> </html>""".format( latest_daily=daily[-1] if daily else 0, latest_weekly=weekly[-1] if weekly else 0, cumulative=cumulative[-1], download=download_link, width=width, height=height, ) # Create message container - the correct MIME type is multipart/alternative. message_root = MIMEMultipart('related') message_root['Subject'] = "Daily iTunes Download Report" message_root['From'] = email message_root['To'] = email message_root.preamble = 'This is a multi-part message.' # Record the MIME types of both parts - text/plain and text/html. alternative = MIMEMultipart('alternative') message_root.attach(alternative) part1 = MIMEText(text, 'plain') part2 = MIMEText(html, 'html') # Attach parts into message container. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. alternative.attach(part1) alternative.attach(part2) # Get the images if daily_chart_url: r = requests.get(daily_chart_url) img = MIMEImage(r.content) img.add_header('Content-ID', '<daily.png>') message_root.attach(img) if weekly_chart_url: r = requests.get(weekly_chart_url) img = MIMEImage(r.content) img.add_header('Content-ID', '<weekly.png>') message_root.attach(img) r = requests.get(cumulative_chart_url) img = MIMEImage(r.content) img.add_header('Content-ID', '<cumulative.png>') message_root.attach(img) if daily_recent_chart_url: r = requests.get(daily_recent_chart_url) img = MIMEImage(r.content) img.add_header('Content-ID', '<daily-recent.png>') message_root.attach(img) try: # Send the message via local SMTP server. s = smtplib.SMTP(host, port) s.starttls() s.login(login, password) # sendmail function takes 3 arguments: sender's address, # recipient's address and message to send - here it is sent as one # string. s.sendmail(email, [email], message_root.as_string()) s.quit() except (ssl.SSLError, smtplib.SMTPServerDisconnected): print('Error') s.close()
def email_report(email, download_link, daily_report, weekly_report, host, port, login=None, password=None, dry_run=False, verbose=False): daily = [v[0] for k, v in daily_report.items()] if daily_report else [] daily_updates = daily_report.items()[-1][1][1] daily_edu = daily_report.items()[-1][1][2] weekly = [v[0] for k, v in weekly_report.items()] if weekly_report else [] cumulative_data = daily_report if daily_report else weekly_report if cumulative_data is None: raise Exception("No data given to generate a cumulative report!") cumulative = [v[3] for k, v in cumulative_data.items()] width, height = 700, 300 # Create the charts daily_chart = SimpleLineChart(width, height) weekly_chart = SimpleLineChart(width, height) cumulative_chart = SimpleLineChart(width, height) # Titles daily_chart.set_title('Daily Downloads') weekly_chart.set_title('Weekly Downloads') cumulative_chart.set_title('Cumulative Downloads') # Add data if daily: daily_data = daily[-180:] daily_chart.add_data(daily_data) daily_chart.set_axis_range(Axis.LEFT, 0, max(daily_data)) daily_chart.set_axis_labels(Axis.RIGHT, [min(daily_data), max(daily_data)]) if weekly: weekly_chart.add_data(weekly) weekly_chart.set_axis_range(Axis.LEFT, 0, max(weekly)) weekly_chart.set_axis_labels(Axis.RIGHT, [min(weekly), max(weekly)]) cumulative_chart.add_data(cumulative) cumulative_chart.set_axis_range(Axis.LEFT, 0, max(cumulative)) cumulative_chart.set_axis_labels( Axis.RIGHT, [min(cumulative), max(cumulative)]) # Set the styling marker = ('B', 'C5D4B5BB', '0', '0', '0') colors = ['3D7930', 'FF9900'] daily_chart.markers.append(marker) weekly_chart.markers.append(marker) cumulative_chart.markers.append(marker) daily_chart.set_colours(colors) weekly_chart.set_colours(colors) cumulative_chart.set_colours(colors) grid_args = 0, 10 grid_kwargs = dict(line_segment=2, blank_segment=6) daily_chart.set_grid(*grid_args, **grid_kwargs) weekly_chart.set_grid(*grid_args, **grid_kwargs) cumulative_chart.set_grid(*grid_args, **grid_kwargs) #daily_chart.fill_linear_stripes( # Chart.CHART, 0, 'CCCCCC', 0.2, 'FFFFFF', 0.2) daily_chart_url = daily_chart.get_url() if daily else None weekly_chart_url = weekly_chart.get_url() if weekly else None cumulative_chart_url = cumulative_chart.get_url() # Create recent versions of the charts if daily: recent_daily = daily[-90:] # Get last year's daily data. First, get the first date for the daily # data. start = daily_report.items()[-90][0] dt = datetime.datetime.strptime(start, '%Y/%m/%d') dt = dt - datetime.timedelta(weeks=52) last_year_datestr = datetime_to_str(dt) # Get the index in the data for the datestr try: i = daily_report.keys().index(last_year_datestr) recent_daily_comparison = daily[i:i + 90] except ValueError: recent_daily_comparison = [] if recent_daily_comparison: daily_chart.data = [recent_daily, recent_daily_comparison] else: daily_chart.data = [recent_daily] # Reset the axes daily_chart.axis = [] min_daily = min(recent_daily + recent_daily_comparison) max_daily = max(recent_daily + recent_daily_comparison) daily_chart.set_axis_range(Axis.LEFT, 0, max_daily) daily_chart.set_axis_labels(Axis.RIGHT, [min_daily, max_daily]) daily_chart.set_title('Recent Daily Downloads (filled is now)') daily_recent_chart_url = daily_chart.get_url() else: daily_recent_chart_url = None if verbose: print('Daily: ' + daily_chart_url) if daily_chart_url else None print('Weekly: ' + weekly_chart_url) if weekly_chart_url else None print('Cumulative: ' + cumulative_chart_url) print('Daily Recent: ' + daily_recent_chart_url) if daily_recent_chart_url else None yesterday = datetime.date.today() - datetime.timedelta(days=1) # Create the body of the message (a plain-text and an HTML version). text = "Get an HTML mail client." html = """\ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=600" /> <style> @media only screen and (min-device-width: 541px) {{ .content {{ width: 540px !important; }} }} </style> </head> <body> <table class="content" align="center" cellpadding="0" cellspacing="0" border="0" style="width: 100%; max-width: 540px; border: 1px solid #cbcbcb;"> <tr> <td height="32" style="text-align: center; background-color:#fe8359;height:32px;color:#fff" bgcolor="fe8359"> <span style="font-size:11px">Daily Report for</span> <span style="font-size:14px;font-weight:bold">{yesterday:%A, %B %d, %Y}</span> </td> </tr> <tr> <td height="30" valign="middle"> <table cellpadding="0" cellspacing="0" border="0" style="width: 100%; text-align: center"> <tr> <td style="margin-top: 5px;"> <span style="font-size: 10px; color: #777">Downloads:</span> <div style="font-size: 15px; margin-top: 3px; "><b>{latest_daily:,}</b></div> </td> <td style="margin-top: 5px;"> <span style="font-size: 10px; color: #777">Updates:</span> <div style="font-size: 15px; margin-top: 3px; "><b>{latest_updates:,}</b></div> </td> <td style="margin-top: 5px;"> <span style="font-size: 10px; color: #777">Educational:</span> <div style="font-size: 15px; margin-top: 3px; "><b>{latest_edu:,}</b></div> </td> <td style="margin-top: 5px;"> <span style="font-size: 10px; color: #777">Since Monday:</span> <div style="font-size: 15px; margin-top: 3px; "><b>{latest_weekly:,}</b></div> </td> <td style="margin-top: 5px;"> <span style="font-size: 10px; color: #777">Cumulative:</span> <div style="font-size: 15px; margin-top: 3px; "><b>{cumulative:,}</b></div> </td> </tr> </table> </td> </tr> <tr> <td></td> </tr> <tr> <td><hr color="#cbcbcb"></td> </tr> <tr><td style="padding: 5px;"><img src="cid:daily.png" width="{width}" height="{height}" alt="Daily Downloads" /></td></tr> <tr><td style="padding: 5px;"><img src="cid:weekly.png" width="{width}" height="{height}" alt="Weekly Downloads" /></td></tr> <tr><td style="padding: 5px;"><img src="cid:cumulative.png" width="{width}" height="{height}" alt="Cumulative Downloads" /></td></tr> <tr><td style="padding: 5px;"><img src="cid:daily-recent.png" width="{width}" height="{height}" alt="Recent Daily Downloads" /></td></tr> <tr> <td><hr color="#cbcbcb"></td> </tr> <tr> <td style="padding: 10px; text-align: center;"> <a style="color: #777" href="{download}">Download today's report</a> </td> </tr> </table> </body> </html>""".format( yesterday=yesterday, latest_daily=daily[-1] if daily else 0, latest_weekly=weekly[-1] if weekly else 0, latest_updates=daily_updates, latest_edu=daily_edu, cumulative=cumulative[-1], download=download_link, width=width, height=height, ) # Create message container - the correct MIME type is multipart/alternative. message_root = MIMEMultipart('related') message_root['Subject'] = "iTunes Report for {:%A, %B %d, %Y}".format(yesterday) message_root['From'] = email message_root['To'] = email message_root.preamble = 'This is a multi-part message.' # Record the MIME types of both parts - text/plain and text/html. alternative = MIMEMultipart('alternative') message_root.attach(alternative) part1 = MIMEText(text, 'plain') part2 = MIMEText(html, 'html') # Attach parts into message container. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. alternative.attach(part1) alternative.attach(part2) # Get the images if daily_chart_url: r = requests.get(daily_chart_url) img = MIMEImage(r.content, _subtype='png') img.add_header('Content-ID', '<daily.png>') message_root.attach(img) if weekly_chart_url: r = requests.get(weekly_chart_url) img = MIMEImage(r.content, _subtype='png') img.add_header('Content-ID', '<weekly.png>') message_root.attach(img) r = requests.get(cumulative_chart_url) img = MIMEImage(r.content, _subtype='png') img.add_header('Content-ID', '<cumulative.png>') message_root.attach(img) if daily_recent_chart_url: r = requests.get(daily_recent_chart_url) img = MIMEImage(r.content, _subtype='png') img.add_header('Content-ID', '<daily-recent.png>') message_root.attach(img) try: # Send the message via local SMTP server. s = smtplib.SMTP(host, port) s.starttls() s.login(login, password) # sendmail function takes 3 arguments: sender's address, # recipient's address and message to send - here it is sent as one # string. s.sendmail(email, [email], message_root.as_string()) s.quit() except (ssl.SSLError, smtplib.SMTPServerDisconnected): print('Error') s.close()