---
title: "Tools"
description: "Every operation in this group: what it accepts, what it returns and the errors it can answer with."
url: "https://nextmail.sh/docs/api/reference/tools"
area: "API"
category: "Reference"
---

# Tools

Every operation in this group: what it accepts, what it returns and the errors it can answer with.

## Operations

The free tools on the Nextmail website, which need no scope. Three check the public mail records of any domain: its DMARC policy, its BIMI logo, and a deliverability report across MX, SPF, DKIM, DMARC and BIMI. They read public DNS and nothing in the workspace, and every answer is what DNS said at that moment. One reads the sign-in code in a message you pass in, and one prices every plan for a usage.

### `GET /tools/dmarc`

Check a domain's DMARC policy

Reads the domain's DMARC record from public DNS, or the record of the organisational domain it inherits from, and says how strict it is and what is wrong with it. `stage` is `missing`, `invalid`, `monitor` for `p=none`, `quarantine` or `reject`.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Query parameters**

- `domain` (`string`, required, up to 320 characters): The domain to check, such as `acme.com`. An email address, a URL or a domain with a trailing dot is read as its domain. Any public domain works, not only the ones in this workspace.

**Returns**

- `200` `DmarcReport`: What the DMARC record says.

**Errors**

- `422`: `invalid_parameter` on `domain`: it does not read as a domain.
- `503`: `unreachable`: public DNS did not answer for the domain just now. Nothing about the domain was decided, so try again in a moment.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.checkDmarc()`](https://nextmail.sh/docs/sdk/reference/tools#checkDmarc); Python [`tools.check_dmarc()`](https://nextmail.sh/docs/python/reference/tools#checkDmarc); Ruby [`tools.check_dmarc`](https://nextmail.sh/docs/ruby/reference/tools#checkDmarc); PHP [`tools->checkDmarc`](https://nextmail.sh/docs/php/reference/tools#checkDmarc); Go [`Tools.CheckDmarc`](https://nextmail.sh/docs/go/reference/tools#checkDmarc); Java [`tools().checkDmarc`](https://nextmail.sh/docs/java/reference/tools#checkDmarc); C# [`Tools.CheckDmarcAsync`](https://nextmail.sh/docs/csharp/reference/tools#checkDmarc); CLI [`nextmail tools check-dmarc`](https://nextmail.sh/docs/cli/reference/tools#tools-check-dmarc); MCP [`checkDmarc`](https://nextmail.sh/docs/mcp/tools/domain-checks#checkDmarc).

### `GET /tools/bimi`

Check a domain's BIMI logo

Reads the domain's BIMI record, fetches the logo it names and checks the DMARC policy beside it, since inboxes draw a logo only at `p=quarantine` or `p=reject`. `status` is `present`, `partial` when the record is there but something stops inboxes showing it, `absent` or `invalid`, and `issues` says why.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Query parameters**

- `domain` (`string`, required, up to 320 characters): The domain to check, such as `acme.com`. An email address, a URL or a domain with a trailing dot is read as its domain. Any public domain works, not only the ones in this workspace.

**Returns**

- `200` `BimiReport`: What the BIMI record says and whether inboxes can draw the logo.

**Errors**

- `422`: `invalid_parameter` on `domain`: it does not read as a domain.
- `503`: `unreachable`: public DNS did not answer for the domain just now. Nothing about the domain was decided, so try again in a moment.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.checkBimi()`](https://nextmail.sh/docs/sdk/reference/tools#checkBimi); Python [`tools.check_bimi()`](https://nextmail.sh/docs/python/reference/tools#checkBimi); Ruby [`tools.check_bimi`](https://nextmail.sh/docs/ruby/reference/tools#checkBimi); PHP [`tools->checkBimi`](https://nextmail.sh/docs/php/reference/tools#checkBimi); Go [`Tools.CheckBimi`](https://nextmail.sh/docs/go/reference/tools#checkBimi); Java [`tools().checkBimi`](https://nextmail.sh/docs/java/reference/tools#checkBimi); C# [`Tools.CheckBimiAsync`](https://nextmail.sh/docs/csharp/reference/tools#checkBimi); CLI [`nextmail tools check-bimi`](https://nextmail.sh/docs/cli/reference/tools#tools-check-bimi); MCP [`checkBimi`](https://nextmail.sh/docs/mcp/tools/domain-checks#checkBimi).

### `GET /tools/deliverability`

Check a domain's deliverability

Checks the records a receiving mailbox reads before it trusts mail from the domain: MX, SPF, DKIM at the selectors its mail provider uses, DMARC and BIMI. Each check says `pass`, `warn`, `fail` or `absent` with a verdict and notes written to be shown to a person, and `score` weighs them into 0 to 100, graded A to F.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Query parameters**

- `domain` (`string`, required, up to 320 characters): The domain to check, such as `acme.com`. An email address, a URL or a domain with a trailing dot is read as its domain. Any public domain works, not only the ones in this workspace.

**Returns**

- `200` `DeliverabilityReport`: Each check, the score and the grade.

**Errors**

- `422`: `invalid_parameter` on `domain`: it does not read as a domain.
- `503`: `unreachable`: public DNS did not answer for the domain just now. Nothing about the domain was decided, so try again in a moment.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.checkDeliverability()`](https://nextmail.sh/docs/sdk/reference/tools#checkDeliverability); Python [`tools.check_deliverability()`](https://nextmail.sh/docs/python/reference/tools#checkDeliverability); Ruby [`tools.check_deliverability`](https://nextmail.sh/docs/ruby/reference/tools#checkDeliverability); PHP [`tools->checkDeliverability`](https://nextmail.sh/docs/php/reference/tools#checkDeliverability); Go [`Tools.CheckDeliverability`](https://nextmail.sh/docs/go/reference/tools#checkDeliverability); Java [`tools().checkDeliverability`](https://nextmail.sh/docs/java/reference/tools#checkDeliverability); C# [`Tools.CheckDeliverabilityAsync`](https://nextmail.sh/docs/csharp/reference/tools#checkDeliverability); CLI [`nextmail tools check-deliverability`](https://nextmail.sh/docs/cli/reference/tools#tools-check-deliverability); MCP [`checkDeliverability`](https://nextmail.sh/docs/mcp/tools/domain-checks#checkDeliverability).

### `POST /tools/verification-code`

Read the sign-in code in a message

Finds the sign-in or verification code in a message you pass in, with the reader that puts a code at the top of a message in Nextmail. Send the message as `raw` (the whole MIME source) or as `subject` with `html` or `text`.

It answers only when it is sure. The message has to hold exactly one code worded as one, such as a verification code, a one-time code or a security code, in any of the common languages. Two different codes, or a number that could be an order, a booking, a meeting, a phone number or a promotion, give `code: null`. The code comes back as you would type it: digits only, or capital letters and digits, without spaces or dashes.

It reads only what you send, so it cannot tell whether the sender is who it claims to be. The `verificationCode` on a message in your mailbox also requires the sender to pass authentication. Nothing is stored, and no model is called.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Request body**

- `subject` (`string`, up to 998 characters): Subject line, at most 998 characters.
- `html` (`string`, up to 1000000 characters): HTML body. Links are left out before the code is looked for.
- `text` (`string`, up to 1000000 characters): Plain text body, used when there is no `html`.
- `raw` (`string`, up to 5000000 characters): The whole message as MIME source, as it was received. Wins over the other fields when it is set.

**Returns**

- `200` `VerificationCodeResult`: The code, or null when the reader is not sure.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.readVerificationCode()`](https://nextmail.sh/docs/sdk/reference/tools#readVerificationCode); Python [`tools.read_verification_code()`](https://nextmail.sh/docs/python/reference/tools#readVerificationCode); Ruby [`tools.read_verification_code`](https://nextmail.sh/docs/ruby/reference/tools#readVerificationCode); PHP [`tools->readVerificationCode`](https://nextmail.sh/docs/php/reference/tools#readVerificationCode); Go [`Tools.ReadVerificationCode`](https://nextmail.sh/docs/go/reference/tools#readVerificationCode); Java [`tools().readVerificationCode`](https://nextmail.sh/docs/java/reference/tools#readVerificationCode); C# [`Tools.ReadVerificationCodeAsync`](https://nextmail.sh/docs/csharp/reference/tools#readVerificationCode); CLI [`nextmail tools read-verification-code`](https://nextmail.sh/docs/cli/reference/tools#tools-read-verification-code).

### `GET /tools/address`

Check an email address

Says whether an address is worth sending to: `valid`, `risky`, `invalid` or `unknown`, with the reasons. It checks the syntax, whether the domain takes mail at all, whether it is a throwaway domain or a role address such as `info@`, and offers a correction for a likely typo such as `gmial.com`. With the `emails:read` scope it also says what this workspace knows: whether it suppressed the address and when it last delivered to it or saw it bounce. It never shows another workspace's history.

`deep` also asks whether the mailbox exists. A deep check is billed per address through pay as you go, $1.50 per 100 addresses on every plan, needs the `emails:send` scope, and is refused when pay as you go is off. Without it the check is free and `checks.mailbox` is null.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Query parameters**

- `email` (`string`, 1 to 320 characters): The address to check.
- `deep` (`boolean`, default `false`): Also ask whether the mailbox exists. Billed per address. Defaults to false.

**Returns**

- `200` `AddressCheck`: What the check found.

**Errors**

- `409`: `deep_check_unavailable` or `deep_check_limit_reached`: a deep check needs pay as you go, and has to fit under its monthly limit.
- `503`: `deep_check_unavailable`: the mailbox check did not answer. Nothing was billed.
- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.checkAddress()`](https://nextmail.sh/docs/sdk/reference/tools#checkAddress); Python [`tools.check_address()`](https://nextmail.sh/docs/python/reference/tools#checkAddress); Ruby [`tools.check_address`](https://nextmail.sh/docs/ruby/reference/tools#checkAddress); PHP [`tools->checkAddress`](https://nextmail.sh/docs/php/reference/tools#checkAddress); Go [`Tools.CheckAddress`](https://nextmail.sh/docs/go/reference/tools#checkAddress); Java [`tools().checkAddress`](https://nextmail.sh/docs/java/reference/tools#checkAddress); C# [`Tools.CheckAddressAsync`](https://nextmail.sh/docs/csharp/reference/tools#checkAddress); CLI [`nextmail tools check-address`](https://nextmail.sh/docs/cli/reference/tools#tools-check-address); MCP [`checkAddress`](https://nextmail.sh/docs/mcp/tools/domain-checks#checkAddress).

### `POST /tools/addresses`

Check several email addresses

Checks up to 100 addresses in one call, each as `GET /tools/address` does, and returns them in the order they were sent. `deep` applies to every address and is billed for each one that reaches the mailbox check.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Request body**

- `emails` (`string[]`, required, 1 to 100 items): The addresses to check, from 1 to 100.
- `deep` (`boolean`, default `false`): Also ask whether each mailbox exists. Billed per address through pay as you go. Defaults to false.

**Returns**

- `200` `AddressCheckList`: One check per address, in order.

**Errors**

- `409`: `deep_check_unavailable` or `deep_check_limit_reached`: a deep check needs pay as you go, and has to fit under its monthly limit.
- `503`: `deep_check_unavailable`: the mailbox check did not answer. Nothing was billed.
- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.checkAddresses()`](https://nextmail.sh/docs/sdk/reference/tools#checkAddresses); Python [`tools.check_addresses()`](https://nextmail.sh/docs/python/reference/tools#checkAddresses); Ruby [`tools.check_addresses`](https://nextmail.sh/docs/ruby/reference/tools#checkAddresses); PHP [`tools->checkAddresses`](https://nextmail.sh/docs/php/reference/tools#checkAddresses); Go [`Tools.CheckAddresses`](https://nextmail.sh/docs/go/reference/tools#checkAddresses); Java [`tools().checkAddresses`](https://nextmail.sh/docs/java/reference/tools#checkAddresses); C# [`Tools.CheckAddressesAsync`](https://nextmail.sh/docs/csharp/reference/tools#checkAddresses); CLI [`nextmail tools check-addresses`](https://nextmail.sh/docs/cli/reference/tools#tools-check-addresses).

### `GET /tools/cost`

Estimate what Nextmail costs for a usage

Prices every plan for the usage you describe, as the cost calculator on the Nextmail website does: the plan itself, the extra sends and AI actions it would bill, the monthly total, and whether the plan fits at all. A plan does not fit when the usage needs more domains than it includes, more than one person without team access, or more sends than it allows without billing extra. `cheapest` names the cheapest plan that fits.

Amounts are in US cents per month. With `interval` set to `year`, the plan price is the monthly equivalent of paying yearly.

Needs no scope: any key or access token for the workspace may run it.

- Needs an API key or an OAuth access token, and no scope.

**Query parameters**

- `sends` (`integer`, at least 0, at most 1000000000): Emails sent in a month. Defaults to 0.
- `domains` (`integer`, at least 0, at most 1000000): Domains you send from. Defaults to 1.
- `people` (`integer`, at least 1, at most 1000000): People who use the workspace. Defaults to 1.
- `aiActions` (`integer`, at least 0, at most 10000000): AI actions in a day, such as drafts, rewrites and summaries. Defaults to 0.
- `interval` (`string`, one of `"month"`, `"year"`): How you pay: `month` or `year`. Defaults to `month`.

**Returns**

- `200` `CostEstimate`: Every plan priced for the usage, and the cheapest one that fits.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.tools.estimateCost()`](https://nextmail.sh/docs/sdk/reference/tools#estimateCost); Python [`tools.estimate_cost()`](https://nextmail.sh/docs/python/reference/tools#estimateCost); Ruby [`tools.estimate_cost`](https://nextmail.sh/docs/ruby/reference/tools#estimateCost); PHP [`tools->estimateCost`](https://nextmail.sh/docs/php/reference/tools#estimateCost); Go [`Tools.EstimateCost`](https://nextmail.sh/docs/go/reference/tools#estimateCost); Java [`tools().estimateCost`](https://nextmail.sh/docs/java/reference/tools#estimateCost); C# [`Tools.EstimateCostAsync`](https://nextmail.sh/docs/csharp/reference/tools#estimateCost); CLI [`nextmail tools estimate-cost`](https://nextmail.sh/docs/cli/reference/tools#tools-estimate-cost).

### Objects

#### `AddressCheck`

`object`

- `object` (`string`, required, one of `"address_check"`)
- `email` (`string`, required): The address as it was sent.
- `normalized` (`string`, required, nullable): The address lower-cased, with an international domain in its ASCII form. Null when the syntax is wrong.
- `result` (`string`, required, one of `"valid"`, `"risky"`, `"invalid"`, `"unknown"`): `valid` is safe to send to, `risky` may bounce or annoy, `invalid` will not be delivered, and `unknown` means DNS did not answer.
- `reasons` (`string[]`, required, one of `"invalid_syntax"`, `"domain_not_found"`, `"no_mail_server"`, `"null_mx"`, `"no_mx_record"`, `"dns_unreachable"`, `"disposable"`, `"role_address"`, `"typo_suspected"`, `"suppressed"`, `"bounced_before"`, `"mailbox_not_found"`, `"mailbox_uncertain"`, `"random_input"`): Why the result is not `valid`. Empty for a valid address.
- `suggestion` (`string`, required, nullable): The address with a likely typo in its domain corrected, or null.
- `checks` (`object`, required)
  - `syntax` (`boolean`, required)
  - `mx` (`object`, required)
    - `status` (`string`, required, one of `"found"`, `"implicit"`, `"missing"`, `"null_mx"`, `"domain_not_found"`, `"unknown"`): `found` has mail servers, `implicit` has none but the domain itself answers, `missing`, `null_mx` and `domain_not_found` take no mail, and `unknown` means DNS did not answer.
    - `hosts` (`string[]`, required)
  - `nullMx` (`boolean`, required): The domain says it takes no mail.
  - `disposable` (`boolean`, required): A throwaway mailbox domain.
  - `role` (`boolean`, required): A shared address such as `info@` or `support@`.
  - `freeProvider` (`boolean`, required): A public mailbox provider such as Gmail.
  - `mailbox` (`object`, required, nullable): Only with `deep`: how sure the mailbox check is. Null otherwise.
    - `exists` (`string`, required, one of `"high"`, `"medium"`, `"low"`)
    - `valid` (`string`, required, one of `"high"`, `"medium"`, `"low"`)
    - `randomInput` (`string`, required, one of `"high"`, `"medium"`, `"low"`)
- `workspace` (`object`, required, nullable): What this workspace knows about the address. Null without the `emails:read` scope.
  - `suppressed` (`boolean`, required)
  - `lastBouncedAt` (`string`, required, nullable, format `date-time`)
  - `lastDeliveredAt` (`string`, required, nullable, format `date-time`)
- `checkedAt` (`string`, required, format `date-time`)

#### `AddressCheckList`

`object`

- `object` (`string`, required, one of `"list"`)
- `data` (`AddressCheck[]`, required)

#### `BimiReport`

`object`

- `object` (`string`, required, one of `"bimi_report"`)
- `domain` (`string`, required)
- `record` (`string`, required, nullable): The BIMI record at `default._bimi`, or null.
- `version` (`string`, nullable)
- `logoUrl` (`string`, nullable): The `l=` of the record: where the SVG logo is served.
- `authorityUrl` (`string`, nullable): The `a=` of the record: where the mark certificate is served, or null without one.
- `logoSvg` (`string`, nullable): The logo as it was fetched, when it could be, to show it.
- `logoReachable` (`boolean`)
- `dmarcPolicy` (`string`, nullable): The `p=` of the DMARC record beside it.
- `dmarcEnforced` (`boolean`): Whether that policy is `quarantine` or `reject`, the only ones under which a logo is drawn.
- `status` (`string`, required, one of `"present"`, `"partial"`, `"absent"`, `"invalid"`)
- `issues` (`string[]`, required)

#### `CostEstimate`

`object`

- `object` (`string`, required, one of `"cost_estimate"`)
- `interval` (`string`, required, one of `"month"`, `"year"`)
- `need` (`object`, required): The usage that was priced, with the defaults filled in.
  - `sends` (`integer`, required)
  - `domains` (`integer`, required)
  - `people` (`integer`, required)
  - `aiActions` (`integer`, required)
- `plans` (`PlanEstimate[]`, required)
- `cheapest` (`string`, required, nullable): The id of the cheapest plan that fits, or null when none does.

#### `DeliverabilityCheck`

`object`

- `id` (`string`, required, one of `"mx"`, `"spf"`, `"dkim"`, `"dmarc"`, `"bimi"`)
- `label` (`string`, required)
- `status` (`string`, required, one of `"pass"`, `"warn"`, `"fail"`, `"absent"`)
- `verdict` (`string`, required): One line saying what was found.
- `record` (`string`, required, nullable): The record that was read, when there is one.
- `notes` (`string[]`, required)

#### `DeliverabilityReport`

`object`

- `object` (`string`, required, one of `"deliverability_report"`)
- `domain` (`string`, required)
- `score` (`integer`, required, at least 0, at most 100)
- `grade` (`string`, required, one of `"A"`, `"B"`, `"C"`, `"D"`, `"F"`)
- `provider` (`string`, required, nullable): The mail provider its MX records point at, such as `Google Workspace`, when it is known.
- `checks` (`DeliverabilityCheck[]`, required)

#### `DmarcReport`

`object`

- `object` (`string`, required, one of `"dmarc_report"`)
- `domain` (`string`, required): The domain that was checked, lower-cased.
- `record` (`string`, required, nullable): The DMARC record as published, or null when there is none.
- `inheritedFrom` (`string`, required, nullable): The parent domain whose record applies, when the domain has none of its own. Null when the record is its own or there is none.
- `tags` (`Record<string, string>`, required): Every tag of the record, such as `p`, `sp`, `pct` and `rua`, as written.
- `stage` (`string`, required, one of `"missing"`, `"invalid"`, `"monitor"`, `"quarantine"`, `"reject"`)
- `issues` (`string[]`, required): Problems found, each written to be shown to a person. Empty when there are none.

#### `PlanEstimate`

`object`

- `object` (`string`, required, one of `"plan_estimate"`)
- `plan` (`string`, required, one of `"free"`, `"starter"`, `"business"`, `"enterprise"`)
- `name` (`string`, required): The plan as it is named on the pricing page.
- `fits` (`boolean`, required): Whether the plan can carry the usage at all. False when `blockers` names anything.
- `blockers` (`string[]`, required, one of `"domains"`, `"people"`, `"sends"`): What the plan cannot carry: `domains` beyond the ones it includes, `people` without team access, or `sends` beyond its limit on a plan that bills no extra sends.
- `baseCents` (`integer`, required): The plan price per month, or its monthly equivalent when paid yearly.
- `extraSends` (`integer`, required): Sends beyond what the plan includes in a month.
- `sendsCents` (`integer`, required): What those extra sends cost in a month.
- `extraAiActions` (`integer`, required): AI actions beyond what the plan includes, over a 30-day month.
- `aiCents` (`integer`, required): What those extra AI actions cost in a month.
- `extrasCents` (`integer`, required): `sendsCents` and `aiCents` together.
- `totalCents` (`integer`, required): The plan price and the extras: what a month costs.

#### `VerificationCodeResult`

`object`

- `object` (`string`, required, one of `"verification_code"`)
- `code` (`string`, required, nullable): The code as you would type it, or null when the message holds no code the reader is sure of.
