> For the complete documentation index see https://domscan.net/llms.txt. Markdown versions of every docs page are available by appending .md to the page URL.

Source: https://domscan.net/es/docs/email-auth

# Autenticación de correo electrónico

API de DomScan: Auditoría de autenticación de correo electrónico para registros SPF, DMARC y DKIM.

Auditoría de autenticación de correo electrónico para registros SPF, DMARC y DKIM. Este endpoint valida los tres estándares en una sola solicitud y devuelve una calificación de seguridad (A-C) con recomendaciones accionables. Útil para resolver problemas de entregabilidad del correo electrónico y reforzar la seguridad.

GET /v1/email-auth Créditos: 3

#### Parámetros de consulta

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| domain | string | obligatorio |
| selectors | string | opcional |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `spf` | object |
| `spf.classification` | object |
| `spf.classification.status` | string |
| `spf.classification.reason` | string |
| `spf.classification.evidence` | object |
| `spf.classification.evidence.source` | string |
| `spf.classification.evidence.method` | string |
| `spf.classification.evidence.observed_at` | string |
| `spf.classification.evidence.detail` | string |
| `spf.classification.checked_at` | string |
| `spf.record` | string \| null |
| `spf.lookup_estimate` | integer |
| `spf.includes[]` | string[] |
| `spf.redirect` | string \| null |
| `spf.macros_present` | boolean |
| `spf.macro_references[]` | string[] |
| `spf.lookup_walk_count` | integer |
| `spf.lookup_limit_exceeded` | boolean |
| `spf.walk[]` | object[] |
| `spf.walk[]` | object |
| `spf.walk[].domain` | string |
| `spf.walk[].depth` | integer |
| `spf.walk[].record` | string |
| `spf.walk[].mechanisms[]` | string[] |
| `spf.walk[].includes[]` | string[] |
| `spf.walk[].redirect` | string \| null |
| `spf.walk[].direct_lookup_count` | integer |
| `spf.walk[].total_lookup_count` | integer |
| `spf.walk[].macros_present` | boolean |
| `spf.walk[].macro_references[]` | string[] |
| `spf.walk[].multiple_records` | integer |
| `spf.walk_errors[]` | string[] |
| `spf.lookup_tree` | object |
| `spf.lookup_tree.root_domain` | string |
| `spf.lookup_tree.node_count` | integer |
| `spf.lookup_tree.max_depth` | integer |
| `spf.lookup_tree.cycles_detected[]` | string[] |
| `spf.lookup_tree.nodes[]` | object[] |
| `spf.lookup_tree.nodes[]` | object |
| `spf.lookup_tree.nodes[].domain` | string |
| `spf.lookup_tree.nodes[].depth` | integer |
| `spf.lookup_tree.nodes[].status` | string |
| `spf.lookup_tree.nodes[].direct_lookup_count` | integer |
| `spf.lookup_tree.nodes[].total_lookup_count` | integer |
| `spf.lookup_tree.nodes[].includes[]` | string[] |
| `spf.lookup_tree.nodes[].redirect` | string \| null |
| `spf.lookup_tree.nodes[].mechanisms[]` | string[] |
| `spf.lookup_tree.nodes[].errors[]` | string[] |
| `spf.lookup_tree.edges[]` | object[] |
| `spf.lookup_tree.edges[]` | object |
| `spf.lookup_tree.edges[].from` | string |
| `spf.lookup_tree.edges[].to` | string |
| `spf.lookup_tree.edges[].type` | string |
| `dkim[]` | object[] |
| `dkim[]` | object |
| `dkim[].classification` | object |
| `dkim[].classification.status` | string |
| `dkim[].classification.reason` | string |
| `dkim[].classification.evidence` | object |
| `dkim[].classification.evidence.source` | string |
| `dkim[].classification.evidence.method` | string |
| `dkim[].classification.evidence.observed_at` | string |
| `dkim[].classification.evidence.detail` | string |
| `dkim[].classification.checked_at` | string |
| `dkim[].selector` | string |
| `dkim[].record` | string \| null |
| `dkim[].key_type` | string \| null |
| `dkim[].key_size` | integer \| null |
| `dkim_audit` | object |
| `dkim_audit.selectors_checked[]` | string[] |
| `dkim_audit.selectors_found[]` | object[] |
| `dkim_audit.selectors_found[]` | object |
| `dkim_audit.selectors_found[].selector` | string |
| `dkim_audit.selectors_found[].dns_name` | string |
| `dkim_audit.selectors_found[].record` | string \| null |
| `dkim_audit.selectors_found[].record_type` | string \| null |
| `dkim_audit.selectors_found[].cname_targets[]` | string[] |
| `dkim_audit.selectors_found[].provider_hint` | string \| null |
| `dkim_audit.selectors_found[].key_type` | string \| null |
| `dkim_audit.selectors_found[].key_size` | integer \| null |
| `dkim_audit.selectors_found[].valid` | boolean |
| `dkim_audit.selectors_found[].revoked` | boolean |
| `dkim_audit.selectors_found[].weak` | boolean |
| `dkim_audit.selectors_found[].hash_algorithms[]` | string[] |
| `dkim_audit.selectors_found[].service_type` | string \| null |
| `dkim_audit.selectors_found[].flags[]` | string[] |
| `dkim_audit.selectors_found[].issues[]` | string[] |
| `dkim_audit.total_found` | integer |
| `dkim_audit.providers_detected[]` | string[] |
| `dkim_audit.valid_selector_count` | integer |
| `dkim_audit.weak_selector_count` | integer |
| `dkim_audit.revoked_selector_count` | integer |
| `bimi` | object |
| `bimi.classification` | object |
| `bimi.classification.status` | string |
| `bimi.classification.reason` | string |
| `bimi.classification.evidence` | object |
| `bimi.classification.evidence.source` | string |
| `bimi.classification.evidence.method` | string |
| `bimi.classification.evidence.observed_at` | string |
| `bimi.classification.evidence.detail` | string |
| `bimi.classification.checked_at` | string |
| `bimi.exists` | boolean |
| `bimi.record` | string \| null |
| `bimi.valid` | boolean |
| `bimi.logo_url` | string \| null |
| `bimi.authority_url` | string \| null |
| `bimi.logo_fetch_ok` | boolean \| null |
| `bimi.logo_http_status` | integer \| null |
| `bimi.logo_content_type` | string \| null |
| `bimi.logo_bytes` | integer \| null |
| `bimi.logo_svg_detected` | boolean \| null |
| `bimi.vmc_present` | boolean |
| `bimi.vmc_fetched` | boolean \| null |
| `bimi.vmc_http_status` | integer \| null |
| `bimi.vmc_content_type` | string \| null |
| `bimi.vmc_certificate_valid` | boolean \| null |
| `bimi.vmc_subject` | string \| null |
| `bimi.vmc_issuer` | string \| null |
| `bimi.vmc_not_before` | string \| null |
| `bimi.vmc_not_after` | string \| null |
| `bimi.vmc_days_to_expiry` | integer \| null |
| `bimi.vmc_fingerprint_sha256` | string \| null |
| `bimi.vmc_san_domains[]` | string[] |
| `bimi.errors[]` | string[] |
| `dmarc` | object |
| `dmarc.classification` | object |
| `dmarc.classification.status` | string |
| `dmarc.classification.reason` | string |
| `dmarc.classification.evidence` | object |
| `dmarc.classification.evidence.source` | string |
| `dmarc.classification.evidence.method` | string |
| `dmarc.classification.evidence.observed_at` | string |
| `dmarc.classification.evidence.detail` | string |
| `dmarc.classification.checked_at` | string |
| `dmarc.record` | string \| null |
| `dmarc.tags` | object |
| `mta_sts` | object |
| `mta_sts.classification` | object |
| `mta_sts.classification.status` | string |
| `mta_sts.classification.reason` | string |
| `mta_sts.classification.evidence` | object |
| `mta_sts.classification.evidence.source` | string |
| `mta_sts.classification.evidence.method` | string |
| `mta_sts.classification.evidence.observed_at` | string |
| `mta_sts.classification.evidence.detail` | string |
| `mta_sts.classification.checked_at` | string |
| `mta_sts.exists` | boolean |
| `mta_sts.record` | string \| null |
| `mta_sts.valid` | boolean |
| `mta_sts.policy_id` | string \| null |
| `mta_sts.policy_fetch_ok` | boolean |
| `mta_sts.policy_http_status` | integer \| null |
| `mta_sts.mode` | string \| null |
| `mta_sts.max_age` | integer \| null |
| `mta_sts.mx_hosts[]` | string[] |
| `mta_sts.mx_records[]` | string[] |
| `mta_sts.policy_matches_mx` | boolean \| null |
| `mta_sts.uncovered_mx[]` | string[] |
| `mta_sts.errors[]` | string[] |
| `tls_rpt` | object |
| `tls_rpt.exists` | boolean |
| `tls_rpt.record` | string \| null |
| `tls_rpt.valid` | boolean |
| `tls_rpt.rua[]` | string[] |
| `tls_rpt.errors[]` | string[] |
| `client_access` | object |
| `client_access.provider_hint` | object |
| `client_access.provider_hint.id` | string |
| `client_access.provider_hint.name` | string |
| `client_access.mx_records[]` | string[] |
| `client_access.services[]` | object[] |
| `client_access.services[]` | object |
| `client_access.services[].service` | string |
| `client_access.services[].host` | string |
| `client_access.services[].port` | integer |
| `client_access.services[].source` | string |
| `client_access.services[].priority` | integer \| null |
| `client_access.services[].weight` | integer \| null |
| `client_access.services[].tls_mode` | string |
| `client_access.services[].reachable` | boolean |
| `client_access.services[].tls_negotiated` | boolean |
| `client_access.services[].starttls_offered` | boolean \| null |
| `client_access.services[].protocol` | string \| null |
| `client_access.services[].cipher` | string \| null |
| `client_access.services[].certificate` | object |
| `client_access.services[].certificate.subject` | string |
| `client_access.services[].certificate.issuer` | string |
| `client_access.services[].certificate.not_before` | string |
| `client_access.services[].certificate.not_after` | string |
| `client_access.services[].certificate.days_to_expiry` | integer |
| `client_access.services[].certificate.expired` | boolean |
| `client_access.services[].certificate.san_domains[]` | string[] |
| `client_access.services[].certificate.public_key_type` | string \| null |
| `client_access.services[].certificate.public_key_bits` | integer \| null |
| `client_access.services[].certificate.fingerprint_sha256` | string \| null |
| `client_access.services[].certificate.hostname_match` | boolean \| null |
| `client_access.services[].certificate.chain_valid` | boolean |
| `client_access.services[].certificate.chain_error` | string \| null |
| `client_access.services[].chain_depth` | integer |
| `client_access.services[].error` | string \| null |
| `client_access.reachable_service_count` | integer |
| `client_access.secure_service_count` | integer |
| `autodiscover` | object |
| `autodiscover.provider_hint` | object |
| `autodiscover.provider_hint.id` | string |
| `autodiscover.provider_hint.name` | string |
| `autodiscover.mx_records[]` | string[] |
| `autodiscover.srv` | object |
| `autodiscover.srv.autodiscover[]` | object[] |
| `autodiscover.srv.autodiscover[]` | object |
| `autodiscover.srv.autodiscover[].priority` | integer |
| `autodiscover.srv.autodiscover[].weight` | integer |
| `autodiscover.srv.autodiscover[].port` | integer |
| `autodiscover.srv.autodiscover[].target` | string |
| `autodiscover.srv.submission[]` | object[] |
| `autodiscover.srv.submission[]` | object |
| `autodiscover.srv.submission[].priority` | integer |
| `autodiscover.srv.submission[].weight` | integer |
| `autodiscover.srv.submission[].port` | integer |
| `autodiscover.srv.submission[].target` | string |
| `autodiscover.srv.submissions[]` | object[] |
| `autodiscover.srv.submissions[]` | object |
| `autodiscover.srv.submissions[].priority` | integer |
| `autodiscover.srv.submissions[].weight` | integer |
| `autodiscover.srv.submissions[].port` | integer |
| `autodiscover.srv.submissions[].target` | string |
| `autodiscover.srv.imap[]` | object[] |
| `autodiscover.srv.imap[]` | object |
| `autodiscover.srv.imap[].priority` | integer |
| `autodiscover.srv.imap[].weight` | integer |
| `autodiscover.srv.imap[].port` | integer |
| `autodiscover.srv.imap[].target` | string |
| `autodiscover.srv.imaps[]` | object[] |
| `autodiscover.srv.imaps[]` | object |
| `autodiscover.srv.imaps[].priority` | integer |
| `autodiscover.srv.imaps[].weight` | integer |
| `autodiscover.srv.imaps[].port` | integer |
| `autodiscover.srv.imaps[].target` | string |
| `autodiscover.srv.pop3[]` | object[] |
| `autodiscover.srv.pop3[]` | object |
| `autodiscover.srv.pop3[].priority` | integer |
| `autodiscover.srv.pop3[].weight` | integer |
| `autodiscover.srv.pop3[].port` | integer |
| `autodiscover.srv.pop3[].target` | string |
| `autodiscover.srv.pop3s[]` | object[] |
| `autodiscover.srv.pop3s[]` | object |
| `autodiscover.srv.pop3s[].priority` | integer |
| `autodiscover.srv.pop3s[].weight` | integer |
| `autodiscover.srv.pop3s[].port` | integer |
| `autodiscover.srv.pop3s[].target` | string |
| `autodiscover.thunderbird_autoconfig` | object |
| `autodiscover.thunderbird_autoconfig.subdomain` | object |
| `autodiscover.thunderbird_autoconfig.subdomain.url` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.status_code` | integer \| null |
| `autodiscover.thunderbird_autoconfig.subdomain.content_type` | string \| null |
| `autodiscover.thunderbird_autoconfig.subdomain.final_url` | string \| null |
| `autodiscover.thunderbird_autoconfig.subdomain.redirect_count` | integer |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[]` | object[] |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[]` | object |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[].type` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[].hostname` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[].port` | integer |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[].socket_type` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.incoming[].username` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[]` | object[] |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[]` | object |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[].type` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[].hostname` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[].port` | integer |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[].socket_type` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.outgoing[].username` | string |
| `autodiscover.thunderbird_autoconfig.subdomain.error` | string \| null |
| `autodiscover.thunderbird_autoconfig.well_known` | object |
| `autodiscover.thunderbird_autoconfig.well_known.url` | string |
| `autodiscover.thunderbird_autoconfig.well_known.status_code` | integer \| null |
| `autodiscover.thunderbird_autoconfig.well_known.content_type` | string \| null |
| `autodiscover.thunderbird_autoconfig.well_known.final_url` | string \| null |
| `autodiscover.thunderbird_autoconfig.well_known.redirect_count` | integer |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[]` | object[] |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[]` | object |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[].type` | string |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[].hostname` | string |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[].port` | integer |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[].socket_type` | string |
| `autodiscover.thunderbird_autoconfig.well_known.incoming[].username` | string |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[]` | object[] |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[]` | object |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[].type` | string |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[].hostname` | string |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[].port` | integer |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[].socket_type` | string |
| `autodiscover.thunderbird_autoconfig.well_known.outgoing[].username` | string |
| `autodiscover.thunderbird_autoconfig.well_known.error` | string \| null |
| `autodiscover.outlook_autodiscover` | object |
| `autodiscover.outlook_autodiscover.url` | string |
| `autodiscover.outlook_autodiscover.status_code` | integer \| null |
| `autodiscover.outlook_autodiscover.content_type` | string \| null |
| `autodiscover.outlook_autodiscover.final_url` | string \| null |
| `autodiscover.outlook_autodiscover.redirect_count` | integer |
| `autodiscover.outlook_autodiscover.auth_required` | boolean \| null |
| `autodiscover.outlook_autodiscover.error` | string \| null |
| `autodiscover.recommended[]` | object[] |
| `autodiscover.recommended[]` | object |
| `autodiscover.recommended[].service` | string |
| `autodiscover.recommended[].host` | string |
| `autodiscover.recommended[].port` | integer |
| `autodiscover.recommended[].tls_mode` | string |
| `autodiscover.recommended[].source` | string |
| `edge_summary` | object |
| `edge_summary.relay_configured` | boolean |
| `edge_summary.evidence_sources[]` | string[] |
| `edge_summary.spf_lookup_count` | integer \| null |
| `edge_summary.spf_lookup_limit_exceeded` | boolean |
| `edge_summary.dkim_valid_selector_count` | integer |
| `edge_summary.dkim_weak_selector_count` | integer |
| `edge_summary.dkim_revoked_selector_count` | integer |
| `edge_summary.providers_detected[]` | string[] |
| `edge_summary.mta_sts_enforced` | boolean |
| `edge_summary.tls_rpt_configured` | boolean |
| `edge_summary.bimi_logo_verified` | boolean \| null |
| `edge_summary.vmc_certificate_valid` | boolean \| null |
| `edge_summary.client_access_reachable_services` | integer \| null |
| `edge_summary.client_access_secure_services` | integer \| null |
| `edge_summary.autodiscover_recommendation_count` | integer \| null |
| `provider_selector_recommendations[]` | object[] |
| `provider_selector_recommendations[]` | object |
| `provider_selector_recommendations[].provider` | string |
| `provider_selector_recommendations[].selectors[]` | string[] |
| `provider_selector_recommendations[].source` | string |
| `provider_selector_recommendations[].checked_selectors[]` | string[] |
| `provider_selector_recommendations[].found_selectors[]` | string[] |
| `provider_selector_recommendations[].missing_selectors[]` | string[] |
| `grade` | string \| null |
| `checks_unknown` | integer |
| `score_confidence` | string |
| `notes[]` | string[] |

#### Solicitud de ejemplo

```bash
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/email-auth?domain=example.com&selectors=google%2Cselector1%2Csendgrid"
```

```javascript
const response = await fetch("https://domscan.net/v1/email-auth?domain=example.com&selectors=google%2Cselector1%2Csendgrid", {
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.get(
    "https://domscan.net/v1/email-auth?domain=example.com&selectors=google%2Cselector1%2Csendgrid",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())
```

```go
package main

func main() {
	req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/email-auth?domain=example.com&selectors=google%2Cselector1%2Csendgrid", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/email-auth?domain=example.com&selectors=google%2Cselector1%2Csendgrid")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")

#### Respuesta de ejemplo

```json
{
  "domain": "google.com",
  "spf": {
    "record": "v=spf1 include:_spf.google.com ~all",
    "lookup_estimate": 1,
    "includes": [
      "_spf.google.com"
    ],
    "redirect": null,
    "macros_present": false,
    "macro_references": [],
    "lookup_walk_count": 1,
    "lookup_limit_exceeded": false,
    "walk": [
      {
        "domain": "google.com",
        "depth": 0,
        "record": "v=spf1 include:_spf.google.com ~all",
        "mechanisms": [
          "include:_spf.google.com",
          "~all"
        ],
        "includes": [
          "_spf.google.com"
        ],
        "redirect": null,
        "direct_lookup_count": 1,
        "total_lookup_count": 1,
        "macros_present": false,
        "macro_references": [],
        "multiple_records": 1
      }
    ],
    "walk_errors": [],
    "lookup_tree": {
      "root_domain": "google.com",
      "node_count": 1,
      "max_depth": 0,
      "cycles_detected": [],
      "nodes": [
        {
          "domain": "google.com",
          "depth": 0,
          "status": "present",
          "direct_lookup_count": 1,
          "total_lookup_count": 1,
          "includes": [
            "_spf.google.com"
          ],
          "redirect": null,
          "mechanisms": [
            "include:_spf.google.com",
            "~all"
          ],
          "errors": []
        }
      ],
      "edges": [
        {
          "from": "google.com",
          "to": "_spf.google.com",
          "type": "include"
        }
      ]
    }
  },
  "dkim": [
    {
      "selector": "google",
      "record": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A",
      "key_type": "rsa",
      "key_size": 2048
    }
  ],
  "dkim_audit": {
    "selectors_checked": [
      "google",
      "default",
      "selector1",
      "selector2"
    ],
    "selectors_found": [
      {
        "selector": "google",
        "dns_name": "google._domainkey.google.com",
        "record": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A",
        "record_type": "TXT",
        "cname_targets": [],
        "provider_hint": "Google Workspace",
        "key_type": "rsa",
        "key_size": 2048,
        "valid": true,
        "revoked": false,
        "weak": false,
        "hash_algorithms": [
          "sha256"
        ],
        "service_type": "email",
        "flags": [
          "s"
        ],
        "issues": []
      }
    ],
    "total_found": 1,
    "providers_detected": [
      "Google Workspace"
    ],
    "valid_selector_count": 1,
    "weak_selector_count": 0,
    "revoked_selector_count": 0
  },
  "bimi": {
    "exists": true,
    "record": "v=BIMI1; l=https://example.com/logo.svg; a=https://example.com/vmc.pem",
    "valid": true,
    "logo_url": "https://example.com/logo.svg",
    "authority_url": "https://example.com/vmc.pem",
    "logo_fetch_ok": true,
    "logo_http_status": 200,
    "logo_content_type": "image/svg+xml",
    "logo_bytes": 2048,
    "logo_svg_detected": true,
    "vmc_present": true,
    "vmc_fetched": true,
    "vmc_http_status": 200,
    "vmc_content_type": "application/x-pem-file",
    "vmc_certificate_valid": true,
    "vmc_subject": "/CN=Example Inc VMC",
    "vmc_issuer": "/CN=Example Issuer",
    "vmc_not_before": "2026-01-01T00:00:00Z",
    "vmc_not_after": "2027-01-01T00:00:00Z",
    "vmc_days_to_expiry": 258,
    "vmc_fingerprint_sha256": "AA:BB:CC:DD",
    "vmc_san_domains": [
      "google.com"
    ],
    "errors": []
  },
  "dmarc": {
    "record": "v=DMARC1; p=reject; rua=mailto:mailauth-reports@google.com",
    "tags": {
      "v": "DMARC1",
      "p": "reject",
      "rua": "mailto:mailauth-reports@google.com"
    }
  },
  "mta_sts": {
    "exists": true,
    "record": "v=STSv1; id=2024010101Z",
    "valid": true,
    "policy_id": "2024010101Z",
    "policy_fetch_ok": true,
    "policy_http_status": 200,
    "mode": "enforce",
    "max_age": 86400,
    "mx_hosts": [
      "*.google.com"
    ],
    "mx_records": [
      "aspmx.l.google.com"
    ],
    "policy_matches_mx": true,
    "uncovered_mx": [],
    "errors": []
  },
  "tls_rpt": {
    "exists": true,
    "record": "v=TLSRPTv1; rua=mailto:sts-reports@google.com",
    "valid": true,
    "rua": [
      "mailto:sts-reports@google.com"
    ],
    "errors": []
  },
  "client_access": {
    "provider_hint": {
      "id": "google_workspace",
      "name": "Google Workspace"
    },
    "mx_records": [
      "aspmx.l.google.com"
    ],
    "services": [
      {
        "service": "imap",
        "host": "imap.gmail.com",
        "port": 993,
        "source": "provider_default",
        "priority": null,
        "weight": null,
        "tls_mode": "implicit",
        "reachable": true,
        "tls_negotiated": true,
        "starttls_offered": null,
        "protocol": "TLSv1.3",
        "cipher": "TLS_AES_256_GCM_SHA384",
        "certificate": {
          "subject": "/CN=imap.gmail.com",
          "issuer": "/CN=WR2",
          "not_before": "2026-01-01T00:00:00Z",
          "not_after": "2026-07-01T00:00:00Z",
          "days_to_expiry": 70,
          "expired": false,
          "san_domains": [
            "imap.gmail.com"
          ],
          "public_key_type": "EC",
          "public_key_bits": 256,
          "fingerprint_sha256": "CC:DD:EE:FF",
          "hostname_match": true,
          "chain_valid": true,
          "chain_error": null
        },
        "chain_depth": 2,
        "error": null
      }
    ],
    "reachable_service_count": 1,
    "secure_service_count": 1
  },
  "autodiscover": {
    "provider_hint": {
      "id": "google_workspace",
      "name": "Google Workspace"
    },
    "mx_records": [
      "aspmx.l.google.com"
    ],
    "srv": {
      "autodiscover": [],
      "submission": [],
      "submissions": [],
      "imap": [],
      "imaps": [],
      "pop3": [],
      "pop3s": []
    },
    "thunderbird_autoconfig": {
      "subdomain": {
        "url": "https://autoconfig.google.com/mail/config-v1.1.xml?emailaddress=postmaster%40google.com",
        "status_code": 404,
        "content_type": "text/html",
        "final_url": "https://autoconfig.google.com/mail/config-v1.1.xml?emailaddress=postmaster%40google.com",
        "redirect_count": 0,
        "incoming": [],
        "outgoing": [],
        "error": null
      },
      "well_known": {
        "url": "https://google.com/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=postmaster%40google.com",
        "status_code": 200,
        "content_type": "application/xml",
        "final_url": "https://google.com/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=postmaster%40google.com",
        "redirect_count": 0,
        "incoming": [
          {
            "type": "imap",
            "hostname": "imap.gmail.com",
            "port": 993,
            "socket_type": "SSL"
          }
        ],
        "outgoing": [
          {
            "type": "smtp",
            "hostname": "smtp.gmail.com",
            "port": 587,
            "socket_type": "STARTTLS"
          }
        ],
        "error": null
      }
    },
    "outlook_autodiscover": {
      "url": "https://autodiscover.google.com/autodiscover/autodiscover.xml",
      "status_code": 401,
      "content_type": "text/html",
      "final_url": "https://autodiscover.google.com/autodiscover/autodiscover.xml",
      "redirect_count": 0,
      "auth_required": true,
      "error": null
    },
    "recommended": [
      {
        "service": "imap",
        "host": "imap.gmail.com",
        "port": 993,
        "tls_mode": "implicit",
        "source": "provider_default"
      }
    ]
  },
  "edge_summary": {
    "relay_configured": true,
    "evidence_sources": [
      "spf_walk",
      "mail_policies",
      "bimi_audit",
      "dkim_audit",
      "mail_client_access",
      "mail_autodiscover"
    ],
    "spf_lookup_count": 1,
    "spf_lookup_limit_exceeded": false,
    "dkim_valid_selector_count": 1,
    "dkim_weak_selector_count": 0,
    "dkim_revoked_selector_count": 0,
    "providers_detected": [
      "Google Workspace"
    ],
    "mta_sts_enforced": true,
    "tls_rpt_configured": true,
    "bimi_logo_verified": true,
    "vmc_certificate_valid": true,
    "client_access_reachable_services": 1,
    "client_access_secure_services": 1,
    "autodiscover_recommendation_count": 1
  },
  "provider_selector_recommendations": [
    {
      "provider": "Google Workspace",
      "selectors": [
        "google",
        "20230601",
        "20210112"
      ],
      "source": "detected",
      "checked_selectors": [
        "google"
      ],
      "found_selectors": [
        "google"
      ],
      "missing_selectors": [
        "20230601",
        "20210112"
      ]
    }
  ],
  "grade": "A",
  "notes": []
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `429` Demasiadas solicitudes

POST /v1/tools/spf/build Créditos: 1

#### Parámetros del cuerpo

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| include | string[] | opcional |
| ip4 | string[] | opcional |
| ip6 | string[] | opcional |
| a | boolean | opcional |
| mx | boolean | opcional |
| redirect | string | opcional |
| all | string Valores permitidos `pass`, `fail`, `softfail`, `neutral` | obligatorio |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `record` | string |
| `dns_name` | string |
| `record_type` | string |
| `length` | integer |
| `dns_lookups` | integer |
| `valid` | boolean |
| `warnings[]` | string[] |
| `explanation` | object |

#### Solicitud de ejemplo

```bash
curl -X POST "https://domscan.net/v1/tools/spf/build" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "include": [
    "_spf.google.com"
  ],
  "ip4": [
    "192.0.2.0/24"
  ],
  "mx": true,
  "all": "softfail"
}'
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/spf/build", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "include": [
      "_spf.google.com"
    ],
    "ip4": [
      "192.0.2.0/24"
    ],
    "mx": true,
    "all": "softfail"
  }),
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.post(
    "https://domscan.net/v1/tools/spf/build",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "include": [
            "_spf.google.com",
        ],
        "ip4": [
            "192.0.2.0/24",
        ],
        "mx": True,
        "all": "softfail",
    },
)
print(response.json())
```

```go
package main

