Sandbox Mode

Sandbox Mode is a safe testing capability for the email send APIs.

Sandbox Mode is a safe testing capability for the email send APIs. When you append a sandboxMode parameter to a send request, Aurora SendCloud runs the same authentication, requestId idempotency check, and full parameter validation as a real send — and then stops before any email is delivered. No message leaves the system, no quota is consumed, and no statistics are recorded.

Sandbox Mode gives you two options. Validate mode lets you confirm that a request would be accepted before you go live. Webhook mode additionally generates simulated delivery events — delivered, opened, clicked, bounced — and pushes them to your registered WebHook URL through the same pipeline used by production events. This lets you build and test your entire callback integration, including failure paths that are difficult to trigger with real traffic.

How It Works

Submit with sandboxMode: Send a request to /api/mail/send, /api/mail/sendtemplate, or /api/mail/sendcalendar with sandboxMode=validate or sandboxMode=webhook appended.

For detailed request parameters and response formats, please refer to the API documentation for the following email-sending API:

Full Validation Runs: The request passes through the complete production chain — API_USER authentication, requestId idempotency, sender, recipients, content, attachments, labels, template, and calendar permission checks.

Delivery Is Skipped: After validation succeeds, the request is truncated. No email is sent to any recipient, no address-list task is created, and nothing enters delivery statistics or email status queries.

Events Are Simulated (webhook mode only): Aurora SendCloud generates simulated events with the same payload structure as production WebHook events and pushes them to the webhook URL configured in your account. Your parsing and signature-verification code works unchanged.

Result Is Returned: The synchronous response tells you exactly what would have happened — simulated emailIdList for your recipients, or a simulated maillistTaskId for address-list sends.

Modes

ModeParameterBehaviorTypical Use
ValidatesandboxMode=validateFull validation, no delivery, simulated IDs in responsePre-launch integration testing, recipient parsing checks
WebhooksandboxMode=webhookNo delivery, simulated WebHook events pushed to your URLWebHook integration development, failure-path testing, regression testing

Omitting sandboxMode performs a normal real send — the parameter only ever enables sandbox behavior.

Validate Mode

Validate mode returns everything a real send would return, with simulated identifiers:

curl -X POST 'https://api.aurorasendcloud.com/api/mail/send' \
  -d 'apiUser={apiUser}' \
  -d 'apiKey={apiKey}' \
  -d '[email protected]' \
  -d '[email protected];[email protected]' \
  -d 'subject=Sandbox validate test' \
  -d 'html=<p>Hello</p>' \
  -d 'sandboxMode=validate'
{
  "result": true,
  "statusCode": 200,
  "message": "Request successful",
  "info": {
    "sandbox": true,
    "sandboxMessage": "Sandbox validation successful, no email delivered",
    "recipientCount": 2,
    "size": 1024,
    "emailIdList": [
      "[email protected]",
      "[email protected]"
    ]
  }
}

With useAddressList=true, the response reports the real member count of your lists together with simulated task IDs:

{
  "result": true,
  "statusCode": 200,
  "message": "Request successful",
  "info": {
    "sandbox": true,
    "sandboxMessage": "Sandbox validation successful, no address-list task created",
    "addressListCount": 1,
    "estimatedRecipientCount": 42,
    "maillistTaskId": [-123456789]
  }
}

respEmailId=false removes emailIdList from the response, matching the behavior of real sends.

Webhook Mode

Webhook mode accepts an additional sandboxEvents parameter that selects which events to simulate:

curl -X POST 'https://api.aurorasendcloud.com/api/mail/send' \
  -d 'apiUser={apiUser}' \
  -d 'apiKey={apiKey}' \
  -d '[email protected]' \
  -d '[email protected]' \
  -d 'subject=Sandbox webhook test' \
  -d 'html=<p>Hello</p>' \
  -d 'sandboxMode=webhook' \
  -d 'sandboxEvents=request,deliver,open,click'
{
  "result": true,
  "statusCode": 200,
  "message": "Request successful",
  "info": {
    "sandbox": true,
    "sandboxMode": "webhook",
    "sandboxMessage": "Webhook sandbox events accepted, no email delivered",
    "sandboxEvents": ["request", "deliver", "open", "click"],
    "sandboxEvent": true,
    "emailIdList": ["[email protected]"]
  }
}

A successful response means the events were accepted. The actual WebHook callbacks arrive asynchronously at your registered URL, with the same payload structure, token, and signature as production events — see the WebHook reference for payload details.

Identifying Simulated Events

