# webtrees Email Newsletter A [webtrees](https://www.webtrees.net/) 2.2+ custom module that sends recurring email newsletters with: - **Upcoming birthdays** of still-living individuals. - **Upcoming marriage anniversaries** of intact couples (optional — admin toggle, per tree). Marriages with a divorce or annulment fact are excluded automatically. - **Once-per-month historical section**: births and deaths of deceased individuals whose anniversary falls in the upcoming window. The decision to actually send is made by comparing a stored "last sent" timestamp to the configured frequency, so the dispatch run is idempotent — calling the trigger more often than the frequency simply does nothing extra. ## Requirements - webtrees ≥ 2.2.0 - PHP ≥ 8.2 - A working SMTP / sendmail configuration in *webtrees → Control panel → Sending email* (this module reuses webtrees' standard mailer). - An external scheduler on the host: system `cron`, a `systemd` timer, a Kubernetes `CronJob`, or anything else that can fire an HTTP request at a fixed interval. **Newsletter dispatch never runs on visitor page loads — it only runs when the scheduler triggers it.** ## Installation 1. Copy this directory into the webtrees `modules_v4/` folder, renaming it to `email_newsletter` (the folder name determines the internal module identifier — the registered name will be `_email_newsletter_`). ```sh 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: - Enable newsletter dispatch per tree. - Pick a frequency (default: 14 days). - Optionally toggle marriage anniversaries and add any extra external email addresses. - Copy the **Cron URL** at the bottom — this is the secret-token URL your scheduler must hit. ## 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 ```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`: ```ini [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`: ```ini [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 one-off send, append `&force=1` to the cron URL — that bypasses the "is it due?" check. ## Subscribers Two sources, combined: 1. **Logged-in webtrees users** who opt in via the per-tree *Newsletter subscription* menu entry (visible only to logged-in users on trees where the module is enabled). Only **approved and email-verified** accounts will receive the newsletter. 2. **External addresses** the tree administrator lists in the *Extra recipient email addresses* textarea (one per line). ## 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.