Operations 12 min read

Python Email Notification Scripts for Model Training, Data Processing, and Financial Modeling

This article explains how to use Python scripts with the email and smtplib libraries to automatically send progress updates and completion notifications for long‑running tasks such as model training, data transfer, and financial simulations, including code examples for MIME construction and SMTP delivery.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Python Email Notification Scripts for Model Training, Data Processing, and Financial Modeling

The author frequently writes Python scripts for data handling, model training, and related tasks, and proposes sending automated email notifications to stay productive while waiting for long‑running processes.

What is needed – Depending on the task (model training, data processing/transfer, or financial modeling), specific information such as loss curves, runtime, model name, or sample results should be included in the notification.

Model training notifications – Update every n epochs with key metrics (loss, accuracy), visualizations, model directory, runtime, and sample outputs. Example code:

import notify
START = datetime.now()  # before training begins
MODELNAME = "SynthwaveGAN"
NOTIFY = 100  # send update every 100 epochs
if e % notify_epoch == 0 and e != 0:
    txt = f"{MODELNAME} update as of {datetime.now().strftime('%H:%M:%S')}."
    msg = notify.message(
        subject="Synthwave GAN",
        text=txt,
        img=[
            f"../visuals/{MODELNAME}/epoch_{e}_loss.png",
            f"../visuals/{MODELNAME}/epoch_{e}_iter_{i}.png"
        ]
    )
    notify.send(msg)

Every 100 epochs an email containing the above information is sent.

Data processing and transfer – Often the most time‑consuming step. Example using a Python script to bulk‑upload files to SQL Server and send a completion email:

import os
import notify
from data import Sql

dt = Sql(database123, server001)  # connect to SQL Server
for i, file in enumerate(os.listdir("../data/new")):
    dt.push_raw(f"../data/new/{file}")  # upload file
msg = notify.message(
    subject="SQL Data Upload",
    text=f"Data upload complete, {i} files uploaded."
)
notify.send(msg)

A try‑except block can capture upload errors and include them in the final notification.

Financial model notifications – Although fast, large‑scale simulations may still benefit from summaries. Example code sends runtime, processed loan count, and visualizations:

end = datetime.datetime.now()  # ending time
hours, rem = divmod((end - start).seconds, 3600)
mins, secs = divmod(rem, 60)
runtime = f"{hours:02d}:{mins:02d}:{secs:02d}"
notify.msg(
    subject="Cashflow Model Completion",
    text=f"{len(model.output)} loans processed. Total runtime:{runtime}",
    img=[
        "../vis/loan01_amortisation.png",
        "../vis/loan07_amortisation.png",
        "../vis/loan01_profit_and_loss.png",
        "../vis/loan07_profit_and_loss.png"
    ]
)
notify.send(msg)

MIME construction – The script uses the email package to build a MIMEMultipart message with MIMEText , MIMEImage , and MIMEApplication parts. The function below creates the message object:

import os
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart

def message(subject="PythonNotification", text="", img=None, attachment=None):
    msg = MIMEMultipart()
    msg["Subject"] = subject
    msg.attach(MIMEText(text))
    if img is not None:
        if type(img) is not list:
            img = [img]
        for one_img in img:
            img_data = open(one_img, "rb").read()
            msg.attach(MIMEImage(img_data, name=os.path.basename(one_img)))
    if attachment is not None:
        if type(attachment) is not list:
            attachment = [attachment]
        for one_attachment in attachment:
            with open(one_attachment, "rb") as f:
                file = MIMEApplication(f.read(), name=os.path.basename(one_attachment))
            file["Content-Disposition"] = f'attachment; filename="{os.path.basename(one_attachment)}"'
            msg.attach(file)
    return msg

SMTP sending – After constructing the message, smtplib handles delivery. The following function logs into Outlook’s SMTP server, sends the email, and gracefully handles network errors:

import smtplib
import socket

def send(server="smtp-mail.outlook.com", port=587, msg=None):
    try:
        smtp = smtplib.SMTP(server, port)
        smtp.ehlo()
        smtp.starttls()
        with open("../data/email.txt", "r") as fp:
            email = fp.read()
        with open("../data/password.txt", "r") as fp:
            pwd = fp.read()
        smtp.login(email, pwd)
        smtp.sendmail(email, email, msg.as_string())
        smtp.quit()
    except socket.gaierror:
        print("Network connection error, email not sent.")

Finally, the two parts are combined to build and send a notification:

# build a message object
msg = message(text="See attached!", img="important.png", attachment="data.csv")
send(msg)  # defaults to Outlook

The complete workflow enables automated email updates for any lengthy Python‑driven process, improving productivity and providing clear status reports.

PythonAutomationnotificationEmailSMTPMIME
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.