feat: reword the no-eligible-mailbox pause on the start endpoint, the task auto-pause, and its test to name the only cause left (a sending behaviour profile with no working days) now that budget and window gates defer

This commit is contained in:
Matthew Meszaros
2026-09-03 20:18:43 -07:00
parent 711be1f8c2
commit 6bc6bf4345
3 changed files with 9 additions and 5 deletions
+2 -2
View File
@@ -604,8 +604,8 @@ func (s *campaignService) enqueueCampaignWakeup(ctx context.Context, campaignID
case errors.Is(err, scheduler.ErrNoEligibleMailbox):
_ = s.campaignRepository.UpdateStatusWithLock(ctx, campaignID, "paused_no_accounts")
return errx.New(errx.BadRequest,
"this campaign's mailboxes are all outside their sending window or over their daily limit right now; "+
"check each mailbox's timezone, sending behaviour and daily cap")
"no mailbox on this campaign can send under its current sending settings; "+
"check each mailbox's sending behaviour profile (working days) and timezone")
case errors.Is(err, scheduler.ErrNoEmailAccounts):
_ = s.campaignRepository.UpdateStatusWithLock(ctx, campaignID, "paused_no_accounts")
return errx.New(errx.BadRequest, "no active email accounts found for campaign's email tags")
+1 -1
View File
@@ -25,7 +25,7 @@ func TestAutoPauseReason(t *testing.T) {
{
name: "no eligible mailbox",
err: scheduler.ErrNoEligibleMailbox,
want: "Campaign auto-paused: every mailbox is outside its sending window or over its daily budget",
want: "Campaign auto-paused: no mailbox can send under its current sending settings (check each mailbox's sending behaviour profile and timezone)",
},
{
name: "generic no accounts",
+6 -2
View File
@@ -204,9 +204,13 @@ func (s *tasksService) HandleCampaignTask(task *proto.ProcessTask) *errx.Error {
}
if errors.Is(err, scheduler.ErrCampaignDeferred) {
// A valid contact exists but no eligible mailbox right now (ESP-strict
// has no same-provider mailbox, or the daily new-lead cap is reached).
// has no same-provider mailbox, the daily new-lead cap is reached, or
// every mailbox has spent its daily budget or is outside its hours).
// Reschedule at the deferred slot WITHOUT sending and WITHOUT touching
// progress / daily counters / rotation — mirrors the daily-limit path.
// This task completes without a send, and completing it must not
// spend the mailbox's budget either (issue #306): the budget counts
// reserved sends, never bare wake-ups.
// Capped: the next-due moment can be days out, and until this chain
// wakes nothing re-reads the campaign, so leads imported meanwhile
// would sit queued until then.
@@ -908,7 +912,7 @@ func autoPauseReason(err error) string {
case errors.Is(err, scheduler.ErrDomainAuthFailing):
return "Campaign auto-paused: every mailbox is sending from a domain that fails SPF or DMARC authentication"
case errors.Is(err, scheduler.ErrNoEligibleMailbox):
return "Campaign auto-paused: every mailbox is outside its sending window or over its daily budget"
return "Campaign auto-paused: no mailbox can send under its current sending settings (check each mailbox's sending behaviour profile and timezone)"
default:
return "Campaign auto-paused: no active email accounts available"
}