Birthday notifier for confluence

19 Sep 2007

To help me keep track of my friend’s birthdays I’ve written a Confluence wiki page with their dates and a Python script that parses the page and sends an email.

The script looks for all confluence pages that have the label ‘notifier’, and parses a table with a format like this:

Name Date
Friend 1 1978-01-01 x  
Friend 2 1975-01-01   x

The table could contain many receiving email addresses, and a ‘x’ marks where to send the email. The Python script is installed in crontab and runs every night.

#!/usr/bin/env python
# -*- coding: latin1 -*-

import MySQLdb
import datetime
import time
import smtplib
import quopri

class ParseError(Exception):

def parsetable(text):
    """Parses a text in confluence table format and returns a dictionary
    with header and content elements"""
    table_text = [line for line in text.split('\n') if line.startswith('|')]

    header = [item.strip('\ ') for item in table_text[0].split('||')[1:-1]]
    if len(header) < 3:
        raise ParseError, 'header'

    content = []
    for line in table_text[1:]:
        row = [item.strip('\ ') for item in line.split('|')[1:-1]]
        if len(row) != len(header):
            raise ParseError, 'content'
        if len(row[0]) > 0:

    return {'header': header, 'content': content}
def checknotify(table):
    """Iterates over a table (in the format that parsetable returns,
    and calls notify() if the date in the second row is near todays date"""
    today =
    for row in table['content']:
        subject = ''
        except ValueError:

        diff =, date.month, - today
        name = quopri.encodestring(row[0])

        if diff.days == 5:
            subject = "%s soon %s years" % (name, today.year - date.year)
            text = "In five days %s will be %s =E5r.\n\nThe date was %s.\n" %(
                name, today.year - date.year, date)
        elif diff.days == 0:
            subject = "%s %s years today" % (name, today.year - date.year)
            text = "Today %s will be %s =E5r.\n\nThe date was %s.\n" %(
                name, today.year - date.year, date)
        if subject != '':
            dest = []
            for i in range(2, len(row)):
                if row[i] != '':
            if len(dest) > 0:
                notify(subject, text, dest)

def notify(subject, text, destination):
    """Sends an email to destination"""
    sender = "noreply@localhost"
    message = "From: %s\r\n" % sender + \
              "To: %s\r\n" % ', '.join(destination) + \
              "Subject: Reminder: %s?=\r\n" % subject + \
              "Content-Transfer-Encoding: quoted-printable\r\n\r\n" + \
    mailserver = smtplib.SMTP('localhost')
    mailserver.sendmail(sender, destination, message)

def main():
    """Connects to confluence and selects all pages that are marked with the
    label 'notifier', and sends email when a reminder is needed"""
    db = MySQLdb.connect(db="confluence",user="confluence",passwd="xxx")
    c = db.cursor()

    c.execute("select BODY from BODYCONTENT where CONTENTID
in (select CONTENTID from CONTENT_LABEL, LABEL where

    for page in c.fetchall():
            table = parsetable(page[0])
        except ParseError, detail:
            print "parse failed:", detail


if __name__ == "__main__":