How Lens Scores a Domain

Lens runs five checks in parallel and produces a single A+–F grade. This guide explains the scoring model, how email security is split between sending and receiving domains, and how to test specific DKIM selectors.

What lens checks

For any domain, lens calls five backends in parallel and aggregates the results:

SectionToolWhat it measuresWeight
IPifconfig-rsNetwork type, hosting reputation, geolocation10%
DNSprismDNSSEC, CAA records, NS delegation, HTTPS records20%
TLStlsightCertificate chain, protocol version, cipher strength35%
HTTPspectraSecurity headers, HSTS, CORS, cookie attributes20%
EmailbeaconSPF, DKIM, DMARC, MTA-STS, DANE, BIMI, DNSBL15%

HTTP and Email sections are optional. When a backend is not configured, the remaining weights are rebalanced proportionally — a missing section does not penalise the grade.

Scoring algorithm

Each check has a verdict and a weight:

A section score is earned / possible × 100%. The overall score is the weighted average of active section scores. The letter grade is determined by comparing the overall percentage to fixed thresholds:

GradeScoreMeaning
A+≥ 97%Exemplary — all checks pass
A≥ 90%Excellent — minor gaps only
B≥ 75%Good — some non-critical findings
C≥ 60%Fair — notable gaps, action recommended
D≥ 40%Poor — significant issues present
F< 40% or hard-failFailing

Hard failures

Four TLS conditions force the grade to F regardless of the numeric score:

These conditions indicate an immediately broken service, so the score is irrelevant. All other findings contribute to the numeric score rather than triggering a hard override.

Email security: sending vs. receiving

Email security has two distinct concerns that apply to different domains:

Lens reflects this split in the ten scored checks of the Email section:

CheckApplies toWeight
SPF All domains 3
DKIM All domains 3
DMARC All domains 4
MX Domains with MX records 2
MTA-STS Domains with MX records 2
TLS-RPT Domains with MX records 1
BIMI Domains with MX records 2
DANE Domains with MX records 2
DNSBL Domains with MX records 2
FCrDNS Domains with MX records 1

When lens detects no MX records, the seven MX-dependent checks are marked not applicable and use a skip verdict. Skip verdicts are excluded from both earned and possible totals, so a parked domain is not penalised for missing receiving infrastructure. Only SPF, DKIM and DMARC (weight 10) are scored.

Worked example: mail domain vs. parked domain

Mail domain (MX records present)

example.com runs email. All ten checks are scored. SPF, DKIM, and DMARC pass; MTA-STS is in testing mode (warn); everything else passes.

Parked domain (no MX records)

parked.example.com is used only for web. No MX records exist. The seven MX-dependent checks are skipped automatically.

A parked domain with correct SPF and DMARC records scores A+ on the email section — the absence of receiving infrastructure is not a deficiency.

Testing DKIM selectors

By default, beacon uses a built-in map of known DKIM selectors for major email providers (Google Workspace, Microsoft 365, etc.). For custom selectors, pass them via the dkim_selectors parameter:

# Via URL parameter
https://lens.netray.info/?d=example.com&dkim_selectors=google,selector1

# Via curl
curl -s 'https://lens.netray.info/api/check/example.com?stream=false&dkim_selectors=default,s1' \
  | jq '.email.checks[] | select(.name == "dkim")'

Selector validation rules:

Invalid selectors return HTTP 400 before any backend call. Absent dkim_selectors parameter: beacon uses its built-in provider map.

Section states

A section can be in one of three states:

StateEffect on scoringWhen it occurs
Scored Contributes to the overall weighted average Backend responded successfully
Errored Excluded from scoring silently Backend unreachable or timed out
Not applicable Excluded from scoring; reason recorded in summary.not_applicable Email backend timed out internally (grade: "Skipped")

An errored section does not lower the grade — the overall score is computed from whatever sections are available. A footnote appears in the UI when not_applicable is non-empty.

Cache behaviour

Results are cached per domain for 5 minutes. The X-Cache response header indicates HIT or MISS. Requests with dkim_selectors always bypass the cache, since selector-specific results cannot be shared.