# Birthday Manager Self-hosted birthday reminder application that automatically e-mails people on their birthday. © 2026 Martinhal IT - Joao Vaz - Version 1.2 ## Features **Page 1 — Dashboard** - Three panels at the top: **Yesterday's Birthdays**, **Today's Birthdays** (with the **Force Send** button to resend the e-mail) and **Tomorrow's Birthdays** - Add / remove birthday entries: First Name, Last Name, Date of Birth, Gender, E-mail address - Yearly calendar overview of all entries (hover a marked day to see the names; browse other years) **Page 2 — Administration** - Add / remove application users - Every user can enable/disable MFA (TOTP — Google Authenticator, Authy, etc.) and change their own password - Full e-mail log: who received mail, at what date & time, and whether it succeeded - Setting for the time of day the automatic birthday e-mails are sent (applies immediately, no restart needed) - Two template zones: **E-mail Template Male** and **E-Mail Template Female**, with placeholders `{first_name}`, `{last_name}`, `{age}` - Image upload — select multiple files at once (15 MB total per upload); each image shows its ready-to-copy `` command, and images are embedded inline in the outgoing e-mail Automatic sending: a scheduler runs every day at `SEND_HOUR` (default 08:00) and e-mails everyone whose birthday it is, using the template matching their gender. Duplicates are avoided (one automatic mail per person per day); **Force Send** always resends. February 29 birthdays are celebrated on February 28 in non-leap years. Every successfully sent e-mail is also copied to the mailbox's **Sent** folder via IMAP, so it shows up in your normal mail client. ## Mail provider The app comes pre-configured for **Purelymail**: | | Server | Port | Security | |---|---|---|---| | Outgoing (SMTP) | `smtp.purelymail.com` | `465` | SSL/TLS | | Incoming (IMAP, Sent-folder copy) | `imap.purelymail.com` | `993` | SSL/TLS | You only need to fill in `SMTP_USER`, `SMTP_PASS` and `SMTP_FROM` with your Purelymail mailbox credentials. If your network only supports STARTTLS for SMTP, set `SMTP_PORT=587` and `SMTP_SECURITY=starttls` instead. Any other provider works too — just override the host/port variables. ## Quick start (Docker — recommended) 1. Edit `docker-compose.yml` and fill in your Purelymail credentials (`SMTP_USER`, `SMTP_PASS`, `SMTP_FROM`) plus a random `SECRET_KEY` and your timezone. 2. Run: ```bash docker compose up -d --build ``` 3. Open http://localhost:8080 and log in with **admin / admin** — then change the password on the Administration page immediately. All data (SQLite database + uploaded images) lives in `./data`, so back up that folder. ## Quick start (plain Python) ```bash pip install -r requirements.txt # Purelymail servers are the built-in defaults - only credentials are needed export SMTP_USER=you@yourdomain.com export SMTP_PASS=your-purelymail-password export SMTP_FROM=you@yourdomain.com export SEND_HOUR=8 export SECRET_KEY=$(python -c "import secrets;print(secrets.token_hex(32))") python app.py ``` The app listens on port 8080 (`PORT` env var to change). Data is stored in `./data` (`DATA_DIR` env var to change). ## Environment variables | Variable | Default | Purpose | |---|---|---| | `SMTP_HOST` | `smtp.purelymail.com` | SMTP server | | `SMTP_PORT` | `465` | SMTP port | | `SMTP_USER` | – | SMTP username / mailbox | | `SMTP_PASS` | – | SMTP password | | `SMTP_FROM` | `SMTP_USER` | From address | | `SMTP_SECURITY` | `ssl` | `ssl`, `starttls` or `none` | | `IMAP_HOST` | `imap.purelymail.com` | IMAP server for the Sent-folder copy | | `IMAP_PORT` | `993` | IMAP port (SSL/TLS) | | `IMAP_USER` | `SMTP_USER` | IMAP username | | `IMAP_PASS` | `SMTP_PASS` | IMAP password | | `IMAP_SENT_FOLDER` | `Sent` | Mailbox folder sent mail is stored in | | `SEND_HOUR` | `8` | Default hour for the daily send — the time picked on the Administration page overrides this | | `SECRET_KEY` | random | Flask session key — set it so logins survive restarts | | `PORT` | `8080` | HTTP port | | `DATA_DIR` | `./data` | Where the database and uploads are stored | ## Notes - The e-mail address field on entries is required because it is where the birthday greeting is sent. - Failed sends (e.g. SMTP misconfigured) are also recorded in the e-mail log with the error as tooltip on the "Failed" status. If a mail is delivered but the IMAP copy to the Sent folder fails, the mail is still logged as Sent and the IMAP error appears as a tooltip. - Run behind a reverse proxy (nginx / Caddy / Traefik) with HTTPS if you expose it beyond your LAN.