Two-level gate: resolve and embed the tree-contact portrait only when (a) at least one locale on the tree has a non-empty intro on file, and (b) the specific recipient is still pending delivery for the current intro version. Recipients who have already seen this intro, or whose locale has no intro, no longer carry the extra image bytes.
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 useIntlDateFormatterfor the recipient's locale. - Per-recipient relationship labels — "your mother", "4th great-
grandfather", "first cousin twice removed". Uses webtrees' own
RelationshipServiceso 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 eitherext-imagickorext-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,systemdtimer, KubernetesCronJob, …) that can fire an HTTP request at a fixed interval. Newsletter dispatch never runs on visitor page loads.
Installation
-
Copy this directory into the webtrees
modules_v4/folder, renaming it toemail_newsletter:cp -r webtrees_email_newsletter /var/www/webtrees/modules_v4/email_newsletter -
In the webtrees control panel, go to Modules → All modules and enable Email Newsletter.
-
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.
-
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:
- 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. - Webtrees users an admin subscribes from the preferences page.
- 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 SiteUser — Control 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.