
# Test the email provider

`POST /v1/email-provider:test` · permission `email-provider:write` · all plans

Checks the stored connection without sending a message:

- `customer_smtp`: connects to your server, sets up TLS, authenticates and quits.
- `customer_api`: calls a read-only endpoint of your provider with the stored key.

The answer is `200 OK` even when the check fails: `result` is `ok` or a fixed error code. The server's own reply text is never returned. The result is stored in `last_test_at` and `last_test_result` of [get](get.md); the `ETag` does not change. Every test writes an audit record (`email_provider.tested`).

An environment can run 10 tests per hour. The body is optional; if you send one, it must be an empty JSON object.

## Response

| Field | Type | Description |
|---|---|---|
| `result` | string | `ok` or an error code (below). |
| `tested_at` | string | Time of the test. |
| `version` | integer | The configuration version that was tested. |

```json
{
  "result": "smtp_auth_failed",
  "tested_at": "2026-10-19T09:30:00Z",
  "version": 4
}
```

Common results:

| Result | Meaning |
|---|---|
| `ok` | Connected and authenticated. |
| `smtp_auth_failed` | The SMTP server refused the user name or password. |
| `smtp_auth_unsupported` | The server offers no supported AUTH mechanism. |
| `smtp_tls_required` | The server on port 587 does not offer STARTTLS. |
| `smtp_tls_invalid` | The server certificate is not valid for the host name. |
| `smtp_temporary`, `smtp_rejected` | The server answered with a temporary or permanent error. |
| `esp_auth_failed` | The provider refused the key. |
| `esp_access_denied` | The provider refused the key or the key lacks read access to the checked endpoint (for example `ses:GetAccount`, or a Mailgun domain sending key). Sending may still work. |
| `esp_rate_limited`, `esp_temporary`, `esp_rejected` | The provider was rate limited, temporarily unavailable or refused the request. |
| `egress_dns_failed`, `egress_dns_private`, `egress_ssrf_blocked`, `egress_connect_failed`, `egress_timeout`, `egress_tls_invalid` | The host does not resolve, resolves to a private address, is blocked, could not be reached in time, or (API providers) presented an invalid certificate. |
| `delivery_credentials_invalid` | The stored credential cannot be used; save it again. |
| `delivery_mode_unavailable` | Outbound delivery is not enabled in this deployment. |

## Errors

| HTTP | code | When |
|---|---|---|
| 400 | `unknown_field` | The body is not an empty JSON object. |
| 409 | `conflict` | The mode has no connection to test (`platform_default`, `customer_webhook`, `platform_managed_domain`; test a webhook endpoint with [Test a webhook endpoint](../webhook-endpoints/test.md); check a sender domain with [verify](../email-sender-domains/verify.md)), or the configuration changed during the test. |
| 429 | `rate_limited` | The hourly test limit or the API rate limit was reached; retry after the `Retry-After` period. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry after the `Retry-After` period. |

## Example

```bash
curl -X POST https://api.eu.keenauth.com/v1/email-provider:test \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

CLI: `keenauth email-provider test`
