Developer documentation
Why didn't my email arrive
A diagnostic checklist for the common reasons a PulsePigeon send did not reach the recipient. The list is a checklist, not an execution order; skip those that clearly do not apply.
Diagnostic checklist
Walk through these in any order. Each item points to the catalog entry that describes the failure and the fix.
| Area | What to check |
|---|---|
| Role | A Viewer can read but cannot send. Ask an owner or admin for the Developer role or higher. |
| Project mode and captured marker | If the project is in Test mode the API responds with a captured marker and never reaches a real inbox. Send from a Live project with a verified domain. |
| API key and project mode match | A project API key only works with a project in its own mode. Create a key in the same project and mode, or use a workspace key with access to all environments. |
| Account review (vetting) | Live sends require a finished account review. Production returns 428 until that step is complete. |
| Verified sending domain | Live sends need a domain you have verified in Domains, or a single sender address that you have confirmed. |
| Send control | Workspace sending status or a safety restriction can halt new sends. Read the reason on that page. |
| Recipient blocks | Suppressed, deleted, or opted-out recipients are refused. Remove the affected address and resend the rest. |
| Plan limits | Monthly email, active contact, or daily caps that would be exceeded are rejected before acceptance. |
| Batch item failures | A batch returns 200 with per-item accepted and failed entries. Resend unchanged failed items with their original Idempotency-Key and use a new key for a corrected message. |
| Accepted then bounced, deferred, or failed | After acceptance a message can still be deferred, bounced, or fail locally. Inspect Bounces and the delivery timeline rather than resending unconditionally. |
Lifecycle states after acceptance
A 2xx response means the API accepted the message for delivery. After acceptance, the message still moves through one of the states below.
| State | Meaning |
|---|---|
| Captured | The project is in Test mode, so the API accepted the message for inspection but never handed it to a provider. |
| Pending | The message is queued and not yet handed to a provider. |
| Deferred | The provider reported a delay for this recipient. Check the delivery timeline and Bounces before you resend. |
| Suppressed | The address bounced, so future sends to it are refused. Fix or remove it; a suppressed address is not retried. |
| Terminal failure | PulsePigeon could not hand the message to a provider because of a delivery or configuration problem. Contact support if the reason repeats. |
A deferred or captured message does not need an unconditional resend. Retries reuse the original Idempotency-Key, and a corrected message uses a new key. Inspect Bounces and the delivery timeline before sending again.
Send conditions catalog
The HTTP status, typed code, reason, and fix for every entry in the catalog's send group. The same entries drive the support block returned with each API error.
| HTTP | Code | Why | Fix |
|---|---|---|---|
| 403 | permission_denied | Your role is Viewer, which is read-only. | Ask an owner or admin for the Developer role or higher. |
| marker | delivery_mode=test_capture | This project is in Test mode, so sends are captured and never reach a real inbox. | Send from a Live project with a verified domain to deliver real email. More |
| 403 | api_key_environment_mismatch | This API key belongs to a different project or mode than the one you used. | Create a key in the same project and mode, then use it. More |
| 403 | api_key_project_mismatch | This API key belongs to a different project or mode than the one you used. | Create a key in the same project and mode, then use it. More |
| 422 | api_key_environment_project_mismatch | This API key belongs to a different project or mode than the one you used. | Create a key in the same project and mode, then use it. More |
| 403 | domain_not_verified | The From address is not on a domain you have verified. | Verify the domain, or confirm this single sender address, then send again. More |
| 428 | pre_send_vetting_required | Production sending starts after your account passes a short review. | Finish the review, or contact support if it is stuck. More |
| marker | template_test_send_vetting | Template test sends need the account review even for Test projects. | Finish the account review, or send a test through the message API to a Test project. More |
| 423 | sending_halted | Sending is paused for this workspace. | Read the reason shown, then contact support to appeal. |
| 402 | subscription_restricted | Your subscription state blocks new sends. Exports stay available. | Fix billing to resume sending. |
| 402 | subscription_suspended | Your subscription state blocks new sends. Exports stay available. | Fix billing to resume sending. |
| 402 | subscription_canceled | Your subscription state blocks new sends. Exports stay available. | Fix billing to resume sending. |
| 402 | subscription_quarantined | Your subscription state blocks new sends. Exports stay available. | Fix billing to resume sending. |
| 402 | plan_monthly_limit_exceeded | Your plan's monthly email or active contact limit is used up. | Upgrade your plan or wait for the next period. |
| 402 | plan_contact_limit_exceeded | Your plan's monthly email or active contact limit is used up. | Upgrade your plan or wait for the next period. |
| 429 | hard_spend_cap_exceeded | Your daily sending cap is reached. | Retry after the daily reset or review your limits. |
| 429 | sending_limit_exceeded | Your daily sending cap is reached. | Retry after the daily reset or review your limits. |
| 403 | recipient_unsubscribed | This recipient opted out of this kind of email. | Do not resend to this address in this category. More |
| 422 | recipient_suppressed | A recipient is suppressed or was deleted. | Remove that recipient from the send. More |
| 422 | recipient_deleted | A recipient is suppressed or was deleted. | Remove that recipient from the send. More |
| 422 | recipient_suppressed_by_dsr | A recipient is suppressed or was deleted. | Remove that recipient from the send. More |
| 422 | consent_required | Marketing mail needs recipient consent. Set mailing address under /compliance. | Save your mailing address on /compliance, then record consent for recipients. |
| 422 | physical_address_required | Marketing mail needs recipient consent. Set mailing address under /compliance. | Save your mailing address on /compliance, then record consent for recipients. |
| 422 | can_spam_footer_required | Marketing mail needs recipient consent. Set mailing address under /compliance. | Save your mailing address on /compliance, then record consent for recipients. |
| marker | batch_item_failed | An item in the batch failed; others may still have been accepted. | Read that item's error; resend unchanged failed items with their original key, and use a new key for a corrected message. More |
| marker | delivery_pending | The message is queued and not yet handed to a provider. | Wait; no action needed. More |
| marker | delivery_deferred | The provider reported a delay for this recipient. | Check the delivery timeline and Bounces before you resend. More |
| marker | delivery_bounced_suppressed | The address bounced, so it is suppressed and future sends to it are refused. | Fix or remove the address; a suppressed address is not retried. More |
| marker | delivery_failed_local | PulsePigeon could not hand the message to a provider because of a delivery or configuration problem on our side or in your setup. | Check the failure reason on the message; contact support if it repeats. More |
| 503 | recipient_gate_unavailable | A recipient eligibility check could not be completed. | Check whether the send was accepted before retrying; if it was not, try again later. |
| 403 | recipient_suppressed_global | A workspace suppression blocks this recipient. | Review the workspace suppression before attempting another send; a stream change will not remove it. |
| 403 | recipient_suppressed_stream | An active suppression for this stream blocks the recipient. | Review the stream suppression and recipient preference before attempting another send. |
| 503 | stream_suppression_unavailable | The stream suppression service could not complete a required check or token operation. | Check whether the operation was accepted before retrying; if its outcome is unknown, verify its current state first. |
| 503 | unsubscribe_origin_unavailable | The hosted unsubscribe origin is unavailable for this send. | Check whether the send was accepted before retrying; contact support if link generation remains unavailable. |
| 422 | transactional_content_promotional | Transactional, security, and billing mail cannot include promotional phrasing. | Send this as category=marketing with real recipient consent, or remove the promotional phrasing. More |
| 503 | unsubscribe_link_unavailable | The unsubscribe link for this marketing send could not be minted. | Retry the send. Contact support if link generation remains unavailable. |
| 422 | marketing_footer_too_large | The marketing footer would push this HTML body past the allowed size. | Shorten the HTML body and retry the send. |
When to ask support
- The message accepted with a 2xx response, never bounced or deferred, but still did not arrive.
- The message landed in Dead letters with a failure reason for an address that should be routable.
- A batch reported every item as failed with no shared error code.
Include the message ID, the project ID, and the timestamp. Do not paste the raw payload, any Idempotency-Key, or recipient addresses into a public ticket.
Diagnostic prompts
Use these prompts to drive your own checks before asking support. They are not an execution order.
- Did the send return a 2xx response, or did it fail with a typed error code?
- If it returned 2xx, is the project in Test mode (then the message was captured, not delivered)?
- If you use a project API key, is it bound to the same project and mode that you sent from?
- Has the workspace passed the production account review?
- Is the From address on a verified domain or a single confirmed sender?
- Is the recipient opted in, not suppressed, not deleted, and not blocked by your blocklists?
- Would this send push the workspace past its plan, contact, or daily cap?
- For batches: did any item fail even though the response was 200?
- For accepted messages: did the message later appear in Bounces or the delivery timeline as deferred or failed?
Related guides
API error reference · Test and Live projects · Webhook verification · Bounces · Contact support