Every simulated event carries a marker in the userHeaders field, so your receiver can distinguish sandbox traffic from production traffic:

{
  "event": "deliver",
  "recipient": "[email protected]",
  "emailId": "[email protected]",
  "timestamp": 1780000000,
  "token": "...",
  "signature": "...",
  "userHeaders": "{\"X-Sandbox\":\"true\"}"
}

userHeaders is a JSON-encoded string. Parse it and check the X-Sandbox key — it is "true" on every sandbox event, on every event type, and production events do not include it:

import json

def is_sandbox_event(user_headers: str) -> bool:
    headers = json.loads(user_headers)
    return headers.get("X-Sandbox") == "true"

Filter or tag sandbox traffic with this check — for example, route simulated events to a test table so they never mix with production data.

Supported Events

Event CodeEvent NameEvent Value (event)Description
18RequestedrequestEmail send request event, one per request
1DelivereddeliverMessage successfully delivered to the recipient's mail server
11OpenopenRecipient opened the email
10ClickclickRecipient clicked a link in the email
12UnsubscribeunsubscribeRecipient clicked the unsubscribe link
3Spam Reportreport_spamRecipient reported the email as spam
4Invalid Email (Deprecated)invalidInvalid email address event, deprecated soon
81SuppressedsuppressedSuppressed messages due to past suppression
83Hard Bouncehard_bouncePermanent failures from invalid addresses
7Soft Bouncesoft_bounceTemporary delivery failure event

sandboxEvents accepts event names or numeric event codes, in any case, mixed freely — for example sandboxEvents=deliver,11 is equivalent to sandboxEvents=deliver,open. deliver also answers to the alias delivered, and report_spam to reported_spam. Duplicates are removed, keeping the first occurrence. If sandboxEvents is omitted, the default is request,deliver.

There is no bounce event. Bounces are split into soft_bounce (temporary) and hard_bounce (permanent); passing bounce or event code 5 returns an error.

Event Combination Rules

Simulated events follow the semantics of real delivery, so some combinations are rejected with error code 40704:

  • At most one terminal failure event per request. invalid, suppressed, and hard_bounce are terminal failure events; at most one of them may appear in a single request.
  • deliver is mutually exclusive with terminal failure events. An email either gets delivered or it fails — combining deliver with any of invalid / suppressed / hard_bounce is rejected, and the error message names every conflicting event (for example mutually exclusive sandbox events: deliver+invalid).
  • soft_bounce combines freely. A temporary failure can appear alone (retry in progress) or together with deliver (retry eventually succeeded).
  • request combines with everything.

The largest valid combination is: request,deliver,soft_bounce,open,click,unsubscribe,report_spam.

Sending with Address Lists

When useAddressList=true and sandboxMode=webhook, events are generated from the real members of your address lists:

  • The request event is one per request and carries a simulated task ID and the estimated recipient count.
  • Every other event is generated for sampled list members — subscribed members taken in join order, up to the first 1,000 across all listed lists — so callback recipients are real member addresses.
  • Unsubscribed members are never sampled.
  • If a list contains no subscribed members, there are no events to publish and the request is rejected with 40704 (no sandbox webhook events to publish).

For normal-recipient sends, each non-request event is generated once per recipient, and the total event count is capped at 100 per request (40704 sandbox events exceed maxEventsPerRequest when exceeded).

Prerequisites

Use a test API user: Sandbox Mode is available to test API users (categoryType=0). Passing sandboxMode with a regular API user returns 40704 (sandboxMode is only available for test API users).

Register a webhook URL (webhook mode): Every event you request must have a webhook URL configured for your account — either the default category or the category matching the API user. Log in to the Aurora SendCloud platform, navigate to the WebHook settings page and add the URL, or call the WebHook API:

curl -X POST 'https://api.aurorasendcloud.com/api/webhook/add' \
  -d 'apiUser={apiUser}' \
  -d 'apiKey={apiKey}' \
  -d 'event=1,3,4,7,10,11,12,18,81,83' \
  -d 'url=http://{your-server}/webhook'

The event parameter takes the numeric event codes from the table above; this example covers every sandbox-supported event. A missing URL for a requested event returns 40706 (no webhook url for sandbox event: open).

Have the feature enabled: Sandbox Mode is disabled by default. If the feature has not been enabled for your account or region, the API returns 40018 — contact Aurora SendCloud support to enable it.

Sandbox Mode Responses

All sandbox responses share the standard business envelope: result, statusCode, message, and info.

