Timezone-aware Campaign Scheduling
Description
I propose adding a feature to Listmonk that allows scheduling email campaigns based on each subscriber's timezone, stored as an attribute or a dedicated field in the subscribers table. This would enable sending emails at a precise local time for each subscriber (e.g., 10:00 AM in their timezone), improving deliverability and open rates while reducing queue bottlenecks caused by long, uniform send lists.
Problem
Currently, Listmonk schedules campaigns at a single UTC time (send_at) for all subscribers in a campaign, regardless of their location. This can lead to:
-
Suboptimal open rates: Emails may arrive at inconvenient times (e.g., midnight) for subscribers in different timezones.
-
Queue overload: Sending all emails simultaneously creates large queues, potentially throttling delivery with SMTP providers like Postmark.
-
Deliverability risks: Bulk sends at a single time may increase the chance of being flagged as spam.
Proposed Solution
1. Timezone Collection:
-
Allow capturing a subscriber’s timezone as an attribute (e.g.,
attribs->>'timezone' = 'Europe/Paris') via: -
Public subscription forms (e.g., using JavaScript
Intl.DateTimeFormat().resolvedOptions().timeZoneto auto-detect). -
Manual entry or API (
POST /api/subscriberswithattribs). -
Optionally, add a dedicated
timezonecolumn to thesubscriberstable for permanent storage and indexing.
2. Campaign Scheduling:
-
Add an option in the campaign creation interface (e.g., "Send based on subscriber timezone") with a target local time (e.g., "10:00 AM local time").
-
When enabled, Listmonk calculates the UTC csend_at` time for each subscriber based on their stored timezone and the specified local time.
3. Queue Management:
-
Distribute the campaign send jobs across multiple time slots in the internal queue, avoiding a single large batch.
-
Leverage the existing worker pool to process sends incrementally, reducing SMTP throttling risks.
Benefits
-
Higher open rates: Emails arrive at optimal local times (e.g., morning), increasing engagement.
-
Improved deliverability: Smaller, staggered batches reduce the likelihood of being flagged as spam by SMTP providers.
-
Reduced queue bottlenecks: Spreads the load over time, avoiding long wait times and improving performance.
Implementation Suggestion
Database:
- Add an optional timezone column to
subscribers(e.g.,VARCHAR(50) with values likeAmerica/New_York), or useattribs->>'timezone'.
Frontend:
- Extend the campaign form with a checkbox: "Send based on subscriber timezone" and a field for target local time (e.g., "10:00").
- Update subscription forms to include JavaScript timezone detection:
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; document.getElementById('timezone').value = timezone;
Backend:
- Modify the campaign scheduler to:
- Query subscribers’ timezones.
- Calculate UTC send times per subscriber (e.g., 10:00 Europe/Paris = 09:00 UTC).
- Queue individual send jobs with staggered send_at timestamps.
API:
- Add a
timezone_awareboolean toPOST /api/campaigns(e.g.,{ "send_at": "10:00", "timezone_aware": true }).
Example Use Case
- A campaign targets 10,000 subscribers across 5 timezones (e.g., PST, EST, GMT, CET, IST).
- User sets "Send at 10:00 AM local time" with
timezone_aware: true. - Listmonk schedules 2,000 emails per timezone, sending them at:
- 17:00 UTC (PST: 10:00 AM).
- 14:00 UTC (EST: 10:00 AM).
- etc.
- Result: Emails arrive at 10:00 AM local time for each subscriber, spread over hours, improving open rates and deliverability.
Additional Notes
- Ensure backwards compatibility: If
timezoneis missing for a subscriber, fall back to the campaign’s globalsend_at. - Document the feature in the API and UI guides.
Motivation
This feature would make Listmonk a stronger competitor to tools like Mautic or commercial platforms (e.g., Mailchimp), where timezone-aware sending is a standard for maximizing engagement and deliverability.
Hi @githubcom13, while this is an interesting proposal, the queuing logic you are proposing is fundamentally incompatible with how it works currently.
listmonk handles campaigns serially (once a campaign starts, it iterates through 0-n ordered subscriptions until the campaign ends by reaching n), and processes at a campaign->n lists level. It paginates from 0-n and uses a checkpoint mechanism to track progress, which fully depends on the records being sequential. A significant number of optimisations have been done to make this model work performantly. Changing it to do scheduling per subscriber, I would think, is outright impossible, without rewriting the entire scheduling core and logic.
This issue has been marked 'stale' after 90 days of inactivity. If there is no further activity, it will be closed in 7 days.