SuiteCRM 8.10.2 Campaign emails stuck in Message Queue after migration – never processed

I can confirm this issue on SuiteCRM 8.10.2 (migrated from 7.x), and I found a much more common trigger than failed sends.

Correction of my earlier assumption
At first I suspected that a duplicate email address in the target list caused the problem. Further tests showed that this was a coincidence: duplicates (and other blocked recipients, e.g. records without an email address) are not the cause. Mailings with a duplicate in the list are sent correctly, and mailings without any duplicate fail.

The real trigger: the time between scheduling and the run date
Whether a mailing is sent depends only on how much time lies between scheduling the record and its scheduled run date, relative to the scheduler runs:

  1. The “Queue Campaign Emails” job queues the emails before the scheduled run date.
  2. If the “Send Campaign Emails” job runs after queueing but before the run date, getEntriesToSend() returns no due entries.
  3. Since queueing is finished, the code path mentioned above (DefaultEmailQueueProcessor.php, if (empty($nextQueueEntries) && $isQueueingFinished) setSent()) sets the record to “Sent”.
  4. The emails stay in the queue with 0 send attempts and are never sent.

Reproduction (schedulers every 15 minutes, same target list for both tests):

  • Scheduled at 11:29 with run date 11:50 → queued at 11:30 → record set to “Sent” at 11:45 (before the run date) → emails never sent
  • Scheduled at 11:50 with run date 11:55 → queued and sent correctly at 12:00, because the run date had already passed when the emails were queued

So the root cause is that setSent() is called when there are no due entries, even though entries that are not yet due are still in the queue. This affects practically every newsletter planned in advance, and it fails silently: no log entries, and the status “Sent” suggests the mailing went out.

Workaround: schedule mailings with a run date of “now” or slightly in the past, so that the emails are already due when they are queued.

Full details: Campaign Email Marketing record set to "Sent" before run date – emails stay in queue forever when scheduled in advance