The Software for a Wedding

Elisabeth and I are getting married in a few weeks, which means we’ve been in wedding-planning mode for the past year or so. And while planning required the typical steps of finding a suitable venue and selecting a caterer and so on, we decided early on to rely enough on a wedding website, such that we could get away with (aka, the requirements):

  • Instead of sending out one Save the Date card and one Invitation in the mail to each guest, we would send out a single invitation with the url for the website;

  • Manage RSVPs online instead of by mail;

  • Eliminate the need to print a Wedding Program by having one online;

  • Only have an online registry;

  • Concentrate all guest-facing wedding-related information in one place;

Except for the registry - we used Zola1-, I decided to code most things on my own.

The end result is here: www.ElisabethAndRafael.com;

The website

I decided to use Python to develop the website, and between Flask and Django, the latter seemed to be better suited. I picked up a copy of Two Scoops of Django, and went to work.

The book has a Django cookie-cutter project on Github that makes it incredibly quick to kickstart a project.

Then, with a decent Bootstrap theme in hand, it really becomes a matter of editing the HTML and CSS (I didn’t use a preprocessor for this project) until it looks good.

A good portion of the website is made up of static content, with tons of images and a little JavaScript here and there for Contact Us functionality, loading up the external Zola widget, and other little gimmicks, like a countdown to the day and Bootstrap Alerts.

For the dynamic content, the website was setup to use PostgreSQL. Django’s Models abstraction made it fun to create the queries required for the Views.

Email functionality

For all things email, I went with Mailgun. They have a very good free plan for small scale applications, and the API was very easy to use in Python.

A few days ago we sent out a marketing-style email update to the guests who had RSVP’d.

The email assets (HTML, images) were uploaded to an Amazon S3 bucket, and made public. Then, the script was simple:

Then the script was as simple as:

The actual script was a bit different: the email had links that I wanted to personalize per recipient, so there was a string.replace() involved, but the gist is the same.

Internationalization

I had family and friends in Brazil, some of which wouldn’t be able to make it to the wedding, but in an effort to be inclusive, I thought it’d be nice to have all the content available in Portuguese as well.

Django’s support for i18n internationalization made it less complicated (if not less annoying) to make the website available in both languages.

RSVP

Allowing people to RSVP online was the most elaborate feature of the website. Guests were asked to enter their email and a 4-digit code they had received with the invitation.

The first time they logged-in, the email would be linked to the wedding code, and the same email would have to be used if they wanted to change their response.

The 4-digit codes were generated taking the SHA-1 hash of each guest row (name, address, and so on, saved in a spreadsheet and exported as CSV), transforming it to URL-friendly base64 and taking the first 4 digits. Limiting it to 4 digits made collisions very likely, but I was more concerned with ease-of-use, and the number of guests was small enough that I was able to get away with running a validation script to make sure all codes were unique.

Deployment

The site was deployed to Heroku, using its Python Buildpack. All static assets were uploaded to Amazon S3 as part of the deployment process, with the paths updated on the fly. Cloudflare’s CDN was thrown in the mix as well.

Unfortunately, Heroku’s free tier didn’t cut it: the fact that the server process had to be restarted when someone visited after some inactivity period, made the site very, very slow. So I had to upgrade to the Hobby tier at $7/month.


  1. contains affiliate link, a everyone gets $50 kind of thing.

Comments