An e-mail reminder Python script

 Fri, 16 Feb 2024 11:37 UTC

An e-mail reminder Python script
Python logo: python.org | This image: CC BY 4.0 by cybrkyd


I miss receiving the e-mail notifications for recurring events from my days of using the Hotmail and Gmail calendars. As most days are spent buried in emails, my inbox is everything: my to-do list, my schedule and of course, my e-mails.

From a privacy stance, I also have concerns about having my life’s events and important dates in the cloud, sitting on someone’s server.

In an effort to self-host everything, my solution proved to be relatively simple in the end: do it yourself in Python.

I was initially on a shared-hosting platform with Roundcube, so the option to send an e-mail for up-coming calendar events was non-existent. There is an option for a ‘message’ to be sent for the Birthday Calendar only but I have no interest in being reminded only about birthdays…what about other events? I believe that some add-on exists somewhere but that was useless to me. Being on shared hosting, I had no way of tinkering with add-ons.

My Requirements

My solution does not forward-read my calendar. Rather, this is a static reminder solution for dates which are important — birthdays, anniversaries and things I need to do on certain dates.

My reminders are stored in a tab-delimited csv file:

Subject Occurrence
REMINDER: Check tyres   02 of every month
REMINDER: Check tyres   16 of every month
REMINDER: Car MOT due 25 September 2024 15 Jul, 15 Aug
REMINDER: Book Car Service  01 Oct, 01 Nov
REMINDER: Someone's Birthday    01 Jan
REMINDER: Someone's Anniversary 02 Jan
REMINDER: Pay that bill Last day of every month

Note the ‘plain English’ usage in some of the lines for the Occurrence column:

Last day of every month
    and
02 of every month

That is very nice shorthand, instead of having 02 Jan, 02 Feb, 02 Mar, ... etc.

The cron job

This is run once a day at 7am my time.

0 7 * * * /var/www/html/example.com/cgi-bin/rem.py >/dev/null 2>&1

E-mail Reminders with Python

The script uses smtplib for the email and uses the csv module to read events from the csv file. The if / elif statements each contain the instruction to e-mail — this is on purpose to avoid the situation I ran into where only one email was sent if there happened to be more than one reminder on any given date.

#!/usr/bin/env python3

import csv
import datetime
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import email.utils
import calendar

def send_email(subject, body, to_email):
    me = "bot@example.com"
    msg = MIMEMultipart('alternative')
    msg['From'] = me
    msg['To'] = to_email
    msg['Subject'] = subject
    msg['Date'] = email.utils.formatdate(localtime=True)
    part1 = MIMEText(body, 'plain', 'utf-8')
    msg.attach(part1)
    s = smtplib.SMTP('localhost')
    s.sendmail(me, to_email, msg.as_string())
    s.quit()

# Read the CSV file
file_path = '/var/www/html/example.com/cgi-bin/list.csv'
current_day = datetime.datetime.now().day
current_month = datetime.datetime.now().month
current_date = datetime.datetime.now().strftime('%d %b')
current_weekday = datetime.datetime.now().strftime('%A')

to_email = 'mail@example.com'

with open(file_path, 'r') as csvfile:
    reader = csv.DictReader(csvfile, delimiter='\t')

    for row in reader:
        subject = row['Subject']
        occurrence = row['Occurrence']

        if 'Last day of every month' in occurrence:
            last_day_of_month = calendar.monthrange(datetime.datetime.now().year, current_month)[1]
            if current_day == last_day_of_month:
                email_subject = subject
                email_body = subject
                send_email(email_subject, email_body, to_email)

        elif 'of every month' in occurrence:
            day_of_month = int(occurrence.split(' ')[0])
            if current_day == day_of_month:
                email_subject = subject
                email_body = subject
                send_email(email_subject, email_body, to_email)

        elif current_date in occurrence:
            email_subject = subject
            email_body = subject
            send_email(email_subject, email_body, to_email)

        elif current_weekday.lower() in occurrence.lower():
            email_subject = subject
            email_body = subject
            send_email(email_subject, email_body, to_email)