func main() {
	body := strings.NewReader(`{
	  "include": [
	    "_spf.google.com"
	  ],
	  "ip4": [
	    "192.0.2.0/24"
	  ],
	  "mx": true,
	  "all": "softfail"
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/tools/spf/build", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/spf/build")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "include" => [
    "_spf.google.com"
  ],
  "ip4" => [
    "192.0.2.0/24"
  ],
  "mx" => true,
  "all" => "softfail"
})

#### Respuesta de ejemplo

```json
{
  "record": "example",
  "dns_name": "example",
  "record_type": "domain",
  "length": 1,
  "dns_lookups": 1,
  "valid": true,
  "warnings": [
    "example"
  ],
  "explanation": {}
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `409` HTTP 409
- `422` HTTP 422
- `429` Demasiadas solicitudes

POST /v1/tools/spf/validate Créditos: 1

#### Parámetros del cuerpo

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| record | string | opcional |
| domain | string | opcional |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `record` | string \| null |
| `valid` | boolean |
| `version` | string \| null |
| `mechanisms[]` | object[] |
| `mechanisms[]` | object |
| `mechanisms[].qualifier` | string |
| `mechanisms[].mechanism` | string |
| `mechanisms[].value` | string |
| `mechanisms[].description` | string |
| `dns_lookups` | integer |
| `max_lookups` | integer |
| `lookup_limit_exceeded` | boolean |
| `policy` | string \| null |
| `includes[]` | string[] |
| `ips[]` | string[] |
| `issues[]` | string[] |
| `warnings[]` | string[] |
| `error` | string |

#### Solicitud de ejemplo

```bash
curl -X POST "https://domscan.net/v1/tools/spf/validate" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "domain": "example.com",
  "record": "v=spf1 include:_spf.google.com ip4:192.0.2.0/24 ~all"
}'
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/spf/validate", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "domain": "example.com",
    "record": "v=spf1 include:_spf.google.com ip4:192.0.2.0/24 ~all"
  }),
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.post(
    "https://domscan.net/v1/tools/spf/validate",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "domain": "example.com",
        "record": "v=spf1 include:_spf.google.com ip4:192.0.2.0/24 ~all",
    },
)
print(response.json())
```

```go
package main

func main() {
	body := strings.NewReader(`{
	  "domain": "example.com",
	  "record": "v=spf1 include:_spf.google.com ip4:192.0.2.0/24 ~all"
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/tools/spf/validate", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/spf/validate")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "domain" => "example.com",
  "record" => "v=spf1 include:_spf.google.com ip4:192.0.2.0/24 ~all"
})

#### Respuesta de ejemplo

```json
{
  "domain": "example.com",
  "record": "v=spf1 include:_spf.google.com ip4:192.0.2.0/24 ~all",
  "valid": true,
  "version": "spf1",
  "mechanisms": [
    {
      "qualifier": "+",
      "mechanism": "include",
      "value": "_spf.google.com",
      "description": "Include SPF from _spf.google.com"
    },
    {
      "qualifier": "+",
      "mechanism": "ip4",
      "value": "192.0.2.0/24",
      "description": "IPv4 address/range 192.0.2.0/24"
    },
    {
      "qualifier": "~",
      "mechanism": "all",
      "description": "Default policy: softfail"
    }
  ],
  "dns_lookups": 1,
  "max_lookups": 10,
  "lookup_limit_exceeded": false,
  "policy": "softfail",
  "includes": [
    "_spf.google.com"
  ],
  "ips": [
    "192.0.2.0/24"
  ],
  "issues": [],
  "warnings": []
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `409` HTTP 409
- `422` HTTP 422
- `429` Demasiadas solicitudes

POST /v1/tools/spf/flatten Créditos: 2

#### Parámetros del cuerpo

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| domain | string | obligatorio |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `original_record` | string |
| `flattened_record` | string |
| `original_lookups` | integer |
| `flattened_lookups` | integer |
| `resolved_ips` | object |
| `resolved_ips.ip4[]` | string[] |
| `resolved_ips.ip6[]` | string[] |
| `includes_resolved[]` | object[] |
| `includes_resolved[]` | object |
| `includes_resolved[].include` | string |
| `includes_resolved[].resolved_to[]` | string[] |
| `warnings[]` | string[] |

#### Solicitud de ejemplo

```bash
curl -X POST "https://domscan.net/v1/tools/spf/flatten" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "domain": "example.com"
}'
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/spf/flatten", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "domain": "example.com"
  }),
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.post(
    "https://domscan.net/v1/tools/spf/flatten",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "domain": "example.com",
    },
)
print(response.json())
```

```go
package main

