# Free tools (API and MCP)

> Verify an email address, check any domain's SPF, DKIM and DMARC and explain SMTP errors through the Couryo API, without a key and at no cost, and through the public MCP server without login.

Source: https://couryo.com/en/docs/tools

Three Couryo tools are open to anyone, with or without an account: verify an email address, check a domain's email setup and explain an SMTP error in plain words. They are also on the site, under [Tools](https://couryo.com/en/tools), and on the MCP.

None of them sends email or opens an SMTP connection to anyone's server: only DNS lookups and rules. Verified addresses are not stored.

## Limits

Without a key, the limit is per IP, per day. With any Couryo key (`Authorization: Bearer ck_...`, a free account's included), the limit belongs to the account and is much higher.

| Tool | Without a key (per IP) | With a key (per account) |
|---|---|---|
| `GET /v1/tools/verify-email` | 50 a day | 2,000 a day |
| `GET /v1/tools/check-domain` | 20 a day | 300 a day |
| `POST /v1/tools/explain-smtp` | 50 a day | 2,000 a day |

Answers carry `RateLimit-Limit` and `RateLimit-Remaining`. Above the limit the answer is `429` with the code [`tool_limit_reached`](https://couryo.com/en/docs/errors.md#tool_limit_reached) and a `Retry-After` header. The calls accept CORS from any origin, so they work straight from the browser.

## Verify an email

```bash
curl "https://api.couryo.com/v1/tools/verify-email?email=ana@hotmail.con"
```

```json
{
  "email": "ana@hotmail.con",
  "verdict": "invalid",
  "reason": "typo",
  "did_you_mean": "ana@hotmail.com",
  "checks": {
    "syntax": true,
    "domain": "hotmail.con",
    "receives_email": "no",
    "disposable": false,
    "role": false,
    "free_provider": false
  },
  "mailbox_checked": false,
  "message": "This looks like a typo. Did you mean ana@hotmail.com?"
}
```

| Field | What it is |
|---|---|
| `verdict` | `valid` (right format and the domain receives email), `risky` (likely typo, temporary inbox or no DNS answer) or `invalid` (wrong format, the domain does not receive email or a sure typo of a big provider, such as `gmail.com.br`) |
| `reason` | the main reason: `ok`, `bad_syntax`, `no_mail_server`, `typo`, `disposable`, `role` or `dns_unavailable` |
| `did_you_mean` | the fixed address when the domain looks like a typo of a big provider (`gmial.com`, `hotmail.con`, `gmail.co`) |
| `checks.receives_email` | `yes` when the domain has an MX (or an address record without MX, as RFC 5321 says), `no` when it has none or publishes a null MX, `unknown` when DNS did not answer |
| `checks.disposable` | temporary inbox service |
| `checks.role` | shared mailbox, such as `info@` or `sales@` |
| `checks.free_provider` | Gmail, Outlook, Yahoo, iCloud and other free providers |
| `mailbox_checked` | always `false`: the mailbox itself is never probed |

Use it in your app's sign-up to catch the typo before sending the confirmation. An `invalid` address would surely bounce; a `risky` one deserves a "did you mean...?" on screen.

## Check a domain

```bash
curl "https://api.couryo.com/v1/tools/check-domain?domain=example.com"
```

It takes a domain, a URL or an address (only the domain is used). The optional `dkim_selector` looks up one DKIM selector besides the common ones (it is the `s=` of the `DKIM-Signature` header).

| Field | What it is |
|---|---|
| `score` and `grade` | 0 to 100 and A to F; SPF, DKIM and DMARC weigh 25 each, MX 15 and MTA-STS, TLS-RPT and BIMI the rest |
| `summary` | a one-sentence summary |
| `mail_provider` | who receives the domain's email, from the MX (Google Workspace, Microsoft 365...) |
| `spf_lookups` | how many DNS lookups the SPF needs (the limit is 10) |
| `dkim_selectors_found` | the selectors where a DKIM key was found |
| `checks[]` | one item per check (`mx`, `spf`, `dkim`, `dmarc`, `mta_sts`, `tls_rpt`, `bimi`), with `status` (`ok`, `warning`, `error`, `missing` or `info`), `title`, `detail`, `records` (what DNS answered), `fix` and `suggested_record`, a record ready to copy when there is one |

The answer is cached for 10 minutes: after fixing your DNS, wait a little before checking again.

## Explain an SMTP error

```bash
curl -X POST https://api.couryo.com/v1/tools/explain-smtp \
  -H "Content-Type: application/json" \
  -H "Accept-Language: en" \
  -d '{ "message": "550 5.7.515 Access denied, sending domain does not meet the required authentication level" }'
```

| Field | What it is |
|---|---|
| `code` and `enhanced_code` | the basic code (`550`) and the enhanced one (`5.7.515`); in an expired message, the reason inside wins (for example `452 4.2.2`, mailbox full) |
| `kind` | `hard` (the address does not work), `soft` (temporary), `policy` (a provider rule, not the address) or `unknown` (no code in the text) |
| `provider` | the provider named in the text, when there is one |
| `explanation` and `next_step` | what happened and what to do, in English or Portuguese following `Accept-Language` |
| `retry` | whether sending again later can work without changing anything |

## On the MCP

The same tools, plus the SPF and DMARC generators, live in two places:

- **Public server, no login:** `https://mcp.couryo.com/tools`. Any agent can use it, with the per-IP limit. Claude Code: `claude mcp add --transport http couryo-tools https://mcp.couryo.com/tools`.
- **Main server** (`https://mcp.couryo.com`, with OAuth or a key): available to every account, the free one included, with the account limit.

| Tool | What it does |
|---|---|
| `verify_email` | verifies an address |
| `check_domain_dns` | checks a domain's SPF, DKIM, DMARC, MX, MTA-STS, TLS-RPT and BIMI |
| `explain_smtp_error` | explains an error or bounce |
| `generate_spf` | builds an SPF record |
| `generate_dmarc` | builds a DMARC record |

See also [MCP and agents](https://couryo.com/en/docs/mcp.md) and the [SPF, DKIM and DMARC](https://couryo.com/en/guides/spf-dkim-dmarc.md) guide.
