
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)