Alexander 7402843d07 Email dark-mode skin; tree title links to tree, hostname to site root
- Add @media (prefers-color-scheme: dark) rules that re-tint every
  surface, border, and text color via case-insensitive
  attribute-substring selectors on style="...". Palette mirrors
  BockenTheme dark mode so the email reads as one product with
  the website on clients that honour prefers-color-scheme
  (Apple Mail / iOS Mail / Outlook for Mac and iOS, Gmail web).
- Add color-scheme + supported-color-schemes meta tags.
- Masthead H1 (tree title) now links to TreePage; the hostname
  line below now links to HomePage (site root) and displays the
  bare hostname without the /tree/<name> suffix.
2026-05-15 16:05:16 +02:00

webtrees Email Newsletter

A webtrees 2.2+ custom module that sends recurring email newsletters with:

  • Upcoming birthdays of still-living individuals (formatted as ordinal age — "45th birthday" / "45. Geburtstag").
  • Upcoming marriage anniversaries of intact couples (admin toggle, per tree). Marriages with a divorce or annulment fact are excluded automatically.
  • Historical events — births and deaths of deceased individuals whose anniversary falls in the upcoming window.

The look-ahead window and the send cadence are the same number: one "every N days" setting (default 14) drives both the cron interval and how far each issue looks ahead. Issues with nothing to report are silently skipped.

Each recipient gets a per-recipient render — language, relationship labels, detail filter, cadence, and personalisation tokens are all resolved against their webtrees account.

Highlights

  • Editorial layout with embedded circular avatars, a left-side timeline rail, and event-type icons (birth / death / marriage).
  • BockenTheme light-mode skin — Open Sans, cream background, Nord accent palette. The newsletter and the website read as one product.
  • Per-recipient localisation — German for users whose webtrees language starts with de, English otherwise. Subject line, body, date strings, and (optionally) a custom subject prefix are all localised. Subject dates use IntlDateFormatter for the recipient's locale.
  • Per-recipient relationship labels"your mother", "4th great- grandfather", "first cousin twice removed". Uses webtrees' own RelationshipService so the labels match the site.
  • Kin-distance detail filter — close family get the full card (avatar + timeline + icon); distant kin appear as a single-line bullet at the foot of each section. The "distance" radius is an admin setting (default 3); spouses inherit their partner's distance; recipients with no linked tree record always see the full detailed view.
  • Per-recipient cadence — each subscriber can pick weekly, biweekly, monthly, every-two-months, quarterly, or "use site default" on their /my-account/{tree} page.
  • One-shot intro paragraph — admins can attach a Markdown intro (bilingual, EN/DE) to the next issue. Supports {{first_name}}, {{last_name}}, {{username}}, {{email}} personalisation tokens. Rendered alongside the tree-contact user's avatar as an editorial column. Cleared automatically after a successful send.
  • Cron-only dispatch — the "is it due?" decision is made server- side against stored timestamps. Calling the trigger more often than the cadence is harmless and idempotent.

Requirements

  • webtrees ≥ 2.2.0
  • PHP ≥ 8.2 with ext-intl (for locale-aware subject dates) and either ext-imagick or ext-gd (for avatar resizing — falls back to original-size embeds if neither is present).
  • A working SMTP / sendmail configuration in Control panel → Sending email. This module reuses webtrees' standard mailer and signs with the site's DKIM keys if configured.
  • An external scheduler on the host (system cron, systemd timer, Kubernetes CronJob, …) that can fire an HTTP request at a fixed interval. Newsletter dispatch never runs on visitor page loads.

Installation

  1. Copy this directory into the webtrees modules_v4/ folder, renaming it to email_newsletter:

    cp -r webtrees_email_newsletter /var/www/webtrees/modules_v4/email_newsletter
    
  2. In the webtrees control panel, go to Modules → All modules and enable Email Newsletter.

  3. Open Control panel → Modules → Email Newsletter → Preferences and, for each tree:

    • Tick Enable newsletter for this tree.
    • Set the send-cadence (default 14 days). This same number is the look-ahead window for the next issue.
    • Toggle Include marriage anniversaries if desired.
    • Set Detailed view distance (default 3). Lower values produce a terser email focused tightly on close kin.
    • Optional: set per-locale Subject prefix and a Generic fallback (e.g. [Bocken family] ).
    • Optional: tick existing webtrees users in Subscribed users to subscribe them. Users can still adjust their own subscription and cadence on /my-account/{tree}.
    • Optional: add external (non-user) addresses in Extra recipient email addresses.
  4. Copy the Cron URL at the bottom and wire it into your scheduler (see below).

Setting up the scheduler

Why no built-in scheduler? PHP has no daemon, and frameworks like Laravel rely on a once-per-minute system cron to fire their internal scheduler. This module follows the same convention: the host OS owns the timer, the module owns the "is it actually due?" decision.

System cron

# Run every 15 minutes. The module itself decides whether sending is due.
*/15 * * * *  curl -fsS --max-time 60 'https://example.com/module/_email_newsletter_/Cron?token=YOUR_TOKEN' > /dev/null

systemd timer

/etc/systemd/system/webtrees-newsletter.service:

[Unit]
Description=webtrees newsletter trigger

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -fsS --max-time 60 "https://example.com/module/_email_newsletter_/Cron?token=YOUR_TOKEN"

/etc/systemd/system/webtrees-newsletter.timer:

[Unit]
Description=Trigger webtrees newsletter dispatch

[Timer]
OnCalendar=*-*-* *:00/15
Persistent=true

[Install]
WantedBy=timers.target

Then systemctl enable --now webtrees-newsletter.timer.

Forcing a one-off send

The admin Preferences page has a Send now button for testing. For an unattended forced send (bypassing the per-recipient "is it due?" check), append &force=1 to the cron URL.

Subscribers

Three sources, combined and de-duplicated by email:

  1. Webtrees users who opt in themselves via the per-tree Newsletter subscription menu entry on /my-account/{tree} — visible only to logged-in users on trees where the module is enabled.
  2. Webtrees users an admin subscribes from the preferences page.
  3. External addresses the admin lists in Extra recipient email addresses.

Only approved and email-verified webtrees accounts will receive the newsletter. External addresses always receive on every run (they have no per-user cadence timer).

Sender identity

To match webtrees' own convention for system-generated email (registration, password resets, "new version available"), the From: header is SiteUserControl panel → Sending email → Sender name / Sender email (SMTP_FROM_NAME / SMTP_DISP_NAME). The tree's contact user becomes the Reply-To:, so replies still reach a human admin.

If SMTP_FROM_NAME isn't set the dispatcher falls back to the tree contact for From: as well, so the message always has a valid sender envelope.

Privacy

The dispatch service does not impersonate a webtrees user, so it sees the tree from the visitor access level. Records and facts that your tree settings hide from visitors will be omitted from the newsletter even if a recipient has higher in-app access. This is the safest default for an outbound email — if you need to expose more information, relax the tree's visitor-access settings or hand-curate the Extra recipient list.

License

AGPL-3.0-or-later. See LICENSE for the full text.

S
Description
An email newsletter plugin for upcoming birthdays and marriage anniversaries of living tree members as well as birth and death days for deceased.
Readme 257 KiB
Languages
PHP 50.8%
HTML 49.2%