{"record":{"id":"0aac8b528f58920a","repo":"jackwener/OpenCLI","slug":"sales-navigator-inmail-blocked-by-recipient-restri","errorCode":null,"errorMessage":"Sales Navigator InMail blocked by recipient restriction","messagePattern":"Sales Navigator InMail blocked by recipient restriction","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-message.js","lineNumber":285,"sourceCode":"    if (!page) throw new CommandExecutionError('Browser session required for linkedin salesnav-message');\n    const recipientArg = requireStringArg(args, 'recipient', '--recipient');\n    const subject = requireStringArg(args, 'subject', '--subject');\n    const body = String(args.body ?? '').trim();\n    if (!body) throw new ArgumentError('--body is required');\n\n    await page.goto(SALES_HOME);\n    await page.wait(4);\n    const csrf = await getCsrf(page);\n    const recipient = await resolveRecipient(page, parseRecipient(recipientArg), csrf);\n\n    let summary = { recipient: '', title: '', company: '', degree: '', inmail_restriction: '', open_link: false };\n    const profileUrl = profileApiUrl(recipient);\n    if (profileUrl) {\n      const profileResult = requireFetchResult(unwrapEvaluateResult(await page.evaluate(fetchJsonScript(profileUrl, csrf))), 'LinkedIn Sales Navigator profile API');\n      summary = requireProfileSummary(profileResult.json);\n    }\n    if (summary.inmail_restriction && summary.inmail_restriction !== 'NO_RESTRICTION') {\n      throw new CommandExecutionError('Sales Navigator InMail blocked by recipient restriction', summary.inmail_restriction);\n    }\n\n    const creditsResult = requireFetchResult(unwrapEvaluateResult(await page.evaluate(fetchJsonScript(CREDITS_URL, csrf))), 'LinkedIn Sales Navigator credits API');\n    const creditsRemaining = extractRemainingCredits(creditsResult?.json);\n\n    const payload = buildCreateMessagePayload({ recipientUrn: recipient.entityUrn, subject, body, copyToCrm: args['copy-to-crm'] });\n    if (!args.send) {\n      return [{\n        status: 'validated_dry_run',\n        recipient: summary.recipient,\n        title: summary.title,\n        company: summary.company,\n        credits_remaining: creditsRemaining,\n        credits_before: creditsRemaining,\n        credits_after: '',\n        sent_in_salesnav: false,\n        message_chars: body.length,\n        subject_chars: subject.length,","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-message.js#L267-L303","documentation":"The library fetched the recipient's Sales Navigator profile and found that the profile's inmail_restriction field is not NO_RESTRICTION, meaning LinkedIn blocks sending an InMail to this recipient. It throws before consuming any InMail credit, because the send would fail or be silently disallowed.","triggerScenarios":"Calling the salesnav-message CLI for a recipient whose LinkedIn profile has an InMail restriction (e.g. recipient opted out of InMails, is outside your network with restricted messaging, or has a 'NO_INMAIL' style restriction value other than NO_RESTRICTION).","commonSituations":"Messaging open-to-work-only or InMail-opted-out candidates; contacting recipients whose accounts limit commercial messages; sending to profiles the operator's seat cannot reach (tier/seat restrictions); stale profile summary cached before recipient changed settings.","solutions":["Pick a different recipient or contact path (regular LinkedIn message/connection request) — the restriction is on LinkedIn's side and cannot be bypassed.","Re-fetch the profile to confirm the restriction value is current, then skip or queue the recipient in your outreach tooling.","Check the thrown detail (the restriction value) and map it in your caller to decide whether retrying later is meaningful (usually not — restrictions are persistent)."],"exampleFix":"// before\nawait sendSalesNavInMail({ recipient, subject, body });\n// after\nconst profile = await fetchProfileSummary(recipient);\nif (profile.inmail_restriction && profile.inmail_restriction !== 'NO_RESTRICTION') {\n  console.warn(`Skipping ${recipient.id}: ${profile.inmail_restriction}`);\n  return { status: 'skipped', reason: profile.inmail_restriction };\n}\nawait sendSalesNavInMail({ recipient, subject, body });","handlingStrategy":"try-catch","validationCode":"const summary = await fetchProfileSummary(recipient);\nif (summary.inmail_restriction && summary.inmail_restriction !== 'NO_RESTRICTION') {\n  throw new SkipError(`Recipient restricted: ${summary.inmail_restriction}`);\n}","typeGuard":"function canSendInMail(summary) {\n  return !!summary && (summary.inmail_restriction ?? 'NO_RESTRICTION') === 'NO_RESTRICTION';\n}","tryCatchPattern":"try {\n  await sendSalesNavInMail(recipient, { subject, body });\n} catch (e) {\n  if (e.detail && e.detail !== 'NO_RESTRICTION') {\n    markRecipientBlocked(recipient, e.detail);\n    return { status: 'skipped' };\n  }\n  throw e;\n}","preventionTips":["Pre-screen recipients' inmail_restriction in bulk before campaigns","Keep a blocklist of restricted recipients","Do not auto-retry InMail sends — restrictions are persistent","Map restriction codes to alternate contact channels"],"tags":["linkedin","sales-navigator","inmail","policy-restriction"],"backgroundTag":"inmail-recipient-restricted","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}