Introduction
DKIM is one of the most misunderstood DNS-based email controls. Many teams know it exists, fewer can explain what a selector is, and even fewer can reliably audit DKIM posture across a vendor list, a customer tenant base, or a domain portfolio.
The practical problem is not the cryptography. It is discovery and repeatability: the DKIM public key lives in DNS TXT records under selector-specific names, keys rotate, providers publish multiple selectors, and records are often split across multiple quoted strings. A DKIM lookup API workflow turns that messy reality into structured, reviewable data.
WhoisJSON does not expose a dedicated "DKIM selector discovery" endpoint. Instead, use the DNS Lookup API /nslookup endpoint and query the exact DKIM hostname you care about (for example, selector1._domainkey.example.com). This guide shows a safe, production-friendly approach that keeps the result honest: lookup and parse the DKIM TXT record you requested; do not claim you enumerated every selector unless you actually did.
What Is DKIM?
DomainKeys Identified Mail (DKIM) is an email authentication mechanism where the sending system signs a message with a private key. The receiver uses a corresponding public key published in DNS to verify the signature.
In an audit context, DKIM answers a narrow but valuable question: "Does this domain publish DKIM keys for the selectors it uses to sign mail?" It does not, by itself, tell you whether a specific message was signed correctly. For that, you need the message headers and body hash.
What Is a DKIM Selector?
A DKIM selector is a short identifier that allows a domain to publish multiple DKIM keys at the same time. Providers use selectors to rotate keys safely without breaking verification.
DKIM-Signature header of a message as s=selector, and in DNS as: selector._domainkey.example.com.If you have access to message headers (from a mailbox, logs, or a test email), selector discovery is straightforward: read the selector from the DKIM-Signature header. If you do not have headers, selector discovery becomes guesswork unless you maintain a provider-specific selector list.
DKIM Lookup API vs DKIM Validation
A DNS lookup and a full DKIM validator solve different problems. Keeping the boundary clear avoids false claims in security reports.
| Workflow | What it does | Typical inputs |
|---|---|---|
| DKIM lookup | Retrieves the DKIM public key TXT record for a specific selector hostname. | selector + domain (e.g., selector1 + example.com) |
| DKIM syntax parsing | Parses v=DKIM1 tags (k=, p=, t=, n=, s=) and normalizes split TXT strings. | DKIM TXT record string |
| DKIM signature validation | Verifies a specific message signature against the published key. | Full email message (headers + body) |
Query DKIM Public Keys in JSON
DKIM is published as a TXT record. That means the API call is a standard DNS lookup. The only difference is the hostname you query.
curl "https://whoisjson.com/api/v1/nslookup?domain=selector1._domainkey.example.com" \
-H "Authorization: TOKEN=YOUR_API_KEY"When a DKIM record exists, read TXT values and filter for those starting with v=DKIM1. Providers often publish additional TXT values for unrelated verification tokens, so filtering matters.
{
"TXT": [
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQE...",
"google-site-verification=abc123"
]
}
How to Parse a DKIM TXT Record Safely
A DKIM record is a semicolon-separated list of tag=value pairs. The most important tag for audits is code p= | (public key). When code p= | is empty, DKIM is effectively disabled for that selector.
| Tag | Meaning | Audit note |
|---|---|---|
v=DKIM1 | Version tag. | Required for DKIM records. |
k= | Key type (commonly rsa, sometimes ed25519). | Treat unknown values cautiously; some clients only support rsa. |
p= | Base64 public key material. | Empty p= is a strong misconfiguration or an intentional disable during rotation. |
t= | Flags such as y (testing) or s (strict). | y indicates non-enforced testing; do not overstate strength. |
s= | Service type (rarely used). | Often omitted; do not require it. |
Python Example: DKIM Lookup and Parsing
This Python example queries a selector hostname, finds the DKIM TXT value, and extracts tags into a small structured object.
import requests
import re
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://whoisjson.com/api/v1"
def parse_dkim_tags(record: str) -> dict:
parts = [p.strip() for p in record.split(";") if p.strip()]
tags = {}
for part in parts:
if "=" in part:
k, v = part.split("=", 1)
tags[k.strip().lower()] = v.strip()
return tags
def lookup_dkim(selector: str, domain: str) -> dict:
host = f"{selector}._domainkey.{domain}"
response = requests.get(
f"{BASE_URL}/nslookup",
headers={"Authorization": f"TOKEN={API_KEY}"},
params={"domain": host},
timeout=10,
)
response.raise_for_status()
txt = response.json().get("TXT") or []
txt_values = [str(v).strip() for v in txt]
dkim = next(
(v for v in txt_values if v.lower().startswith("v=dkim1")),
None,
)
if not dkim:
return {"host": host, "status": "missing", "record": None}
tags = parse_dkim_tags(dkim)
public_key = tags.get("p")
key_type = tags.get("k", "rsa")
return {
"host": host,
"status": "present" if public_key else "disabled",
"keyType": key_type,
"hasPublicKey": bool(public_key),
"testing": "t" in tags and re.search(r"(^|:)y($|:)", tags["t"]) is not None,
"tags": tags,
"record": dkim,
}
print(lookup_dkim("selector1", "example.com"))
Node.js Example: Audit Multiple Selectors with Bounded Concurrency
In practice, you often test a small set of likely selectors for common providers (or the selectors you observed in headers). This example queries multiple selector hostnames and returns a compact report per selector.
import pLimit from "p-limit";
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://whoisjson.com/api/v1";
function parseTags(record) {
return String(record || "")
.split(";")
.map((p) => p.trim())
.filter(Boolean)
.reduce((acc, part) => {
const idx = part.indexOf("=");
if (idx === -1) return acc;
const k = part.slice(0, idx).trim().toLowerCase();
const v = part.slice(idx + 1).trim();
acc[k] = v;
return acc;
}, {});
}
async function lookupHost(host) {
const url = new URL(`${BASE_URL}/nslookup`);
url.searchParams.set("domain", host);
const res = await fetch(url, {
headers: { Authorization: `TOKEN=${API_KEY}` },
});
if (!res.ok) throw new Error(`DNS lookup failed: ${res.status}`);
return await res.json();
}
async function lookupDkim(selector, domain) {
const host = `${selector}._domainkey.${domain}`;
const data = await lookupHost(host);
const txt = (data.TXT ?? []).map(String).map((v) => v.trim());
const record = txt.find((v) => v.toLowerCase().startsWith("v=dkim1")) || null;
const tags = parseTags(record);
return {
host,
selector,
present: Boolean(record),
hasPublicKey: Boolean(tags.p),
keyType: tags.k || "rsa",
testing: typeof tags.t === "string" && tags.t.split(":").includes("y"),
record,
};
}
// Example: audit a few likely selectors
const domain = "example.com";
const selectors = ["selector1", "selector2", "google", "k1", "s1"];
const limit = pLimit(5);
const results = await Promise.all(
selectors.map((s) => limit(() => lookupDkim(s, domain).catch((e) => ({ selector: s, host: `${s}._domainkey.${domain}`, error: e.message }))))
);
console.log(results);
Common DKIM Findings
Missing selector record
The queried selector hostname has no DKIM TXT record. Confirm that the selector is correct (from headers) before treating this as a weakness.
Empty public key (p=)
The record exists but p= is empty, which often indicates a disabled selector or a broken rotation.
Testing flag (t=y)
Some receivers treat testing mode as lower assurance. Do not overstate enforcement when t=y is present.
Multiple selectors
Providers commonly publish multiple selectors. Use header-derived selectors to avoid guessing.
DKIM vs SPF vs DMARC (How They Fit Together)
DKIM is one piece of the email authentication triangle. A practical audit checks all three, plus transport/security controls where relevant.
| Control | Main question | Where it lives |
|---|---|---|
| SPF | Which infrastructure may send mail using the envelope domain? | Root-domain TXT (v=spf1) |
| DKIM | Was the message signed by a key published by the domain? | Selector TXT (selector._domainkey) |
| DMARC | What should receivers do when aligned authentication fails? | _dmarc TXT |
For SPF and DMARC, see the dedicated guides: SPF lookup and DMARC lookup. For full DNS inventory and record-type context, use the DNS Lookup API guide.
Bulk DKIM Checks for Vendor Reviews and Portfolios
Large-scale DKIM checks are useful in two common cases: vendor due diligence (does the vendor's sending domain publish DKIM keys for observed selectors?) and tenant onboarding (does the customer's domain publish DKIM keys for their chosen provider selectors?).
- Prefer selectors observed in email headers over guessed selectors.
- Store the exact DKIM TXT record string for change detection and evidence.
- Treat missing DKIM as a configuration gap, not as a definitive fraud signal.
- Combine results with DMARC posture, MX routing, and transport security records.
- Use bounded concurrency and backoff patterns for reliability at scale.
For production retry patterns, see the rate limits and retries guide. For broader email posture scoring, see Email Domain Reputation API.
What a DKIM Lookup Cannot Prove
FAQ
What is a DKIM lookup API?
A DKIM lookup API retrieves the DKIM public key TXT record for a specific selector hostname and returns it as structured data for parsing, audits, and monitoring.
Which WhoisJSON endpoint can I use to check DKIM?
Query GET /api/v1/nslookup with domain=selector._domainkey.example.com, then filter the TXT array for values beginning with v=DKIM1.
How do I find the DKIM selector?
The most reliable method is to read the selector from the DKIM-Signature header (s=) of a message. Without headers, selector discovery is incomplete and often provider-specific.
What does an empty p= value mean?
An empty p= typically means the selector is disabled or misconfigured. It may occur during a broken rotation or when a provider intentionally publishes a disabled record.
Can I check DKIM, SPF, and DMARC together?
Not in one DNS call, because DKIM lives on selector-specific hostnames while SPF and DMARC live on predictable root-domain names. In practice, you query /nslookup for SPF/DMARC on the root domain, and /nslookup for DKIM on selector hostnames.
Conclusion
A DKIM lookup API workflow makes DKIM audits repeatable. Query a selector hostname through /nslookup, filter TXT values for v=DKIM1, parse tags, and flag the misconfigurations that matter: missing records, empty public keys, and testing mode.
Keep the scope precise. DNS lookups can show published keys for selectors you specify; signature verification and complete selector discovery require message-level data. That boundary is what makes a DKIM audit report credible.
Check DKIM selector records with WhoisJSON
Query DKIM, SPF, DMARC, MX, MTA-STS, TLS-RPT and standard DNS records with one API key.
DNS Lookup APIView Documentation