func main() {
	body := strings.NewReader(`{
	  "domain": "example.com"
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/tools/spf/flatten", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/spf/flatten")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "domain" => "example.com"
})

#### Respuesta de ejemplo

```json
{
  "domain": "example.com",
  "original_record": "example",
  "flattened_record": "example",
  "original_lookups": 1,
  "flattened_lookups": 1,
  "resolved_ips": {
    "ip4": [
      "192.0.2.0/24"
    ],
    "ip6": [
      "2001:db8::/32"
    ]
  },
  "includes_resolved": [
    {
      "include": "example",
      "resolved_to": [
        "example"
      ]
    }
  ],
  "warnings": [
    "example"
  ]
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `409` HTTP 409
- `422` HTTP 422
- `429` Demasiadas solicitudes

POST /v1/tools/dmarc/build Créditos: 1

#### Parámetros del cuerpo

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| policy | string Valores permitidos `none`, `quarantine`, `reject` | obligatorio |
| subdomain_policy | string Valores permitidos `none`, `quarantine`, `reject` | opcional |
| percentage | integer | opcional |
| rua | string[] | opcional |
| ruf | string[] | opcional |
| adkim | string Valores permitidos `relaxed`, `strict` | opcional |
| aspf | string Valores permitidos `relaxed`, `strict` | opcional |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `record` | string |
| `dns_name` | string |
| `record_type` | string |
| `valid` | boolean |
| `explanation` | object |

#### Solicitud de ejemplo

```bash
curl -X POST "https://domscan.net/v1/tools/dmarc/build" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "policy": "quarantine",
  "subdomain_policy": "quarantine",
  "percentage": 100,
  "rua": [
    "mailto:dmarc@example.com"
  ],
  "adkim": "relaxed",
  "aspf": "relaxed"
}'
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/dmarc/build", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "policy": "quarantine",
    "subdomain_policy": "quarantine",
    "percentage": 100,
    "rua": [
      "mailto:dmarc@example.com"
    ],
    "adkim": "relaxed",
    "aspf": "relaxed"
  }),
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.post(
    "https://domscan.net/v1/tools/dmarc/build",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "policy": "quarantine",
        "subdomain_policy": "quarantine",
        "percentage": 100,
        "rua": [
            "mailto:dmarc@example.com",
        ],
        "adkim": "relaxed",
        "aspf": "relaxed",
    },
)
print(response.json())
```

```go
package main

func main() {
	body := strings.NewReader(`{
	  "policy": "quarantine",
	  "subdomain_policy": "quarantine",
	  "percentage": 100,
	  "rua": [
	    "mailto:dmarc@example.com"
	  ],
	  "adkim": "relaxed",
	  "aspf": "relaxed"
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/tools/dmarc/build", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/dmarc/build")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "policy" => "quarantine",
  "subdomain_policy" => "quarantine",
  "percentage" => 100,
  "rua" => [
    "mailto:dmarc@example.com"
  ],
  "adkim" => "relaxed",
  "aspf" => "relaxed"
})

#### Respuesta de ejemplo

```json
{
  "record": "example",
  "dns_name": "example",
  "record_type": "domain",
  "valid": true,
  "explanation": {}
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `409` HTTP 409
- `422` HTTP 422
- `429` Demasiadas solicitudes

POST /v1/tools/dmarc/validate Créditos: 1

#### Parámetros del cuerpo

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| record | string | opcional |
| domain | string | opcional |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `record` | string \| null |
| `valid` | boolean |
| `version` | string \| null |
| `policy` | string \| null |
| `subdomain_policy` | string \| null |
| `percentage` | integer |
| `rua[]` | string[] |
| `ruf[]` | string[] |
| `adkim` | string |
| `aspf` | string |
| `fo` | string |
| `ri` | integer |
| `strength` | string |
| `issues[]` | string[] |
| `warnings[]` | string[] |
| `error` | string |

#### Solicitud de ejemplo

```bash
curl -X POST "https://domscan.net/v1/tools/dmarc/validate" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "domain": "example.com",
  "record": "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com"
}'
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/dmarc/validate", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "domain": "example.com",
    "record": "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com"
  }),
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.post(
    "https://domscan.net/v1/tools/dmarc/validate",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "domain": "example.com",
        "record": "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com",
    },
)
print(response.json())
```

```go
package main

