feat(email): add support for scheduled email sending in tickets/talks#3485
feat(email): add support for scheduled email sending in tickets/talks#3485MukundC25 wants to merge 3 commits intofossasia:devfrom
Conversation
There was a problem hiding this comment.
Sorry @MukundC25, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
There was a problem hiding this comment.
Pull request overview
Adds “send later” scheduling for outbound emails in both the Tickets (sendmail plugin) and Talk/CfP (orga mail) flows by persisting a scheduled_at timestamp and adding background processing to dispatch due emails.
Changes:
- Add
scheduled_atto both TicketsEmailQueueand Talk/CfPQueuedMail, plus corresponding migrations. - Add scheduling fields to compose/edit UIs and show scheduled/immediate status in outbox lists.
- Add Celery/signal-based processing for scheduled sends, including an eta-trigger path and a periodic poller.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| app/eventyay/plugins/sendmail/views.py | Persists scheduled_at when composing and schedules Celery send tasks. |
| app/eventyay/plugins/sendmail/templates/pretixplugins/sendmail/send_team_form.html | Adds “Scheduling” fieldset to team email compose UI. |
| app/eventyay/plugins/sendmail/templates/pretixplugins/sendmail/send_form.html | Adds “Scheduling” fieldset to attendee email compose UI. |
| app/eventyay/plugins/sendmail/templates/pretixplugins/sendmail/outbox_list.html | Adds Status column showing scheduled vs immediate. |
| app/eventyay/plugins/sendmail/templates/pretixplugins/sendmail/outbox_form.html | Allows editing scheduled_at in outbox editor. |
| app/eventyay/plugins/sendmail/tasks.py | Adds scheduled-time pre-check/reschedule behavior in send task. |
| app/eventyay/plugins/sendmail/models.py | Adds scheduled_at field + guard to prevent early sends. |
| app/eventyay/plugins/sendmail/migrations/0002_emailqueue_scheduled_at.py | DB migration for Tickets EmailQueue.scheduled_at. |
| app/eventyay/plugins/sendmail/forms.py | Adds scheduled_at fields + validation and allows editing on outbox items. |
| app/eventyay/orga/views/mails.py | Handles scheduled compose flow and schedules periodic signal dispatch at ETA. |
| app/eventyay/orga/templates/orga/mails/outbox_list.html | Adds Status column showing scheduled vs immediate. |
| app/eventyay/orga/templates/orga/mails/outbox_form.html | Adjusts outbox form rendering (enables scheduled field rendering). |
| app/eventyay/orga/templates/orga/mails/_mail_editor.html | Adds scheduled_at field rendering in shared editor partial. |
| app/eventyay/orga/forms/mails.py | Adds scheduled_at fields/validation and a talk-specific datetime widget. |
| app/eventyay/event/services.py | Hardens periodic event mail checks (null-safety + date_to logic). |
| app/eventyay/control/forms/init.py | Changes timezone awareness handling for SplitDateTimeField. |
| app/eventyay/common/tasks.py | Adds Celery task to emit periodic_task signal. |
| app/eventyay/common/signals.py | Adds scheduled email poller receiver processing due QueuedMail/EmailQueue. |
| app/eventyay/common/apps.py | Ensures common.tasks is imported/registered on app ready. |
| app/eventyay/base/models/mail.py | Adds scheduled_at + guard in Talk/CfP QueuedMail.send(). |
| app/eventyay/base/migrations/0025_queuedmail_scheduled_at.py | DB migration for Talk/CfP QueuedMail.scheduled_at. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 52bbcc414d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
52bbcc4 to
1fe6bb4
Compare
002488b to
8d6d19f
Compare
| if scheduled_at: | ||
| send_queued_mail.apply_async(args=[self.request.event.pk, qm.pk], eta=scheduled_at) | ||
| self.request.event.log_action( |
| for mail in result: | ||
| send_scheduled_queuedmail.apply_async(args=[mail.pk], eta=scheduled_at) | ||
| messages.success( |
| with transaction.atomic(): | ||
| qm = ( | ||
| EmailQueue.objects |
| for mail in result: | ||
| send_scheduled_queuedmail.apply_async(args=[mail.pk], eta=scheduled_at) | ||
| messages.success( |
| if self.scheduled_at and self.scheduled_at > now(): | ||
| raise SendMailException(_('This mail is scheduled for the future and cannot be sent yet.')) |
Fixes #1137
What This PR Does
Implements email scheduling for both the Tickets and Talk/CfP components, allowing organizers to set a future date/time for email delivery instead of sending immediately.
Database Schema & Guards
scheduled_atfield toQueuedMail(Talk/CfP component)scheduled_atfield to [EmailQueue] (Tickets component)Scheduler & Background Processing
eta=scheduled_at, so delivery happens at the exact scheduled timesend_queued_mail.apply_async(eta=scheduled_at)per emailsend_periodic_signal.apply_async(eta=scheduled_at)to trigger [process_scheduled_emails]select_for_update(skip_locked=True)+@minimum_intervaldecorator prevent duplicate sends across workersSendMailExceptionspecifically; re-raises unexpected exceptions to keep errors visibleUI Features
scheduled_atfor unsent emailsInfrastructure Requirements
For Local Development: No additional setup beyond
docker compose up -d. Celery Beat can be configured via Django admin (PeriodicTaskentry for [eventyay.common.tasks.send_periodic_signal].For Production: Requires Celery Beat to be running with a
PeriodicTaskentry for [eventyay.common.tasks.send_periodic_signal] at a 60-second interval. This is intentionally not automated via migrations to avoid coupling application migrations to infrastructure configuration.Testing
docker compose logs worker -f | grep ScheduledMailSELECT id, subject, scheduled_at, sent_at FROM sendmail_emailqueue WHERE scheduled_at IS NOT NULL;Notes
scheduled_atstored in UTC, displayed in user's timezoneEmail Scheduling (IST)
Screen.Recording.2026-05-07.at.7.54.23.PM.mov