Problem:
Birthday emails were being sent multiple times per day due to a type mismatch and the lack of an immediate early exit, allowing re-processing even with a lock.
The following is log evidence from the admin log on our server of multiple birthday email batch runs. Each entry shows the time the process ran, who ran it, the number of emails sent, and the display names of the recipients. This is only a partial view. Some users have reported receiving as many as forty birthday emails. If you examine the lists of display names, you will see people being sent emails on multiple days as well. SaluteProducts, GucciVSbag1, 69 k20, lanebradford, GMC XLI, John Self, Wildman38, NCars, 1954trucker, Brittain, stylemaster47, mac_the_yankee, Brian Moore, Ian Ferguson, MoonDawg, JohnG 53, 1bigpig!, Bart, BenTolson, slotmandave, slick59, Fleetwoodfloyd, Hookalatch, Bobinpa, CaptKen47, noodlenose, sepp, tirediron
![[Linked Image from stovebolt.com]](https://stovebolt.com/images/Screenshot%202026-01-03%20at%202.33.21%E2%80%AFPM.png)
![[Linked Image from stovebolt.com]](https://stovebolt.com/images/Screenshot%202026-01-03%20at%202.33.36%E2%80%AFPM.png)
Note: the developer fixed a separate problem by ensuring that the value for birthday in {$config['TABLE_PREFIX']}CACHE was not erased when the cache was cleared. This was a necessary fix but did not completely resolve the issue
Solution:
- Added early string exit if $sent === $today (lines 108-110) — prevents a re-run on same day.
- Simplified lock claim query (lines 113-119) — removed redundant AND CACHE_VALUE = ? clause (original had unnecessary extra check; affected_rows suffices).
- Added $sent_count tracking + optional debug log (lines 144, 153-154, 166-167) — counts emails and logs batch size.
Code Changes:
Early exit (added after globals - lines 104 & 105):
PHP
// Quick exit if already done today
if ($sent === $today) {
return;
}
Simplified lock claim (replaced original lines 115-120):
PHP
$query = "
UPDATE {$config['TABLE_PREFIX']}CACHE
SET CACHE_VALUE = ?
WHERE CACHE_FIELD = 'birthdays'
";
$dbh->do_placeholder_query($query, array("PENDING-$rightnow"), __LINE__, __FILE__);
Sent count + log (added in loop and after - added after line 165 - at the end of the function):
PHP
165 // Optional: log how many we sent (for debugging)
if ($sent_count > 0) {
admin_log("BIRTHDAY_BATCH", "Sent $sent_count birthday emails");
}
This last one adds a line to the admin log that looks like this:
2026-01-02 18:00:37 UBB.threads (IP address) BIRTHDAY_BATCH Sent 27 birthday emails
Birthday emails should only be sent by UBB threads, not by user actions, and, if you incorporate this line, you should see one entry per day.