Integrate email verification
in under 10 minutes
JSON REST API. Bearer token authentication. Latency <200 ms. 100% Verification run in France, GDPR compliant.
Base URL
https://api.mailcheck.fr/v1All requests are over HTTPS. Insecure HTTP calls are rejected with a 400 code.
Authentication
All requests require a Bearer token in the Authorization header.
Your API key is available in the dashboard, under Settings > API Key.
Authorization: Bearer mc_live_xxxxxxxxxxxxxxxxxxxx MAILCHECK_API_KEY).
POST /v1/verify, verifying an address
Verifies a single email address. Returns the status, the score and the verification details.
Request
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The email address to verify |
options.catch_all | boolean | No | Enables catch-all detection (default: true) |
{
"email": "[email protected]",
"options": {
"catch_all": true
}
} Response format
The response is a JSON object with the following fields:
| Field | Type | Description |
|---|---|---|
email | string | The verified address (normalized to lowercase) |
status | string | valid / invalid / risky / catch_all / disqualifie |
score | integer | Confidence score 0–100 (≥80 = reliable) |
checks.syntax | boolean | Valid RFC 5322 syntax |
checks.dns | boolean | Domain resolved in DNS |
checks.mx | boolean | MX records present and active |
checks.smtp | boolean | Mailbox confirmed via SMTP |
checks.disposable | boolean | Disposable address detected |
checks.catch_all | boolean | Catch-all (wildcard) server detected |
confidence | string | high / medium / low |
{
"email": "[email protected]",
"status": "valid",
"score": 97,
"checks": {
"syntax": true,
"dns": true,
"mx": true,
"smtp": true,
"disposable": false,
"catch_all": false
},
"confidence": "high"
} Returned statuses
| Status | Meaning | Recommended action |
|---|---|---|
| valid | Mailbox confirmed via SMTP, active domain, not disposable | Include in your sends |
| risky | Valid syntax and DNS but ambiguous SMTP or catch-all detected | Send with caution or segment separately |
| catch_all | Server accepts all incoming email (wildcard) | Decide based on your risk tolerance |
| invalid | Nonexistent mailbox confirmed by the server, invalid domain or incorrect syntax | Remove from the list immediately |
| disqualifie | Disposable address (domain in our blocklist) | Remove, never any purchase intent |
cURL example
# Verify an email address
curl -X POST https://api.mailcheck.fr/v1/verify \
-H "Authorization: Bearer mc_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","options":{"catch_all":true}}' Python example
import os
import requests
API_KEY = os.environ["MAILCHECK_API_KEY"]
def verify_email(email: str) -> dict:
response = requests.post(
"https://api.mailcheck.fr/v1/verify",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"email": email,
"options": {"catch_all": True}
},
timeout=5
)
response.raise_for_status()
return response.json()
# Usage example
result = verify_email("[email protected]")
if result["status"] == "valid":
print(f"✓ Valid email · Score: {result['score']}")
else:
print(f"✗ Status: {result['status']}") Node.js example
const API_KEY = process.env.MAILCHECK_API_KEY;
async function verifyEmail(email) {
const res = await fetch("https://api.mailcheck.fr/v1/verify", {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
email,
options: { catch_all: true }
})
});
if (!res.ok) {
throw new Error(`API error: ${res.status}`);
}
return res.json();
}
// Usage example
verifyEmail("[email protected]")
.then(data => {
console.log(`Status: ${data.status} · Score: ${data.score}`);
})
.catch(console.error); Rate limits
Limits apply per API key over a sliding window of 1 second.
| Plan | Requests / second | Verifications / month |
|---|---|---|
| Starter | 10 req/s | 5,000 |
| Growth | 50 req/s | 50,000 |
| Pro | 200 req/s | 200,000 |
| Agency | 200 req/s | 1,000,000 |
When exceeded, the API returns a 429 Too Many Requests with a
Retry-After header indicating the wait time in seconds.
MCP connector, plug your data into Claude
The MCP connector gives Claude read access to your open tracking data. You ask in plain language, Claude queries mailcheck and answers. No key to paste into a configuration file, authorisation goes through OAuth.
https://mcp.mailcheck.frAvailable on accounts with an active subscription, any plan, including the Tracking plan at 9 EUR per month.
Setup, three steps
In Claude, open settings then Connectors, click Add connector and paste the URL above. You are redirected to mailcheck to authorise access, then sent back to Claude.
The five tools
| Tool | What it returns |
|---|---|
list_tracked_emails | Your tracked emails, newest first. Filters on recipient, provider, opened or not, date |
get_email_opens | Every open of a given email, with timestamps |
find_unopened | Emails never opened, and the deduplicated list of recipients worth a follow-up |
recipient_engagement | A recipient profile, open rate and average time to first open |
tracking_stats | Aggregated stats over a period, sent, opened, rate, average delay |
Questions you can ask
- Who has not opened my emails this week?
- How many times did this client open my proposal?
- What is my average time between sending and the first open?
- Which recipients came back to a message more than once?
What the connector does not do
Access is read only. The connector cannot send an email, change your data, or read the body of your messages. It exposes the subject, recipient, sender and open timestamps, nothing else. Every tool is scoped to your own account.
Open tracking via API, for a custom SMTP server
The Chrome extension covers Gmail and Zoho Mail automatically. If you send from your own SMTP server, you get the same open tracking with two calls: one to register the email, one invisible pixel in the message body. Opens then show up in your dashboard and in the MCP connector, exactly like any email tracked by the extension.
https://wk.mailcheck.fr
A different base from the verification API above. Same API key, same
Authorization: Bearer header.
1. Register the email before sending
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier for the email, 64 characters max. Use a UUID |
subject | string | No | Message subject, shown in the dashboard |
recipient | string | No | Recipient address |
sender | string | No | Your sending address |
provider | string | No | Free-text label, e.g. smtp. On the free plan, only one provider is allowed per calendar month |
id must be a UUID you generate yourself, never a
readable or sequential value. The table is shared across every account: an id
already taken elsewhere is silently ignored, and the opens would then be counted
on the wrong account.
curl -X POST https://wk.mailcheck.fr/tracking/emails \
-H "Authorization: Bearer sk-mc-xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","subject":"Your quote","recipient":"[email protected]","sender":"[email protected]","provider":"smtp"}' 2. Add the pixel to the HTML body
Insert this image, with the same id, before sending through your SMTP server:
<img src="https://wk.mailcheck.fr/o/3fa85f64-5717-4562-b3fc-2c963f66afa6.gif" width="1" height="1" alt=""> This route needs no authentication, like any tracking pixel: it records the open and returns a transparent 1x1 GIF.
Free plan limits
10 tracked emails per calendar month, one provider at a time (the
provider value of the first email of the month locks the
rest). Unlimited tracking across every provider from the Tracking plan at 9
EUR/month.
What the self-open filter does not cover here
The extension ignores your own rereads by comparing the IP address at send time to the one at open time. With an SMTP server, the email is registered from your server, so that fingerprint is your server's, not your browser's. The filter stays harmless, it simply does not apply to this particular case.
Error codes
| HTTP code | Error code | Description |
|---|---|---|
| 400 | invalid_request | Invalid request body or missing email field |
| 401 | unauthorized | Missing or invalid API key |
| 402 | insufficient_credits | Monthly quota exhausted, top up your plan |
| 429 | rate_limit_exceeded | Too many requests, see the Retry-After header |
| 500 | server_error | Internal error, retry in a few seconds |
{
"error": "insufficient_credits",
"message": "Your monthly quota is exhausted. Upgrade your plan.",
"credits_remaining": 0
} Ready to integrate?
Create your account for free and get your API key in under a minute. 2 free verifications.