diff --git a/resources/views/email.phtml b/resources/views/email.phtml
index d2d8097..93c99fe 100644
--- a/resources/views/email.phtml
+++ b/resources/views/email.phtml
@@ -20,9 +20,83 @@ use Illuminate\Support\Collection;
* @var int $lookahead_days
* @var int $historical_lookahead
* @var int $generated_at
+ * @var array if the dispatch service was able to
+ * resolve an image for the individual; otherwise renders a coloured
+ * circle with the person's initials. The placeholder is intentionally
+ * CSS-only — inline SVG and data: URIs are unreliable in Outlook /
+ * some webmail clients.
+ */
+$avatar = static function (Individual|null $individual) use ($avatar_cids, $avatar_size): string {
+ if (!$individual instanceof Individual) {
+ return '';
+ }
+
+ $alt = e(strip_tags($individual->fullName()));
+
+ if (isset($avatar_cids[$individual->xref()])) {
+ $cid = $avatar_cids[$individual->xref()];
+
+ return '
';
+ }
+
+ // CSS-only fallback: coloured circle with initials. Hash the xref
+ // into a stable hue so each person keeps the same colour across
+ // newsletters.
+ $hue = hexdec(substr(md5($individual->xref()), 0, 2)) * 360 / 255;
+ $first = strip_tags($individual->getAllNames()[0]['givn'] ?? $individual->xref());
+ $last = strip_tags($individual->getAllNames()[0]['surn'] ?? '');
+ $i1 = mb_substr($first, 0, 1);
+ $i2 = mb_substr($last, 0, 1);
+ $initials = e(mb_strtoupper($i1 . $i2));
+
+ return '' . $initials . '';
+};
+
+/**
+ * HTML for the avatar(s) attached to a Fact's primary record:
+ * a single circle for Individual facts, side-by-side circles for
+ * Family facts (anniversaries).
+ */
+$record_avatars = static function (Fact $fact) use ($avatar): string {
+ $record = $fact->record();
+
+ if ($record instanceof Individual) {
+ return $avatar($record);
+ }
+
+ if ($record instanceof Family) {
+ $parts = [];
+
+ foreach ([$record->husband(), $record->wife()] as $spouse) {
+ if ($spouse instanceof Individual) {
+ $parts[] = $avatar($spouse);
+ }
+ }
+
+ // Slight negative margin so the two circles overlap a touch —
+ // visually communicates "couple" without needing extra glue.
+ return ''
+ . implode('', $parts)
+ . '';
+ }
+
+ return '';
+};
+
$record_label = static function (Fact $fact): string {
$record = $fact->record();
@@ -141,15 +215,25 @@ $anniversary_label = static function (int $age) use ($ordinal): string {
= e(I18N::translate('Events in the next %d days.', $lookahead_days)) ?>
= e(I18N::translate('Events in the next %d days for people who have passed away.', $historical_lookahead)) ?>
-