Internal
Public Access
Fix daily email timing to work across all timezones
Critical fix: Task now runs every hour instead of once at 6 AM UTC. This ensures users in all timezones receive their email at 6 AM local time. Changes: - Run task every hour instead of once daily - Check if it's 6-7 AM in user's timezone (1 hour window) - Track sent emails in Notification model to prevent duplicates - Add 'daily_email' notification type Without this fix, users in timezones where 6 AM UTC is not morning would never receive their daily email. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
03cfdea42d
commit
aca8abca56
+1
-1
@@ -24,7 +24,7 @@ app.autodiscover_tasks()
|
|||||||
app.conf.beat_schedule = {
|
app.conf.beat_schedule = {
|
||||||
'send-daily-task-email': {
|
'send-daily-task-email': {
|
||||||
'task': 'notifications.tasks.send_daily_task_email',
|
'task': 'notifications.tasks.send_daily_task_email',
|
||||||
'schedule': crontab(hour=6, minute=0), # Daily at 6 AM UTC
|
'schedule': crontab(minute=0), # Every hour on the hour
|
||||||
},
|
},
|
||||||
'process-recurring-tasks': {
|
'process-recurring-tasks': {
|
||||||
'task': 'notifications.tasks.process_recurring_tasks',
|
'task': 'notifications.tasks.process_recurring_tasks',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class Notification(models.Model):
|
|||||||
('overdue', 'Overdue'),
|
('overdue', 'Overdue'),
|
||||||
('shared', 'Task Shared'),
|
('shared', 'Task Shared'),
|
||||||
('comment', 'Comment'),
|
('comment', 'Comment'),
|
||||||
|
('daily_email', 'Daily Email'),
|
||||||
]
|
]
|
||||||
|
|
||||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
|
|||||||
+23
-2
@@ -45,13 +45,25 @@ def send_daily_task_email():
|
|||||||
user_local_time = timezone.now().astimezone(user_tz)
|
user_local_time = timezone.now().astimezone(user_tz)
|
||||||
user_local_hour = user_local_time.hour
|
user_local_hour = user_local_time.hour
|
||||||
|
|
||||||
# Only send if it's between 6-9 AM in the user's timezone
|
# Only send if it's between 6-7 AM in the user's timezone
|
||||||
if not (6 <= user_local_hour < 9):
|
# (gives 1 hour window, task runs every hour)
|
||||||
|
if not (6 <= user_local_hour < 7):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Get today's date in user's timezone
|
# Get today's date in user's timezone
|
||||||
today = user_local_time.date()
|
today = user_local_time.date()
|
||||||
|
|
||||||
|
# Check if we already sent an email today
|
||||||
|
from .models import Notification
|
||||||
|
already_sent_today = Notification.objects.filter(
|
||||||
|
user=user,
|
||||||
|
notification_type='daily_email',
|
||||||
|
created_at__date=today
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
if already_sent_today:
|
||||||
|
continue
|
||||||
|
|
||||||
# Get tasks due today
|
# Get tasks due today
|
||||||
tasks_due_today = Task.objects.filter(
|
tasks_due_today = Task.objects.filter(
|
||||||
user=user,
|
user=user,
|
||||||
@@ -107,6 +119,15 @@ def send_daily_task_email():
|
|||||||
recipient_list=[user.email],
|
recipient_list=[user.email],
|
||||||
fail_silently=False,
|
fail_silently=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Record that we sent the email (prevents duplicates)
|
||||||
|
Notification.objects.create(
|
||||||
|
user=user,
|
||||||
|
notification_type='daily_email',
|
||||||
|
title=subject,
|
||||||
|
message=f"Daily email sent with {tasks_due_today.count()} tasks due today and {overdue_tasks.count()} overdue tasks"
|
||||||
|
)
|
||||||
|
|
||||||
emails_sent += 1
|
emails_sent += 1
|
||||||
logger.info(f"Sent daily task email to {user.email}")
|
logger.info(f"Sent daily task email to {user.email}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user