Test mode
Test mode validates the send and simulates its outcome without delivering it to a mail server. It does not consume sending quota or affect your sending reputation.
There are two ways in, and they compose.
Test keys
A key created in the test environment is prefixed tix_test_ and can never send real
mail. Use it in CI, in local development, and anywhere you would rather not hand out a
credential that can reach your customers.
Authorization: Bearer tix_test_...
For email sending and reads:
- Sends are simulated. No message leaves the platform.
- Nothing counts against your daily or monthly send allowance.
- Email reads are separated by environment. Listing returns test messages; fetching a live message with a test key returns
not_found, so a leaked test key cannot read production mail. - It can only create further test keys. Asking for a live key returns
test_mode_restricted. - It has its own rate-limit allowance, so a load test cannot starve production.
This isolation applies to email records, not a separate copy of every workspace resource. Domains, templates and other management resources remain scoped to the workspace. Inbound mail and broadcast send/test operations require a live key.
Sending validation still applies. An unverified sending domain still fails, a malformed
from still fails, an oversized attachment still fails. That is the point: test mode is
useful precisely because it does not skip validation.
Sandbox addresses
Recipients at epostix.dev select a simulated outcome with the local part. If any to,
cc or bcc address is a sandbox recipient, the whole send is simulated, including its
other recipients. Keep sandbox recipients separate from live sends.
| Recipient | What happens |
|---|---|
delivered@epostix.dev | Accepted and delivered |
bounced@epostix.dev | Rejected as a hard bounce |
complained@epostix.dev | Delivered, then marked as spam |
suppressed@epostix.dev | Blocked before sending |
delayed@epostix.dev | Deferred, then delivered |
Each accepts a +label suffix, so delivered+order-1234@epostix.dev and
delivered+order-1235@epostix.dev are distinct messages. Use labels in loops: without them
you will trip duplicate detection on the eleventh identical
send inside a minute.
Any other local part at that domain is rejected with a
validation_error listing the ones that work, rather than
quietly defaulting to delivered.
Sandbox addresses work with live keys too. A live key sending to
bounced@epostix.dev produces a simulated bounce: no delivery, no quota, no effect on
reputation, and no suppression written to your account. That is how you exercise your bounce
handling against your real production credentials.
Webhooks fire either way
Simulated sends emit delivery events using the same envelope as live sends. Do not rely on
webhook arrival order: delivery retries can change it. bounced@epostix.dev produces email.sent and then email.bounced, and your
handler can exercise its bounce path without sending real mail.
This is the reason to use sandbox addresses rather than mocking our API: you are testing your own webhook handler against real deliveries of real payloads.
Telling them apart afterwards
Every message carries a mode field, either live or test, so a simulated send is
identifiable long after it was made.
{
"id": "...",
"mode": "test",
"status": "delivered"
}
What test mode does not cover
SMTP submission is always live. SMTP credentials have no test variant, so a message sent
through smtp.epostix.com is a real send whatever else you have configured. Use the API when
you want a simulated send.