When Selda holds a send
You approve a send and one lead does not go. This page is the whole list of reasons that can happen, and the only question worth asking about each one: who decided?
- You decided — Selda is enforcing something you set. It stays.
- A limit — a ceiling or a plan contract. Not an opinion about this lead.
- A setting — Selda formed a judgement. You own that judgement: ten switches, all on by default, and most of them can be clicked past for one lead without turning the rule off.
- A fact — there is nothing to send, or nowhere to send it.
Selda never invents a reason and never hides one. A held lead shows its reason in words, with who decided it and what you can do next. An unrecognised code renders an honest “cannot put this into words”, never a raw enum.
Where the switches are
The Brain → When Selda holds a send. One screen, not one per channel: every rule below governs LinkedIn exactly as much as email.
The daily cap is deliberately not there. It lives in Settings → Channels, because it is a property of the sending mailbox or profile rather than a judgement Selda formed. See Email and LinkedIn.
You decided
Enforced, because you are the one who said so. The fix is to change your own instruction.
| Reason | What happened |
|---|---|
sandbox | The workspace is in the free sandbox. Nothing sends until it goes live. |
workspace_stopped | You stopped the workspace. |
workspace_paused | An owner or admin paused the whole workspace. Resume it first; held messages are scheduled again, spread out. |
campaign_paused | You paused this campaign. |
removed_from_campaign | You took this lead out. |
not_armed | The step is not armed to send yet. |
original_not_sent | A follow-up cannot go before the message it follows. |
you_replied | You answered this person yourself, so Selda stood down. Resumable per lead. |
A limit
Not a judgement about the lead. Nothing to override, because the answer is elsewhere.
| Reason | What happened |
|---|---|
daily_cap | The mailbox or profile has sent its allowance for today. It resumes tomorrow. |
linkedin_invite_cap | Today’s LinkedIn connection invites have all gone out. The rest are held, not dropped, and go tomorrow. |
linkedin_message_cap | Today’s LinkedIn first messages have all gone out. Same: held, and they go tomorrow. |
linkedin_like_cap | Today’s LinkedIn post likes have all gone out. Same: held, and they go tomorrow. |
plan_cannot_send | The plan does not include sending on this channel. |
outbound_disabled | Outbound is switched off for this workspace. |
LinkedIn carries two ceilings rather than one, because LinkedIn restricts an account for inviting too fast independently of what it messages, and the account is your own profile. Both are in Settings → Email, under the LinkedIn row, with today’s count beside each. Set your own number or leave Selda’s, which the row states rather than applies silently. Reminders inside a conversation already open are never held by either one.
Selda’s judgement, and therefore your setting
Ten settings, every one on by default. Eight reproduce the behaviour that shipped before them;
stopOnNothingNew and stopOnColleagueReply were new defaults, chosen on purpose.
Turning one off is your call, and two of them carry a legal warning and an explicit acknowledgement
rather than a casual toggle.
| Setting | Holds when | Per-lead override |
|---|---|---|
stopOnReply | The recipient replied (recipient_replied) | yes |
stopOnColleagueReply | Somebody else at the same company answered this campaign, so reminders to colleagues already written to stop (colleague_answered) | yes |
stopOnMeetingBooked | A meeting is on the calendar (meeting_booked) | yes |
stopOnBounce | The address bounced (excluded) | no |
respectOptOut | They asked not to be contacted (do_not_contact) | no, and it carries a legal warning |
stopOnSuppressed | The address or domain is suppressed (suppressed) | no, and it carries a legal warning |
holdOnClosedDay | A public holiday or outside your sending hours (deferred_closed_day, deferred_outside_hours) | yes |
holdPreSendCheck | The pre-send check raised something (pre_send_check) | yes |
holdOnTakenSlot | The meeting time the message offers is already taken (offered_time_taken) | yes |
stopOnNothingNew | The follow-up would repeat what the last one said (nothing_new_to_say) | yes |
A fact
Nothing to decide. Most of these have a fix, and the fix is never a switch.
| Reason | What happened | The fix |
|---|---|---|
no_connected_inbox | No mailbox or profile is connected | Connect one in Settings → Channels |
channel_disconnected | Connected here, gone at the provider | Reconnect it |
linkup_disconnected | A LinkedIn account is no longer connected | Reconnect it in Settings → Email and calendar |
greeting_recipient_mismatch | The greeting names one person and the address is someone else’s | One word in the greeting, or the right address on the row |
already_contacted | You have written to this person before | Resumable per lead, if reaching them again is what you meant |
send_failed | The provider refused it. The error is shown as it came back | Depends on the error |
no_pending_followup · no_pending_steps | There is no next step waiting | Nothing is wrong |
greeting_recipient_mismatch is the one Selda-side hold with no setting and no override, and
it is the exception that proves the rule. A message whose greeting and whose address name two
different people is a fact about the artifact, not an opinion about the situation, and it is the
one outcome on this path that cannot be taken back. Nobody is denied anything: name the recipient
in the greeting, or put their address on the row, and it clears.
Nothing to send
Not holds at all. They appear for completeness, because a lead that did not move should always say why.
| Reason | What happened |
|---|---|
completed | The sequence finished |
stopped | The sequence was stopped |
already_sent | This exact message is already in their inbox. Sending again is the one thing this prevents |
send_in_progress | Another pass is inside the send right now. It retries |
Every code on this page is in convex/lib/sendStopPolicy.ts, and
convex/lib/__tests__/sendStopsAreDocumented.test.ts fails if a code is added there and not
described here, or described here and not in the catalog.