func main() {
	body := strings.NewReader(`{
	  "domain": "example.com",
	  "record": "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com"
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/tools/dmarc/validate", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/dmarc/validate")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "domain" => "example.com",
  "record" => "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com"
})

#### Respuesta de ejemplo

```json
{
  "domain": "example.com",
  "record": "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; ruf=mailto:forensics@example.com",
  "valid": true,
  "version": "DMARC1",
  "policy": "quarantine",
  "subdomain_policy": null,
  "percentage": 50,
  "rua": [
    "mailto:dmarc@example.com"
  ],
  "ruf": [
    "mailto:forensics@example.com"
  ],
  "adkim": "relaxed",
  "aspf": "relaxed",
  "fo": "0",
  "ri": 86400,
  "strength": "weak",
  "issues": [],
  "warnings": [
    "DMARC only applies to 50% of messages"
  ]
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `409` HTTP 409
- `422` HTTP 422
- `429` Demasiadas solicitudes

GET /v1/tools/dkim/check Créditos: 1

#### Parámetros de consulta

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| domain | string | obligatorio |
| selector | string | obligatorio |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `selector` | string |
| `dns_name` | string |
| `exists` | boolean |
| `valid` | boolean |
| `record` | string |
| `version` | string |
| `key_type` | string |
| `key_data` | string |
| `key_size` | integer |
| `flags[]` | string[] |
| `hash_algorithms[]` | string[] |
| `service_type` | string |
| `issues[]` | string[] |

#### Solicitud de ejemplo

```bash
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/tools/dkim/check?domain=example.com&selector=google"
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/dkim/check?domain=example.com&selector=google", {
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.get(
    "https://domscan.net/v1/tools/dkim/check?domain=example.com&selector=google",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())
```

```go
package main

func main() {
	req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/tools/dkim/check?domain=example.com&selector=google", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/dkim/check?domain=example.com&selector=google")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")

#### Respuesta de ejemplo

```json
{
  "domain": "example.com",
  "selector": "s1",
  "dns_name": "s1._domainkey.example.com",
  "exists": true,
  "valid": true,
  "record": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmJozfC9DIeQ/D61fUDgQO/UpGyaMcxSRagnXuEbbwljO4pJcrtPIJyYW7Y8dmX3XZh1V+tvL7zhYPAYHhJ2//YGSetg20T1xvyy1s4Mfa3JPKFNvq+HYe2/ag/rz8Cl7I0rn7ET0BQc/iKxiptIlgALWdYBNiQBsLCBRsGjQWzzQh1puVIm2U+LTp9qQq42DVnkTJ/kOT2z2QjYTkGeCU19sjXi04gQu5XV7iXF7IZjLbMxE4OnUWRwlAr4n0H/PRGfuteB5KF/COZZ9fP0HKpIUjF8k5YJsjbKEiPA2sL/vKS90nsvPrWsDguT8mAPxIc2wrvYCDtL/O2fJTMQlwQIDAQAB",
  "version": "DKIM1",
  "key_type": "rsa",
  "key_data": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmJozfC9DIeQ/D61fUDgQO/UpGyaMcxSRagnXuEbbwljO4pJcrtPIJyYW7Y8dmX3XZh1V+tvL7zhYPAYHhJ2//YGSetg20T1xvyy1s4Mfa3JPKFNvq+HYe2/ag/rz8Cl7I0rn7ET0BQc/iKxiptIlgALWdYBNiQBsLCBRsGjQWzzQh1puVIm2U+LTp9qQq42DVnkTJ/kOT2z2QjYTkGeCU19sjXi04gQu5XV7iXF7IZjLbMxE4OnUWRwlAr4n0H/PRGfuteB5KF/COZZ9fP0HKpIUjF8k5YJsjbKEiPA2sL/vKS90nsvPrWsDguT8mAPxIc2wrvYCDtL/O2fJTMQlwQIDAQAB",
  "key_size": 2048,
  "issues": []
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `429` Demasiadas solicitudes

GET /v1/tools/dkim/discover Créditos: 2

#### Parámetros de consulta

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| domain | string | obligatorio |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `selectors_checked[]` | string[] |
| `selectors_found[]` | object[] |
| `selectors_found[]` | object |
| `selectors_found[].selector` | string |
| `selectors_found[].dns_name` | string |
| `selectors_found[].exists` | boolean |
| `selectors_found[].record` | string \| null |
| `selectors_found[].record_type` | string \| null |
| `selectors_found[].cname_targets[]` | string[] |
| `selectors_found[].key_type` | string \| null |
| `selectors_found[].key_size` | integer \| null |
| `selectors_found[].provider_hint` | string \| null |
| `selectors_found[].valid` | boolean |
| `selectors_found[].revoked` | boolean |
| `selectors_found[].weak` | boolean |
| `selectors_found[].hash_algorithms[]` | string[] |
| `selectors_found[].service_type` | string \| null |
| `selectors_found[].flags[]` | string[] |
| `selectors_found[].issues[]` | string[] |
| `total_found` | integer |
| `common_providers_detected[]` | string[] |
| `providers_detected[]` | string[] |
| `valid_selector_count` | integer |
| `weak_selector_count` | integer |
| `revoked_selector_count` | integer |

#### Solicitud de ejemplo

```bash
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/tools/dkim/discover?domain=example.com"
```

```javascript
const response = await fetch("https://domscan.net/v1/tools/dkim/discover?domain=example.com", {
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.get(
    "https://domscan.net/v1/tools/dkim/discover?domain=example.com",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())
```

```go
package main

func main() {
	req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/tools/dkim/discover?domain=example.com", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/tools/dkim/discover?domain=example.com")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")

#### Respuesta de ejemplo

```json
{
  "domain": "example.com",
  "selectors_checked": [
    "example"
  ],
  "selectors_found": [
    {
      "selector": "default",
      "dns_name": "example",
      "exists": true,
      "record": "example",
      "record_type": "TXT",
      "cname_targets": [
        "example"
      ],
      "key_type": "domain",
      "key_size": 1,
      "provider_hint": "example",
      "valid": true,
      "revoked": false,
      "weak": false,
      "hash_algorithms": [
        "example"
      ],
      "service_type": "domain",
      "flags": [
        "example"
      ],
      "issues": [
        "example"
      ]
    }
  ],
  "total_found": 1,
  "common_providers_detected": [
    "example"
  ],
  "providers_detected": [
    "example"
  ],
  "valid_selector_count": 1,
  "weak_selector_count": 1,
  "revoked_selector_count": 1
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `429` Demasiadas solicitudes

GET /v1/email/compliance Créditos: 6

#### Parámetros de consulta

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| domain | string | obligatorio |
| selectors | string | opcional |
| providers | string | opcional |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `domain` | string |
| `status` | string |
| `score` | integer |
| `grade` | string |
| `checks_unknown` | integer |
| `score_confidence` | string |
| `provider_readiness` | object |
| `provider_readiness.google` | object |
| `provider_readiness.google.provider` | string |
| `provider_readiness.google.display_name` | string |
| `provider_readiness.google.status` | string |
| `provider_readiness.google.dns_visible_status` | string |
| `provider_readiness.google.requirements[]` | object[] |
| `provider_readiness.google.requirements[]` | object |
| `provider_readiness.google.requirements[].id` | string |
| `provider_readiness.google.requirements[].label` | string |
| `provider_readiness.google.requirements[].status` | string |
| `provider_readiness.google.requirements[].severity` | string |
| `provider_readiness.google.requirements[].category` | string |
| `provider_readiness.google.requirements[].evidence` | string |
| `provider_readiness.google.requirements[].recommendation` | string |
| `provider_readiness.google.verification_required[]` | string[] |
| `provider_readiness.google.notes[]` | string[] |
| `provider_readiness.microsoft` | object |
| `provider_readiness.microsoft.provider` | string |
| `provider_readiness.microsoft.display_name` | string |
| `provider_readiness.microsoft.status` | string |
| `provider_readiness.microsoft.dns_visible_status` | string |
| `provider_readiness.microsoft.requirements[]` | object[] |
| `provider_readiness.microsoft.requirements[]` | object |
| `provider_readiness.microsoft.requirements[].id` | string |
| `provider_readiness.microsoft.requirements[].label` | string |
| `provider_readiness.microsoft.requirements[].status` | string |
| `provider_readiness.microsoft.requirements[].severity` | string |
| `provider_readiness.microsoft.requirements[].category` | string |
| `provider_readiness.microsoft.requirements[].evidence` | string |
| `provider_readiness.microsoft.requirements[].recommendation` | string |
| `provider_readiness.microsoft.verification_required[]` | string[] |
| `provider_readiness.microsoft.notes[]` | string[] |
| `summary` | object |
| `summary.authentication` | object |
| `summary.transport` | object |
| `summary.dns_security` | object |
| `summary.brand_trust` | object |
| `action_items[]` | object[] |
| `action_items[]` | object |
| `action_items[].priority` | string |
| `action_items[].category` | string |
| `action_items[].title` | string |
| `action_items[].detail` | string |
| `action_items[].fix` | string |
| `evidence` | object |
| `evidence.email_auth` | object |
| `evidence.dns_security` | object |
| `proxy` | object |
| `proxy.configured` | boolean |
| `proxy.enriched` | boolean |
| `proxy.checks[]` | string[] |
| `limitations[]` | string[] |
| `checked_at` | string |
| `check_duration_ms` | integer |

#### Solicitud de ejemplo

```bash
curl -H "X-API-Key: $DOMSCAN_API_KEY" "https://domscan.net/v1/email/compliance?domain=example.com&selectors=google%2Cselector1%2Csendgrid&providers=google%2Cmicrosoft"
```

```javascript
const response = await fetch("https://domscan.net/v1/email/compliance?domain=example.com&selectors=google%2Cselector1%2Csendgrid&providers=google%2Cmicrosoft", {
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY },
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.get(
    "https://domscan.net/v1/email/compliance?domain=example.com&selectors=google%2Cselector1%2Csendgrid&providers=google%2Cmicrosoft",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
)
print(response.json())
```

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest(http.MethodGet, "https://domscan.net/v1/email/compliance?domain=example.com&selectors=google%2Cselector1%2Csendgrid&providers=google%2Cmicrosoft", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/email/compliance?domain=example.com&selectors=google%2Cselector1%2Csendgrid&providers=google%2Cmicrosoft")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")

#### Respuesta de ejemplo

```json
{
  "domain": "example.com",
  "status": "warn",
  "score": 82,
  "grade": "B",
  "provider_readiness": {
    "google": {
      "provider": "google",
      "display_name": "Google/Gmail bulk sender readiness",
      "status": "pass",
      "dns_visible_status": "pass",
      "requirements": [
        {
          "id": "google_spf",
          "label": "SPF must be configured for bulk senders",
          "status": "pass",
          "severity": "critical",
          "category": "dns",
          "evidence": "SPF policy: softfail",
          "recommendation": "Publish one valid SPF record that covers every approved sending platform."
        },
        {
          "id": "google_alignment",
          "label": "From domain must align with either SPF or DKIM on live messages",
          "status": "unknown",
          "severity": "high",
          "category": "message",
          "evidence": "Alignment requires Authentication-Results from a real sent message",
          "recommendation": "Send a test message and verify SPF or DKIM alignment."
        }
      ],
      "verification_required": [
        "From domain must align with either SPF or DKIM on live messages",
        "Outbound mail must be transmitted over TLS"
      ],
      "notes": [
        "Status is based on DNS-visible controls. Live sending requirements still need message-header and sender-platform verification."
      ]
    },
    "microsoft": {
      "provider": "microsoft",
      "display_name": "Microsoft Outlook.com high-volume sender readiness",
      "status": "pass",
      "dns_visible_status": "pass",
      "requirements": [],
      "verification_required": [
        "DMARC must align with either SPF or DKIM"
      ],
      "notes": [
        "Status is based on DNS-visible controls. Live sending requirements still need message-header and sender-platform verification."
      ]
    }
  },
  "summary": {
    "authentication": {
      "spf": {
        "status": "pass",
        "record": "v=spf1 include:_spf.example.com ~all",
        "policy": "softfail",
        "lookup_count": 3,
        "lookup_limit_exceeded": false
      },
      "dkim": {
        "status": "pass",
        "selectors_checked": [
          "google",
          "selector1",
          "sendgrid"
        ],
        "selectors_found": [
          "google"
        ],
        "valid_selector_count": 1,
        "weak_selector_count": 0,
        "revoked_selector_count": 0,
        "providers_detected": [
          "Google Workspace"
        ]
      },
      "dmarc": {
        "status": "warn",
        "record": "v=DMARC1; p=none; rua=mailto:dmarc@example.com",
        "policy": "none",
        "subdomain_policy": null,
        "percentage": 100,
        "rua": [
          "mailto:dmarc@example.com"
        ],
        "alignment_mode": {
          "spf": null,
          "dkim": null
        }
      }
    },
    "transport": {
      "mta_sts": {
        "status": "pass",
        "mode": "enforce",
        "policy_fetch_ok": true,
        "policy_matches_mx": true
      },
      "tls_rpt": {
        "status": "pass",
        "rua": [
          "mailto:tls@example.com"
        ]
      },
      "mx_records": [
        "aspmx.l.google.com"
      ],
      "client_access_secure_services": 1
    },
    "dns_security": {
      "dnssec": "pass",
      "caa": "pass",
      "zone_transfer": "pass",
      "authoritative_consistency": "pass",
      "blacklist": "pass"
    },
    "brand_trust": {
      "bimi": "unknown",
      "vmc": "unknown"
    }
  },
  "action_items": [
    {
      "priority": "medium",
      "category": "authentication",
      "title": "Move DMARC beyond monitoring mode",
      "detail": "DMARC is valid but still uses p=none.",
      "fix": "After reviewing aggregate reports, move to p=quarantine or p=reject."
    }
  ],
  "evidence": {
    "email_auth": {
      "spf": {
        "record": "v=spf1 include:_spf.example.com ~all"
      },
      "dmarc": {
        "record": "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
      }
    },
    "dns_security": {
      "security_score": 86,
      "security_grade": "B"
    }
  },
  "proxy": {
    "configured": true,
    "enriched": true,
    "checks": [
      "spf_walk",
      "mail_policies",
      "dkim_audit",
      "bimi_audit"
    ]
  },
  "limitations": [
    "DNS-visible checks cannot prove live message-level SPF, DKIM, DMARC alignment, RFC 5322 formatting, spam rate, or one-click unsubscribe behavior."
  ],
  "checked_at": "2026-04-26T12:00:00Z",
  "check_duration_ms": 642
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `429` Demasiadas solicitudes

POST /v1/email-auth/bulk Créditos: 3/item

#### Parámetros de consulta

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| dry_run | string Valores permitidos `true` | opcional |

#### Parámetros del cuerpo

| Parámetro | Tipo | obligatorio |
| --- | --- | --- |
| domains | string[] | obligatorio |
| selectors | string[] | opcional |

#### Campos de respuesta

| Campo | Tipo |
| --- | --- |
| `results[]` | unknown[] |
| `meta` | object |
| `meta.total` | integer |
| `meta.succeeded` | integer |
| `meta.failed` | integer |
| `meta.max_items` | integer |
| `meta.credits_per_item` | integer |
| `meta.duration_ms` | integer |

#### Solicitud de ejemplo

```bash
curl -X POST "https://domscan.net/v1/email-auth/bulk" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "domains": [
    "example.com",
    "cloudflare.com"
  ],
  "selectors": [
    "selector1",
    "selector2"
  ]
}'
```

```javascript
const response = await fetch("https://domscan.net/v1/email-auth/bulk", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "domains": [
      "example.com",
      "cloudflare.com"
    ],
    "selectors": [
      "selector1",
      "selector2"
    ]
  }),
});
const data = await response.json();
console.log(data);
```

```python
import os
import requests

response = requests.post(
    "https://domscan.net/v1/email-auth/bulk",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "domains": [
            "example.com",
            "cloudflare.com",
        ],
        "selectors": [
            "selector1",
            "selector2",
        ],
    },
)
print(response.json())
```

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	body := strings.NewReader(`{
	  "domains": [
	    "example.com",
	    "cloudflare.com"
	  ],
	  "selectors": [
	    "selector1",
	    "selector2"
	  ]
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/email-auth/bulk", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Status, string(data))
}
```

```ruby
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/email-auth/bulk")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "domains" => [
    "example.com",
    "cloudflare.com"
  ],
  "selectors" => [
    "selector1",
    "selector2"
  ]
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
puts JSON.pretty_generate(JSON.parse(response.body))
```

#### Respuesta de ejemplo

```json
{
  "results": [
    {
      "input": "example",
      "data": {}
    }
  ],
  "meta": {
    "total": 1,
    "succeeded": 1,
    "failed": 1,
    "max_items": 10,
    "credits_per_item": 1,
    "duration_ms": 1
  }
}
```

#### Códigos de estado HTTP

- `200` OK
- `400` Solicitud incorrecta
- `401` No autorizado
- `402` Pago requerido
- `409` HTTP 409
- `422` HTTP 422
- `429` Demasiadas solicitudes
