Sandbox vs Live
Every ScaiSend send runs in one of two modes: live (actually delivered) or sandbox (validated, recorded, but not delivered). This page describes when each applies, how to force sandbox, and how to verify what happened.
The two mechanisms#
Sandbox mode turns on in two independent ways:
- The request uses a test API key (
sg_test_*). Every request made with the key is sandbox. There is no way to override this to live. - The request body sets
mail_settings.sandbox_mode.enable: true. Per-request override; works on live and test keys alike.
Either mechanism is sufficient. If both are absent, the send goes live.
| Key type | sandbox_mode.enable |
Result |
|---|---|---|
sg_live_* |
absent or false |
Live send |
sg_live_* |
true |
Sandbox |
sg_test_* |
absent or false |
Sandbox |
sg_test_* |
true |
Sandbox |
What happens in each mode#
Live mode#
- Request is validated (schema, size, attachment count, template_id format, etc.).
- If
From:domain isn't verified, the request fails synchronously. - Message is persisted with status
QUEUED. - Worker service picks it up, renders the template, applies tracking, builds MIME.
- SMTP service picks it up, resolves MX, DKIM-signs, connects, delivers.
- Events (
processed,delivered,bounce,deferred,open,click) are recorded and fanned out to webhooks. - Status progresses:
QUEUED→PROCESSING→SENDING→DELIVERED(orBOUNCED/FAILED).
Sandbox mode#
- Request is validated the same way as live.
- Domain verification is not checked. You can send from an unverified domain in sandbox.
- Message is persisted with status
SANDBOX. - Nothing is queued to the SMTP service. The Worker doesn't render the template; no MIME is built.
- No events are fanned out. You won't receive
delivered,bounce, etc. - Response shape is identical to live — same
message_id, same HTTP status.
Sandbox messages are visible via GET /v3/messages and GET /v3/messages/{id} with status sandbox.
Forcing sandbox on a live key#
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Using test keys in CI#
Create a dedicated test key for CI:
1 2 3 4 | |
Store the returned sg_test_* key as a CI secret. Your test suite can call /v3/mail/send against a real ScaiSend instance without sending real mail — request validation, template rendering, and response shape all behave exactly as they would in production.
This is the pattern to prefer over per-request sandbox_mode. Environment isolation via the key type is a stronger guarantee than a body flag that a misconfigured environment variable could flip.
Confirming a send was sandboxed#
1 2 | |
The status field is sandbox. The events[] array is empty (or contains only processed if your deployment records that even for sandbox — varies by version).
1 2 3 4 5 6 7 8 9 | |
What sandbox does not do#
- No rate limits are enforced differently. Sandbox sends count against your tenant's rate limit.
- No statistics are incremented.
GET /v3/statsignores sandbox messages. You won't see them inprocessedcounts. - No webhooks fire. Your production webhook endpoint won't be bothered by CI traffic.
- Attachments are not stored. ScaiSend accepts them (and validates size and type) but doesn't persist them to S3.
When to use each#
| Scenario | Mechanism |
|---|---|
| CI pipeline, end-to-end integration tests | Test key (sg_test_*) |
| Staging environment | Test key |
| Local developer laptops | Test key, one per developer |
| Production smoke test immediately after deploy | Live key with sandbox_mode.enable: true |
| Debugging a send failure in production without delivering | Live key with sandbox_mode.enable: true |
| Production traffic | Live key |
What's next#
- Authentication — creating test keys.
- Your First Integration — recommends test keys for CI.
- Sending Mail — the full
/v3/mail/sendrequest shape includingmail_settings.