Send a test email
POST /v1/email-templates/{family}/{locale}:test-send · permission email-templates:write · Startup plan and above
Renders one version of an email template with the same sample data as preview and sends it to one address through the normal delivery path, so you can check it in a real inbox. The subject starts with [TEST] . The template is validated again before it is sent.
Rules:
- The recipient must be a verified email address of an
activemember of your dashboard account. Any other address is refused, and the address is never repeated in the response or in logs. - Each environment can send at most 20 test emails per UTC day. The 21st is refused with
429until the next UTC day (Retry-Aftergives the wait in seconds). - The suppression list still applies. If the recipient is suppressed, the message is recorded with state
suppressed, is not delivered and still counts toward the daily limit. - The environment must send custom templates: a test send is refused when the delivery mode is
platform_defaultor sending is restricted or suspended. - Each accepted test send is written to the management audit log as
email_template.test_sent, with the family, locale and version but not the recipient.
Path parameters
| Parameter | Description |
|---|---|
family |
Email family, for example verify_email or email_otp (see List email templates). |
locale |
Locale tag, for example en or de. |
Headers
| Header | Description |
|---|---|
Idempotency-Key |
Optional, 16 to 64 characters of A-Z a-z 0-9 _ -. Repeating a request with the same key returns the first message and does not send or count it again. The SDKs and the CLI set it for you. |
Request
| Field | Type | Description |
|---|---|---|
to |
string | Required. The recipient: a verified address of an active dashboard member, without a display name. Letter case and surrounding spaces are ignored. |
version |
integer | The saved version to send (1 or more). Default: the newest version. |
published |
boolean | true sends the published version. Cannot be combined with version. |
Response
200 OK
{
"message_id": "0199f3c4-5d6e-7a8b-9c0d-1e2f3a4b5c6d",
"state": "queued",
"version": 3,
"accepted_at": "2026-10-19T09:00:00Z"
}
| Field | Description |
|---|---|
message_id |
The message's identifier. |
state |
queued (it will be sent shortly) or suppressed (the recipient is on the suppression list). A repeated request returns the first message's current state, which can also be sent, failed or expired. |
version |
The version that was sent. |
accepted_at |
When the message was accepted. |
Errors
| HTTP | code | When |
|---|---|---|
| 400 | unknown_field |
The body has an unknown field or is not a JSON object. |
| 400 | malformed_request |
The body is not valid JSON, or Idempotency-Key is malformed or repeated. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. |
| 403 | plan_feature_unavailable |
The environment's plan does not include custom email templates (Startup and above; required_plan says which). |
| 404 | not_found |
The family or locale is unknown, the version does not exist, or published is set and nothing is published. |
| 409 | email_template_not_deliverable |
The environment's delivery mode or sending state does not send custom templates. |
| 422 | validation_failed |
to is missing or is not a plain email address, version is below 1, both version and published were sent (conflicts_with_published), or the version no longer passes validation. |
| 422 | template_forbidden_construct |
The version uses a Liquid construct outside the sandbox. |
| 422 | test_recipient_not_allowed |
The recipient is not a verified address of an active dashboard member. |
| 429 | rate_limited |
The environment already sent 20 test emails this UTC day, or the API rate limit was exceeded; retry after the Retry-After period. |
| 503 | test_recipient_source_unavailable |
The recipient cannot be checked right now; nothing was sent. Retry after the Retry-After period. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry after the Retry-After period. |
Example
curl -X POST https://api.eu.keenauth.com/v1/email-templates/verify_email/en:test-send \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: test-send-verify-email-en-0001" \
-d '{"to":"you@example.com","version":3}'
CLI: keenauth email-templates test-send verify_email en --to you@example.com --version 3
Personal data
This endpoint carries personal data: dashboard users and account contacts. Personal data in the KeenAuth APIs describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.