What lens checks
For any domain, lens calls five backends in parallel and aggregates the results:
| Section | Tool | What it measures | Weight |
|---|---|---|---|
| IP | ifconfig-rs | Network type, hosting reputation, geolocation | 10% |
| DNS | prism | DNSSEC, CAA records, NS delegation, HTTPS records | 20% |
| TLS | tlsight | Certificate chain, protocol version, cipher strength | 35% |
| HTTP | spectra | Security headers, HSTS, CORS, cookie attributes | 20% |
| beacon | SPF, DKIM, DMARC, MTA-STS, DANE, BIMI, DNSBL | 15% |
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:
- pass → earns full weight
- warn → earns exactly half its weight (a weight-5 warn earns 2.5)
- fail / not found → earns zero
- skip → excluded from both earned and possible totals (not a penalty)
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:
| Grade | Score | Meaning |
|---|---|---|
| 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-fail | Failing |
Hard failures
Four TLS conditions force the grade to F regardless of the numeric score:
- Untrusted chain — the certificate is not signed by a trusted CA. Browsers will show a security warning.
- Expired certificate — any certificate in the chain is past its validity period.
- Hostname mismatch — the certificate does not cover the checked hostname. Browsers will show a security warning.
- TLS unreachable — no address completed a TLS handshake.
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:
-
Sending identity — SPF, DKIM, and DMARC.
These apply to every domain, because any domain can be spoofed in
the
From:header of an email, even domains that never send mail. A parked domain with no MX records still needs SPF and DMARC to prevent impersonation. - Receiving infrastructure — MX records, MTA-STS, DANE/TLSA, TLS-RPT, BIMI, FCrDNS, and DNSBL reputation. These only apply to domains that actively receive email. A parked or web-only domain with no MX records has no receiving infrastructure to check.
Lens reflects this split in the ten scored checks of the Email section:
| Check | Applies to | Weight |
|---|---|---|
| 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.
- SPF, DKIM, DMARC: 10/10
- MX, DNSBL, FCrDNS: 5/5
- MTA-STS: 1/2 (a warn earns half the weight)
- TLS-RPT, DANE, BIMI: 5/5
- Email section: 21/22 = 95.5% → grade A
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.
- SPF: 3/3, DMARC: 4/4 (mandatory even for parked domains)
- DKIM: skipped (no DKIM keys published)
- MX, MTA-STS, TLS-RPT, BIMI, DANE, DNSBL, FCrDNS: skipped (no MX)
- Email section: 7/7 = 100% → grade A+
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:
- Characters:
[a-zA-Z0-9-]only - Length: 1–63 characters per selector
- Count: 1–10 selectors per request
- Separator: comma (whitespace around commas is trimmed)
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:
| State | Effect on scoring | When 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.