# 16-Mar-2026 — Customisable email templates, placeholder toolbar, and email routing diagnostics

## [build 540](https://github.com/nbarrett/ngx-ramblers/actions/runs/23185962824) — [commit cc7411f](https://github.com/nbarrett/ngx-ramblers/commit/cc7411f4dbe023d78a3d3b7bf5e0d51d02ee5e1c)

_____

### Covers: follow-up notifications, mailing lists, and member priority ([#177](https://github.com/nbarrett/ngx-ramblers/issues/177)),  improve transactional email deliverability across all environments[#186](https://github.com/nbarrett/ngx-ramblers/issues/186))

- Add admin-editable markdown email templates with section toggle, edit/preview mode, insertable placeholder fields via toolbar dropdown and per-event overrides for all five email types. 
- Introduce BookingEmailType enum replacing string literals across frontend and backend. 
- Add data migration to backfill default templates and help content. 
- Show SPF, DKIM, and DMARC authentication results with colour-coded badges and plain-English summaries in the email routing log. 
- Fix worker invocation log timing and row striping.

## User Guide — Booking Email Templates & Reminder Notifications
- Admins can now customise the content of every booking-related email and schedule automatic reminder emails to be sent before events.
- All configuration is managed from the **Bookings → Configuration** tab in the admin area.
## Email Types
Five email types are supported, each sent automatically at the
appropriate point in the booking lifecycle:
| Email            | Triggered when                                          |
|------------------|---------------------------------------------------------|
| **Confirmation** | A booking is created                                    |
| **Cancellation** | A booking is cancelled by the attendee or an admin      |
| **Waitlisted**   | A non-member booking is displaced during member priority |
| **Restored**     | A waitlisted booking is restored after a cancellation   |
| **Reminder**     | The event is within the configured reminder window      |
## Customising Email Templates
### Global Templates
Navigate to **Bookings → Configuration → Email Templates**. Each email type has a markdown editor where you can write the email body. A live preview is shown alongside the editor.
### Per-Event Overrides
- For **confirmation** and **reminder** emails, you can override the global template on a per-event basis. Navigate to **Bookings → Per-Event Detail**, select an event, and edit the override fields.
- If an override is set, it takes priority over the global template for that event.
### Template Resolution Order
When sending an email the system resolves the template as follows:
1. **Per-event override** (confirmation and reminder only)
2. **Global template** from booking configuration
3. **Built-in default** (hardcoded fallback)
The first non-empty value wins.
## Placeholders
Templates support the following placeholders, which are replaced with
real values at send time:
| Placeholder          | Replaced with                                       |
|----------------------|-----------------------------------------------------|
| `{{EVENT_TITLE}}`    | The event title                                     |
| `{{EVENT_DATE}}`     | Formatted date and time (e.g. Wednesday, 15 March…) |
| `{{EVENT_LINK}}`     | URL to the event page                               |
| `{{ATTENDEE_NAME}}`  | First name of the primary attendee                  |
| `{{ATTENDEE_LIST}}`  | Markdown list of all attendees with email addresses  |
| `{{PLACES_COUNT}}`   | Number of places in the booking                     |
Include them in your template text exactly as shown (with double
braces). Unknown placeholders are left as-is.
## Reminder Emails
### Configuration
- In **Bookings → Configuration**, set the **Reminder days before event** field to the number of days before an event that reminders should be sent.
- Set to **0** to disable reminders.
### How It Works
A daily cron job runs at **08:00** each morning. It:
1. Reads the configured `reminderDaysBefore` value.
1. Finds all events whose start date falls within the reminder window
(today → today + reminderDaysBefore).
1. For each event, finds active bookings that have not yet received a
reminder (no `reminderSentAt` timestamp).
1. Sends the reminder email and stamps `reminderSentAt` on the booking.
Each booking receives at most one reminder — the process is idempotent.
## Brevo Integration
- Emails are sent via the existing Brevo transactional email pipeline.
- The `bookingNotificationConfigId` must be set in the mail configuration to point to a valid Brevo notification config. If it is not configured, booking emails are silently skipped.
- The resolved markdown template is rendered to HTML and injected into the Brevo template as the `BODY_CONTENT` merge field alongside the standard site merge fields (banner, signoff, app name, etc.).