From ce2d230d843af5face90c9d87f02b32b04202174 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:07:31 +0000 Subject: [PATCH 1/4] Initial plan From 8e01e7f0f911d24f47d4382a0ed5afd3fc20152a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:14:55 +0000 Subject: [PATCH 2/4] Add personalized reminder emails with organization and time info Co-authored-by: DonnieBLT <128622481+DonnieBLT@users.noreply.github.com> --- .../commands/cron_send_reminders.py | 112 +++++++++++------- .../templates/website/reminder_settings.html | 17 ++- website/views/daily_reminders.py | 92 ++++++++++++-- 3 files changed, 171 insertions(+), 50 deletions(-) diff --git a/website/management/commands/cron_send_reminders.py b/website/management/commands/cron_send_reminders.py index 665ced381c..726834499f 100644 --- a/website/management/commands/cron_send_reminders.py +++ b/website/management/commands/cron_send_reminders.py @@ -3,7 +3,6 @@ import random import time from datetime import time as dt_time -from itertools import islice from django.conf import settings from django.core.mail import EmailMultiAlternatives @@ -15,12 +14,6 @@ logger = logging.getLogger(__name__) -def batch(iterable, size): - """Helper function to create batches from an iterable""" - iterator = iter(iterable) - return iter(lambda: list(islice(iterator, size)), []) - - class Command(LoggedBaseCommand): help = "Sends daily check-in reminders to users who haven't checked in today" @@ -76,7 +69,7 @@ def handle(self, *args, **options): user_ids = [rs.user_id for rs in active_settings] profile_map = {profile.user_id: profile for profile in UserProfile.objects.filter(user_id__in=user_ids)} - users_needing_reminders = [] + reminders_to_send = [] for reminder_settings in active_settings: try: @@ -85,7 +78,7 @@ def handle(self, *args, **options): if profile and profile.last_check_in and profile.last_check_in == now.date(): continue - users_needing_reminders.append(reminder_settings.user) + reminders_to_send.append((reminder_settings, profile)) logger.info( f"User {reminder_settings.user.username} added to reminder list for time {reminder_settings.reminder_time} ({reminder_settings.timezone})" ) @@ -94,33 +87,63 @@ def handle(self, *args, **options): logger.error(f"Error processing user {reminder_settings.user.username}: {str(e)}") continue - if not users_needing_reminders: + if not reminders_to_send: logger.info("No users need reminders at this time") return - # Process users in batches of 50 - batch_size = 50 - successful_batches = 0 - failed_batches = 0 - total_users = len(users_needing_reminders) + # Process reminders individually for personalization + successful_count = 0 + failed_count = 0 + total_users = len(reminders_to_send) - for i, user_batch in enumerate(batch(users_needing_reminders, batch_size), 1): + for i, (reminder_settings, profile) in enumerate(reminders_to_send, 1): try: - # Add random delay between batches (1-5 seconds) if not the first batch - if i > 1: - delay = random.uniform(1, 5) - logger.info(f"Waiting {delay:.2f} seconds before processing batch {i}") + # Add small delay between emails to avoid overwhelming the server + if i > 1 and i % 10 == 0: + delay = random.uniform(0.5, 2) + logger.info(f"Processed {i} emails, waiting {delay:.2f} seconds") time.sleep(delay) + user = reminder_settings.user + + # Get organization info + org_name = "" + org_info_html = "" + if profile and profile.team: + org_name = profile.team.name + org_info_html = f""" +
Organization: {org_name}
+It's time for your daily check-in! Please log in to update your status.
-Hello {user.username},
+It's time for your daily check-in{f" for {org_name}" if org_name else ""}! Please log in to update your status.
+ {org_info_html} +Your Reminder Time: {reminder_time_str} ({timezone_str})
+Regular check-ins help keep your team informed about your progress and any challenges you might be facing.
-Thank you for keeping your team updated!
+Thank you for keeping your team updated!
+Best regards,
The BLT Team