Scheduling Periodic Automatic Emails: PythonAnywhere and SendGrid

We may need to use a periodic and automated email tool to generate or store data. Although you could use your own email server and automate the task, several integrated APIs can simplify this process across all volume and pricing ranges.


We will use one of the saved records from our previous post to create a relatively pretty HTML table and send this table as an email. You can use the same file if you wish:

20211104_record
.csv
Download CSV • 361KB

You will also need your own SendGrid private API key; you can obtain one for free starting here.


If not installed, we need the SendGrid Python API and a library to turn pandas dataframes into HTML. Pretty_html_table is simple to use:

!pip install sendgrid
!pip install pretty_html_table

We also need pandas. When we bring our CSV file into a dataframe, our public procurement item classification code must be imported as an object to represent a series of strings. We can use string location methods with this column:

import pandas as pd
df = pd.read_csv('/content/20211104_record.csv', 
                 dtype={'ItemClassificationCode': object})

SendGrid API client contains several helpers; in this case, Mail, Email, To, and Content will be helpful. In addition, this is an excellent place to set your own API key value:

from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Email, To, Content
from pretty_html_table import build_table
SENDGRID_KEY = 'Write Your API Key Here'

We can define a function to format our dataframe with pretty_html_table, using default options and a light grey color theme:

def df_to_html(df):
    output = build_table(df, 'grey_light')
    return output

The primary function that will send the email requires the HTML content and the from and to email fields. The "from" field must be the SendGrid registered email account; otherwise, the system will reject it. Helpers Email, To, Content, and Mail enable the easy composition of the message. When the message is composed, mail.get() generates a JSON representation of the entire message that the client send.post method can deliver:

def send_email(html_content,
               from_email='your registered email'
               to_email='your destination email'):

    sg = SendGridAPIClient(SENDGRID_KEY)
    
    # Use verified sender:
    from_email = Email(from_email)  
    # Email recipient:
    to_email = To(to_email)  
    subject = "Autocontratacion"
    
    content = Content("text/html", html_content)
    mail = Mail(from_email, to_email, subject, content)


    # Get a JSON-ready representation of the Mail object
    mail_json = mail.get()

    # Send an HTTP POST request to /mail/send
    response = sg.client.mail.send.post(request_body=mail_json)
    print(response.status_code)
    print(response.headers)

Our dataframe is too large to be useful as an email table; performing a minimum filter will reduce the size and become informative for, for example, a person interested in newly published contracts for information systems consulting, codes starting with 72:

df = df.dropna(axis=0, how='all')
df = df[df['ContractFolderStatusCode'] == 'PUB']
df = df[df['ItemClassificationCode'].str.startswith('72', na=False)]

Sending with:

html_content = df_to_html(df)
send_email(html_content)

Returns the confirmation message:


At the receiver, the message is simple and easily readable:


This is a simple, easy, and convenient method to deliver dataframe views to consumer email accounts directly.


If you require data model development, deployment, verification, or validation, do not hesitate and contact us. We will also be glad to help you with your machine learning or artificial intelligence challenges when applied to asset management, trading, or risk evaluations. Ostirion does not endorse any of the products mentioned in this post and is in no way affiliated with the mentioned companies, nor does it receive any compensation for this publication.


The link to the Google Colab notebook for this post can be located here.


4 views0 comments