← All writing

29 October 2026 · EmailHTMLTemplates

Emails that list many cases at once

Notes from writing fifteen transactional email templates for dispute management, including bulk emails that loop over rows and a naming scheme that kept them sane.

When we rebuilt dispute management, the emails had to change too. A merchant who gets a dispute needs to know what happened, what to do and by when, in an inbox that might be Gmail, Outlook or a phone. I wrote fifteen templates for the dispute, pre-arbitration and arbitration stages, plus reminders, closures and an announcement for existing merchants.

HTML email is its own planet

Email clients support a narrow, old slice of HTML and CSS. The usual rules applied:

  • Tables for layout, inline styles, and no reliance on modern CSS.
  • Buttons built as styled links inside table cells, so they survive clients that strip styles.
  • Images treated as optional, with every important word also present as real text.

One email, many rows

The interesting part was the bulk emails. A merchant with ten new disputes shouldn’t get ten emails. The bulk templates take a list and loop over it with the templating language the backend uses (Jinja), so one email lists every case with its ID, reference number, reason and deadline:

{% for row in jinja_data %}
  <tr>
    <td>{{ row.caseId }}</td>
    <td>{{ row.reference }}</td>
    <td>{{ row.reason }}</td>
    <td>{{ row.dueDate }}</td>
  </tr>
{% endfor %}

(Field names simplified here.) Formatting the date on the backend, before it reached the template, kept the template dumb, which is what you want in email.

A naming scheme that scales

Fifteen files named things like merchantWon.html and arbBulkNotification.html became hard to map to the events that sent them. We renamed them to a structured code:

DISPUTE_<EVENT>_<AUTO|MANUAL|BULK>_V1.html

The event says what happened. The suffix says whether the system sends it automatically, a person sends it manually, or it goes in bulk. The version lets a new design ship next to the old one. Backend engineers could find the right template from the event name alone.

Copy that respects the reader

  • Say the stage plainly (“pre-arbitration”), then what it means.
  • Put the deadline near the top, in the same words the dashboard uses.
  • When nothing is needed (“closed, no action required”), say so explicitly, so the email doesn’t cause worry.
  • Add step-by-step instructions that match the screens a click away.
↑↓ move↵ openesc close