Skip to main content
Coding

Code Riffs: Have Your Code Send You an Email

By June 26, 2015February 10th, 2021No Comments

When I write a script that take a long time to run I like to have a system notifying me when certain things happen, like 50% of the job is complete, or if a fatal error just occurred that crashed everything. I find that having an email sent when either of those things happen allows me to forget about the process running in the background and pay attention to other things.

 

So I wrote a simple generic email sending function in Python (which is what I use to run the “heavy and demanding” stuff) that sends me an email and I trigger it at certain points of the script. Below is a short description of how to set it up and how to use it in your code.

 

First, get a Google App Specific Key. Without this it’s not going to work. Hereafter, I’m assuming you have an App Specific Key.

Now let’s look at the function (which in the making of I used 1 and 2 as references).

import smtplib
 
def sendErrorMail(emailAddress,emailAppPassword,type,message):
    if emailAddress!=” and emailAppPassword!=”:
        FROM = emailAddress
        TO = [emailAddress] #must be a list
        SUBJECT = “ENTER SUBJECT TEXT HERE, {type}”.format(type=type)
        # Prepare actual message
        emailMessage = “Subject: {subject}\n\n {text}”.format(
        subject=SUBJECT,text=message)
        try:
            server = smtplib.SMTP(“smtp.gmail.com:587“) #Hello GMAIL
            server.ehlo() #Identifying for the first time
            server.starttls() #Secure transmission of password
            server.login(emailAddress, emailAppPassword)
            server.ehlo() #Identifying again
            server.sendmail(FROM, TO, emailMessage)
            server.close()
        except:
            print(“failed to send mail“)
    else:
        print(“Didn’t send an email. \n Please enter your login details at “
              “the beginning of the script if you want an email sent”)

After calling smtplib we define the sender function which accepts four arguments:

  • emailAddress: this should be the email address you want the email sent to.
  • emailAppPassword: this is the Google App Specific Key.
  • type: use this to define the type of the email you’re sending, such as “ERROR!” or “Progress Update:” etc.
  • message: self explanatory, whatever information you want the email to convey.

The function then checks that it actually got an email address and an email password and continues to construct the message. Notice you need to fill in the subject of the email, this can be turned into another function argument if you wish to make this even more generic. Once the email is ready it shakes hands with Gmail (notice it requires double identification) and sends the message. The function returns two types of errors, either it failed to send the message (something with the hand shake went wrong) or it didn’t receive an email address and password to begin with.

 

Great. The function is defined and we understand what it does and what we need to supply it to get it to work. What about actual usage? Here is a short example showing how to use it once it has been defined:

import shutil

updateIntervals = [50]
spaceAlertNotSent = True
diskSpaceThreshold = 20 #  In GB

try:
    for step in [1, 2, 3]:
        functionWHATEVER(step)
        #Progress so far
        progressBar = round(step/3*100,2)
        if round(progressBar,0) in updateIntervals:
            mailType = "Progress Update"
            message = "Progress is at: {pB}".format(pB=progressBar)
            sendErrorMail(emailAddress,
                          emailAppPassword,
                          mailType,
                          message)
            #To make sure duplicates are not sent
            updateIntervals.remove(round(progressBar,0))
        print(str(progressBar)+'%')
        #Check available space on disk and send an email if necessary
        if spaceAlertNotSent:
            availableSpace = shutil.disk_usage("/")[2]/1000000000
            if availableSpace < diskSpaceThreshold:
                mailType = "DISK SPACE"
                message = "Available space: {space}GB".format(space=availableSpace)
                sendErrorMail(emailAddress,
                              emailAppPassword,
                              mailType,
                              message)
                spaceAlertNotSent = False
except BaseException as e: #  In case of an error, store error message in e
    mailType = "Error"
    message = "Error returned is: {error}".format(error=e)
    sendErrorMail(emailAddress,
                  emailAppPassword,
                  mailType,
                  message)

This shows three examples of using the email sender. To report the progress, alert of disk space running out, and send the error message in case it happens. In case you’re looking for more details:

  • Report Progress: first we define the threshold for which we even want to be updated about. This is done in updateIntervals and here it will simply alert us once the job is 50% done. The script then removes 50 from the list to avoid further emails until the next threshold is reached, and in this case, there is not other threshold. If we were to define the list as updateIntervals = [25, 50, 75, 95] then we would get an email sent at each of those thresholds, but only once per threshold.
  • Running Low on Disk Space: some of the scripts I write deal with large amounts of data and I don’t always bother with thinking ahead in terms of disk space. I use the shutil module to check for disk space and if it drops below the threshold defined in diskSpaceThreshold (defined in GB) then it sends an email to let me know it’s time to either panic, stop the current script, or wildly delete things and hoping I won’t regret it later. The spaceAlertNotSent verifies that the email will be sent only once.
  • Reporting an Error Message: in case functionWHATEVER(step) breaks and returns an error the try/except will capture the error message and send it in an email.

 

Obviously, this can be used for many other things. The above are just suggestions that I use and find helpful to highlight. I hope you find this useful and that you don’t end up spamming yourself.

 

Code Riffs is a series of posts where I share code snippets or coding tricks I stumble upon. I know I found similar posts very helpful so instead of just keeping these snippets and tricks to myself I’m putting them out here for everyone to benefit from. Also, this forces me to write proper documentation for some of them. Previous coding snippets and tricks can be found on the code page.