Tools
Free public tools for email header analysis and domain health checks. These endpoints do not require authentication and are rate-limited per IP.
Header Analyzer
POST/v1/public/tools/header-analyzer
Parse and analyze raw email headers to trace the delivery path, extract authentication results, identify the sending infrastructure, and detect anomalies. IP enrichment is applied to the first 20 IP-bearing Received hops.
Authentication
None required (public endpoint).
Request Body
{
"headers": "Received: from mail-wr1-f41.google.com (209.85.221.41) by mx.example.com with ESMTPS; Sun, 13 Apr 2026 10:00:00 +0000\r\nAuthentication-Results: mx.example.com; spf=pass smtp.mailfrom=user@gmail.com\r\nDKIM-Signature: v=1; a=rsa-sha256; d=gmail.com; s=20230601; ..."
}
| Field | Type | Required | Description |
|---|---|---|---|
headers | string | Yes | Raw email headers to analyze, maximum 48 KiB |
The complete JSON request body is limited to 64 KiB. Requests exceeding either limit return 413 Payload Too Large.
Response (200)
{
"data": {
"received_chain": [
{
"from_host": "mail-wr1-f41.google.com",
"from_ip": "209.85.221.41",
"by_host": "mx.example.com",
"protocol": "ESMTPS",
"timestamp": "2026-04-13T10:00:00Z",
"delay": "0s",
"asn": 15169,
"asn_name": "Google LLC",
"country": "US",
"cloud_provider": "Google Cloud",
"connection_type": "datacenter",
"threat_score": 0
}
],
"authentication": {
"spf_result": "pass",
"dkim_result": "present",
"dkim_selector": "20230601",
"dkim_domain": "gmail.com"
},
"infrastructure": {
"origin_ip": "209.85.221.41",
"from_domain": "gmail.com",
"x_mailer": "",
"user_agent": ""
},
"anomalies": []
},
"meta": {
"processing_time_ms": 25
}
}
Response Fields
Received Chain (per hop)
| Field | Type | Description |
|---|---|---|
from_host | string | Sending host name |
from_ip | string | Sending IP address |
by_host | string | Receiving host name |
protocol | string | Transfer protocol (SMTP, ESMTP, ESMTPS) |
timestamp | string | RFC 3339 timestamp from header |
delay | string | Time delay since previous hop |
asn | integer | ASN of the sending IP (enriched) |
asn_name | string | ASN organization name (enriched) |
country | string | Country code of the sending IP (enriched) |
cloud_provider | string | Cloud provider if detected (enriched) |
connection_type | string | Connection type (enriched) |
threat_score | integer | Threat score of the sending IP (enriched) |
Authentication
| Field | Type | Description |
|---|---|---|
spf_result | string | SPF result (pass, fail, softfail, none) |
dkim_result | string | DKIM status (present, absent) |
dkim_selector | string | DKIM selector used |
dkim_domain | string | DKIM signing domain |
dmarc_result | string | DMARC result if found |
Infrastructure
| Field | Type | Description |
|---|---|---|
origin_ip | string | Originating IP (first hop with an IP) |
from_domain | string | Sending domain |
x_mailer | string | X-Mailer header value |
user_agent | string | User-Agent header value |
Anomalies
Array of detected anomalies (strings). Examples:
- "Negative time delay between hops -- possible forged Received header"
Domain Check
GET/v1/public/tools/domain-check/{domain}
Quick public domain health check. Combines MX, SPF, DKIM, and DMARC validation into a single grade. Similar to the /v1/email/domain/{domain}/dns endpoint but designed as a free tool without requiring authentication.
Authentication
None required (public endpoint).
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | Public DNS hostname with at least two valid labels; IP literals, underscores, empty labels, and single-label names are rejected |
The complete check has a five-second deadline. All MX, SPF, DKIM, and DMARC work shares a 32-lookup request budget and the process-wide DNS concurrency bound. Successful results are cached in a bounded five-minute cache.
Response (200)
{
"data": {
"domain": "example.com",
"grade": "B",
"score": 80,
"mx": {
"records": ["mx1.example.com", "mx2.example.com"],
"is_valid": true
},
"spf": {
"raw": "v=spf1 include:_spf.google.com ~all",
"mechanisms": ["include:_spf.google.com", "~all"],
"all_qualifier": "~",
"is_valid": true,
"is_permissive": false,
"dns_lookup_count": 3,
"exceeds_lookups": false
},
"dkim": [
{
"selector": "google",
"found": true,
"key_type": "rsa",
"key_bits": 2048,
"is_valid": true
}
],
"dmarc": {
"raw": "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com",
"version": "DMARC1",
"policy": "quarantine",
"subdomain_policy": "quarantine",
"effective_policy": "quarantine",
"percentage": 100,
"aggregate_report_uris": ["mailto:dmarc@example.com"],
"dkim_alignment": "r",
"spf_alignment": "r",
"report_interval": 86400,
"record_domain": "example.com",
"inherited": false,
"strength_rating": "moderate",
"is_valid": true
},
"recommendations": [
"Consider upgrading DMARC policy from quarantine to reject for maximum protection"
]
},
"meta": {
"processing_time_ms": 500
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
domain | string | The checked domain |
grade | string | Letter grade (A-F) |
score | integer | Numeric score (0-100) |
mx | object | MX record results |
spf | object | SPF record analysis |
dkim | array | DKIM records found |
dmarc | object | DMARC record analysis |
recommendations | array | Actionable improvement suggestions |
Grading
| Grade | Score | Description |
|---|---|---|
| A | 90-100 | Excellent email authentication |
| B | 75-89 | Good, minor improvements possible |
| C | 55-74 | Moderate risk, missing configurations |
| D | 35-54 | Poor, significant gaps |
| F | 0-34 | Critical, minimal or no authentication |
Telemetry Ingestion
POST/v1/email/telemetry/ingest
Submit email sending telemetry observations from your system. This data feeds into the reputation scoring engine. Maximum 100 observations per request.
Authentication
Required (API key).
Request Body
{
"observations": [
{
"ip": "198.51.100.25",
"bounce_rate": 0.03,
"complaint_rate": 0.001,
"volume_24h": 5000,
"observed_at": "2026-04-13T10:00:00Z"
},
{
"ip": "203.0.113.50",
"bounce_rate": 0.15,
"complaint_rate": 0.005,
"volume_24h": 800,
"observed_at": "2026-04-13T10:00:00Z"
}
]
}
Observation Fields
| Field | Type | Required | Description |
|---|---|---|---|
ip | string | Yes | Sending IP address |
bounce_rate | number | No | Bounce rate (0.0 to 1.0) |
complaint_rate | number | No | Complaint rate (0.0 to 1.0) |
volume_24h | integer | No | Sending volume in last 24h |
observed_at | string | No | ISO 8601 timestamp (defaults to now, must be within last 48h) |
Response (200)
{
"data": {
"accepted": 2,
"rejected": 0,
"errors": []
},
"meta": {
"processing_time_ms": 15
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
accepted | integer | Number of observations stored |
rejected | integer | Number of observations rejected |
errors | array | Error messages for rejected observations |
Validation Rules
bounce_ratemust be 0.0 to 1.0complaint_ratemust be 0.0 to 1.0volume_24hmust be >= 0observed_atmust be within the last 48 hours and not in the future- Maximum 100 observations per request
- Invalid IPs are rejected with an error message
Error Responses
400 Bad Request
{
"data": {
"error": "headers field is required",
"code": "MISSING_HEADERS"
},
"meta": {
"processing_time_ms": 0
}
}
401 Unauthorized (Telemetry only)
{
"data": {
"error": "authentication required",
"code": "AUTH_REQUIRED"
},
"meta": {
"processing_time_ms": 0
}
}
413 Payload Too Large (Header Analyzer)
{
"data": {
"error": "headers field exceeds 48 KiB",
"code": "HEADERS_TOO_LARGE"
},
"meta": {
"processing_time_ms": 0
}
}
504 Gateway Timeout (Domain Check)
{
"data": {
"error": "domain check exceeded its time limit",
"code": "DOMAIN_CHECK_TIMEOUT"
},
"meta": {
"processing_time_ms": 0
}
}
Code Examples
cURL
# Header analysis (no auth needed)
curl -X POST "https://api.limesindex.com/v1/public/tools/header-analyzer" \
-H "Content-Type: application/json" \
-d '{"headers": "Received: from mail.example.com (198.51.100.25) by mx.google.com..."}'
# Domain check (no auth needed)
curl -X GET "https://api.limesindex.com/v1/public/tools/domain-check/example.com"
# Telemetry ingestion (auth required)
curl -X POST "https://api.limesindex.com/v1/email/telemetry/ingest" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"observations": [
{
"ip": "198.51.100.25",
"bounce_rate": 0.03,
"complaint_rate": 0.001,
"volume_24h": 5000,
"observed_at": "2026-04-13T10:00:00Z"
}
]
}'
Python
import requests
BASE_URL = "https://api.limesindex.com"
# Header analysis (public, no auth)
raw_headers = """Received: from mail.example.com (198.51.100.25) by mx.google.com
with ESMTPS; Sun, 13 Apr 2026 10:00:00 +0000
Authentication-Results: mx.google.com; spf=pass"""
resp = requests.post(
f"{BASE_URL}/v1/public/tools/header-analyzer",
json={"headers": raw_headers}
)
analysis = resp.json()["data"]
for hop in analysis["received_chain"]:
print(f"Hop: {hop.get('from_ip', '?')} -> {hop.get('by_host', '?')}")
if hop.get("asn"):
print(f" ASN: {hop['asn']} ({hop['asn_name']})")
# Domain check (public, no auth)
resp = requests.get(f"{BASE_URL}/v1/public/tools/domain-check/example.com")
check = resp.json()["data"]
print(f"Grade: {check['grade']} (Score: {check['score']})")
for rec in check["recommendations"]:
print(f" - {rec}")
# Telemetry ingestion (auth required)
API_KEY = "YOUR_API_KEY"
resp = requests.post(
f"{BASE_URL}/v1/email/telemetry/ingest",
headers={"X-API-Key": API_KEY},
json={
"observations": [
{
"ip": "198.51.100.25",
"bounce_rate": 0.03,
"complaint_rate": 0.001,
"volume_24h": 5000
}
]
}
)
result = resp.json()["data"]
print(f"Accepted: {result['accepted']}, Rejected: {result['rejected']}")
Use Cases
- Header forensics: Trace email delivery issues by analyzing Received headers
- Domain auditing: Check any domain's email auth setup before sending to it
- Telemetry contribution: Share your sending metrics to improve the global reputation model
- Onboarding: Validate domain DNS before adding to your platform
Related Endpoints
- Email Domain DNS - Authenticated version with persistence
- Email Reputation - IP reputation scoring
- Warmup - Warm-up guidance based on telemetry data