Commit Graph

5 Commits

Author SHA1 Message Date
Alexander 4ceade9079 Editorial redesign: event icons, timeline, person links
Reworks the newsletter as a family-chronicle layout: ivory paper
background, deep oxblood ink, aged-gold accents, EB Garamond
display with Georgia body fallback.

- Inline SVG event icons (sparkle for birth, dagger for death,
  interlocked rings for marriage). Falls back silently in
  Outlook desktop; modern Gmail / Apple / iOS / Outlook 365
  render them.
- Right-side gold hairline timeline running through the date
  column of every event row, with a filled dot per entry.
- Person names link to their webtrees Individual page via
  Individual::url() (absolute URL through route() → BASE_URL),
  including the avatar circles.
- German strings added for the new section kickers
  ("Family Chronicle", "Living kin who will celebrate this
  fortnight.", "Marriages still intact.").
2026-05-15 12:31:51 +02:00
Alexander 51c1e36125 Resize avatar images before embedding
Source media files can easily be multiple megabytes — embedding
the originals made a per-recipient email balloon to 10MB+. Each
avatar is now cover-cropped to 96x96 (HiDPI for the rendered
48px circle) and re-encoded as JPEG q=75 via Intervention\Image,
which webtrees already depends on. Typical avatar payload drops
from megabytes to ~5-15KB.

Falls back to the original bytes (with a log warning) if neither
Imagick nor GD is loaded — better an oversized email than none.
2026-05-15 12:24:28 +02:00
Alexander 12b44edfa5 Always include historical section on forced sends
The "once-per-calendar-month" gate that prevents the historical
section from appearing on every regular send also suppressed it
on admin "Send now" previews after the first run of the month —
making the section silently disappear when re-testing the email.

Force-send now bypasses the gate but still updates the
last-historical-month stamp, so the real monthly cadence stays
intact for cron-driven sends.
2026-05-15 12:20:26 +02:00
Alexander a07184ab3a Embed circular profile pictures in newsletter emails
Pull each individual's highlighted media image via webtrees'
Individual::findHighlightedMediaFile, attach as Symfony inline
parts with stable cid:avatar-<xref> identifiers, and render
border-radius:50% on the <img>. Couples on anniversaries show
both spouses' circles side-by-side.

Fallback when no image is available (privacy-hidden record, no
OBJE, external URL, unreadable file): a CSS-only coloured circle
with the person's initials. The hue is derived from a hash of
the XREF so the same person keeps the same colour across
newsletters.

Done via a NewsletterMailer subclass of EmailService that adds a
sendWithEmbeds() method — the parent's transport() and DKIM
config still apply, only the message-construction path differs.
2026-05-15 12:14:29 +02:00
Alexander 7ce8201082 Initial commit: webtrees Email Newsletter module
Recurring email newsletter for webtrees 2.2+. Each enabled tree
sends upcoming birthdays of living individuals, optional marriage
anniversaries of intact couples, and a once-per-calendar-month
historical section of births and deaths of deceased individuals.

Triggered exclusively by an external scheduler (system cron,
systemd timer, etc.) hitting a token-gated HTTP endpoint — never
on visitor page loads. The "is it due?" decision is idempotent
within the configured frequency window.

Per-user subscription is integrated into the built-in
/my-account/{tree} page via a custom view + a decorated
AccountUpdate handler. Admins can add external addresses and
trigger an immediate send for testing. Email body renders in
German for German-language users; English otherwise. Birthdays
and anniversaries are formatted with the upcoming-event ordinal
age (e.g. "45th birthday" / "45. Geburtstag").
2026-05-15 12:00:39 +02:00