Validate mode, normal recipients:

parametertypedescription
info.sandboxbooleanalways true in sandbox responses
info.sandboxMessagestringhuman-readable sandbox outcome
info.recipientCountintnumber of resolved recipients (from to, cc, bcc, or xsmtpapi.to)
info.sizelongrequest size in bytes
info.emailIdListstring[]simulated email IDs, one per recipient; removed when respEmailId=false

Validate mode, address lists:

parametertypedescription
info.addressListCountintnumber of address lists in the request
info.estimatedRecipientCountintreal member count across the listed lists
info.maillistTaskIdlong[]simulated task IDs (negative values)

Webhook mode:

parametertypedescription
info.sandboxModestringwebhook
info.sandboxEventsstring[]resolved event names, in request order
info.sandboxEventbooleanalways true
info.emailIdListstring[]simulated email IDs, unique per recipient; present for address-list sends when the lists contain subscribed members
info.maillistTaskIdlong[]simulated task IDs (address-list sends)

Simulated emailId values follow the production format ({timestamp}_USERID_{apiUserId}_{seq}.{host}{index}${recipient}), so they are safe inputs for testing your callback parsing. They do not exist in delivery records — querying them through the email status API returns no result.

Rate Limits

Sandbox Mode requests are protected by dedicated rate limits, separate from your real sending quota. When a limit is reached the API returns 50000 (interface frequency limited). The default limits are 100 requests per minute per user and 60 per minute per API user for validate mode, with tighter limits (30 and 20) for webhook mode.

Error Codes

statusCodeOccurs whenResolution
40704sandboxMode is neither validate nor webhookFix the parameter value
40704sandboxEvents passed without sandboxMode=webhookOnly pass sandboxEvents in webhook mode
40704Unknown event name or code (including bounce / 5)Use an event from the supported-events table
40704Mutually exclusive event combinationFollow the combination rules above
40704sandboxMode used with a non-test API userSwitch to a test API user
40704Empty event list, or address list has no subscribed membersPass valid events; add subscribed members to the list
40704Event count exceeds the per-request cap (normal recipients)Reduce events or recipients
40018Sandbox Mode is not enabled for the account or regionContact Aurora SendCloud support
40706A requested event has no webhook URLRegister a webhook URL for that event
40874useAddressList is neither true nor false in webhook modeFix the parameter value
40901Event backup failed on the server; request not acceptedInfrastructure issue — retry after the fault is resolved
50000Sandbox Mode rate limit reachedSlow down, or request higher limits

All other errors — authentication, requestId, mail parameters, templates, calendars, attachments — use the same codes and messages as the base send APIs.

Best Practices

Deduplicate retried events: Event delivery is retried automatically when your server is unavailable, and retries may produce duplicate events. Deduplicate callbacks by event + emailId + timestamp + recipient.

Correlate retries with sendRequestId: Set sendRequestId (or the X-Request-ID header) on each sandbox request. The request event's emailId changes when a request is retried, so the request ID is the stable correlation key.

Prefer suppressed and hard_bounce over invalid: invalid is deprecated and will be removed. New integrations should simulate failure paths with suppressed or hard_bounce.

Test the full lifecycle in one request: Combine request, deliver, soft_bounce, open, click, unsubscribe, and report_spam in a single call to exercise your entire callback pipeline, then use single failure events (suppressed, hard_bounce) for targeted failure handling.

Expect asynchronous callbacks: A 200 response means events were accepted, with delivery to your webhook following asynchronously. Do not poll the email status API for sandbox emailIds — sandbox events do not enter delivery records or statistics.

FAQ

Does Sandbox Mode send real emails?
No. In both modes, validation runs against the exact production rules and then delivery is skipped. No message is sent to any recipient.

Do Sandbox Mode requests consume my sending quota?
No. Sandbox Mode requests have their own rate limits and do not consume sending quota or appear in delivery statistics.

Are simulated webhook events identical to production events?
Yes. They carry the same payload structure, including token and signature, so your existing parsing and signature-verification code works without changes. The only addition is the X-Sandbox marker in userHeaders — see Identifying Simulated Events.

Why is there no bounce event?
Bounces are split into soft_bounce (temporary, retryable) and hard_bounce (permanent). Passing bounce or event code 5 returns 40704.

Which endpoints support Sandbox Mode?
/api/mail/send and /api/mail/sendtemplate (POST and GET) and /api/mail/sendcalendar (POST). All other request parameters are unchanged — Sandbox Mode only adds sandboxMode and sandboxEvents.