Skip to main content
Glama

DMARKOFF — DMARC, SPF & DKIM Analytics

get_domain_source_details

Read-onlyIdempotent

Detailed per-record view of email sources for a domain with flexible grouping and filtering.

Grouping (group_by, default: "isp"): • "isp" — by ISP/provider (shows ISP, hostname, brand domain, country). Best starting point for investigation. • "ip" — by sending IP address (shows IP, ISP, PTR, country, source type) • "host" — by hostname (ip_domain_name) • "reporter" — by DMARC report sender (shows reporter organization) • "report" — one row per aggregate report: reporter, reportKey (tells two reports apart), windowStart / windowEnd (the window the report covers, UTC), reportDate (the day it is filed under), receivedAt (when it was stored), lagHours (receivedAt − windowEnd), records, total, dmarcPass, quarantined, rejected. Newest window first. Use it to see which reports a total is made of, to split sends on consecutive days, and to check whether a reporter has reported for a day yet. Every other filter but problems_only narrows this view too: a report none of whose rows match is left out, and its counts cover only the matching rows — to see which reports arrived and what each counted in full, filter by reporter alone. With that, a report that is not listed (check page and totalRecords first) was never sent — a receiver that got no mail from the domain in a window sends none —, has not arrived yet, or was dropped on arrival (an unpaid, parked or excluded domain, or one the project does not hold while it does not add domains from reports: projects_overview counts those per project as missedReports); this tool cannot tell which. reporterLag, next to the rows, says when to expect one: per reporter, reports, medianLagHours, typicalLagHours (90th percentile) and maxLagHours from window end to arrival, and latestWindowEnd — the end of the newest window it reported for this domain in the last 30 days, absent if none. The figures cover the project's reports of the last 30 days whatever the period, from every domain of the project: a reporter's figures are the same whichever of its domains is asked about, a reporter that never reported for this one is listed when it reported for another, and reporterLagScope in the answer names the project and the first day. Of the filters only reporter applies. A report for a window ending at T is due by about T + typicalLagHours: before that, a missing one is most likely still on its way; well past T + maxLagHours, it was most likely not sent or was dropped. maxLagHours is only the longest wait among the reports already in: with few reports (see reports) the figures are rough, and while reports run late (a reporter's outage, a processing backlog) one can still come after it. At most 50 reporters, those that reported for this domain first; one with no reports in 30 days is not listed. reporterLag is absent when it could not be read.

Note: with group_by=isp, the same provider may appear multiple times with different countries — this is correct (one row per provider+country combination).

Each row (except group_by=report) includes: message count, disposition, policy override, SPF/DKIM/DMARC evaluation, SPF auth details (return-path, result, scope), DKIM auth details (domain, selector, result). sourceReason / sourceReasonText — WHY the classifier put the source into known / unknown / forward, in the words the web app uses. This is the field that turns "unknown" into an action: the text says whether to hunt for the sender, fix a Return-Path, selector or SPF include, or leave a relay's damage alone. Empty on rows parsed before the classifier started recording it. The reason is decided when a report is parsed and stays with its rows: after a classifier release, rows parsed before and after it can carry different reasons for the same data until the stored rows are rewritten, so two rows that differ only in sourceReason are one source, not two. spfRecordError — the stored check of one of the domain's own SPF records that receivers cannot evaluate, on a row whose SPF failure that record explains: returnPath, evaluation, permErrorScope, failedCheck, text, fixDescription and lastChecked (the check is the record as it was then, not necessarily in the period: get_record_history shows changes). The record has to be fixed whoever sent the row — quote its fixDescription — but what it means for the row depends on failedCheck: • only_one_record_found — two SPF records: receivers differ, and our own check of the IP fails for every IP too, so the classifier cannot tell a sender the records list from a stranger and sourceReason reads no_auth_pass (identify the sender). For a sender one of the records lists (compare the IP with each of dns_check_spf's records), merging them is the whole fix; a sender the user recognises that no record lists also needs its include or ip4 in the merged record; one they do not recognise is still spoofing. Put on every failing row except forwarded and relayed ones. • any other (a syntax error, more than 10 DNS lookups, an include target without SPF, a 3rd void lookup) — strict receivers return permerror, but our check skips the broken term and ignores the limits, so it still finds the senders the record lists: put only on those rows (sourceReason spf_permerror, or dmarc_not_pass without an aligned DKIM pass on rows parsed before that reason existed) where the receiver returned permerror. A no_auth_pass row is an IP the record does not list, or lists only in the broken term: compare the IP with the record (dns_check_spf) before calling it a stranger. On rows parsed before 2026-10-13 our check stopped at the same limits, so a sender listed after the break reads no_auth_pass there and gets no spfRecordError. Forwarded and relayed rows are told apart by sourceReason (fwd_*, relay_broke_dkim); rows parsed before the reason was recorded only by sourceType, which group_by=ip alone carries. The "comment" field comes from the DMARC XML report and is populated when ARC (Authenticated Received Chain) overrides the DMARC policy — e.g. when a forwarded message would fail DMARC but ARC trusts the forwarding chain, applying a different effective policy than the p= tag in the DMARC record. Empty when no override occurred.

Dates: a report is filed under the UTC day its window begins. A reporter whose window starts at its local midnight — Seznam's starts at 22:00 UTC in summer — puts its mail a day early: a one-day period misses most of that reporter's mail of the day (filed under the day before) and takes most of the next day's (the window that starts at 22:00 UTC that day); group_by=report shows each report's window. stats_period_start equal to stats_period_end reads that one day.

The answer is {period, page, totalRecords, rows}, and reporterLag and reporterLagScope with group_by=report: period is the period actually read (start, end, days, and endClamped when the end asked for was after today).

Optional filters: source_ip, isp, ip_domain_name, eval_spf, eval_dkim, eval_dmarc, source_type, disposition, dkim_domain, dkim_selector, spf_domain, reporter. For ISP grouping set problems_only=true to see only rows with authentication failures. reporter matches the reporter's name or its brand domain, in any case, but exactly: take it from group_by=reporter over the same period. An empty answer with a reporter filter can mean the value matched no reporter, not that its reports are missing.

Use this to investigate specific sending sources, drill down into authentication failures, or analyze traffic by provider/IP/reporter/report.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "project_id": "<project_id>",
      "domain": "<domain>"
    },
    "name": "get_domain_source_details"
  }
}

Input Schema

NameRequiredDescriptionDefault
ispNofilter by ISP/provider name
pageNopage number starting from 1 (default 1)
limitNoresults per page (default 25 max 100)
domainYesthe domain name (e.g. example.com)
eval_spfNofilter by SPF evaluation: pass or fail
group_byNogrouping: isp (Provider, default) / ip (Sending IP) / host (Hostname) / reporter (DMARC Reporter) / report (one row per aggregate report)
reporterNofilter by DMARC reporter: its name or its brand domain, as group_by=reporter shows them (e.g. Mail.Ru or google.com)
eval_dkimNofilter by DKIM evaluation: pass or fail
source_ipNofilter by source IP address
eval_dmarcNofilter by DMARC evaluation: pass or fail
project_idYesthe project ID
spf_domainNofilter by SPF auth domain (return-path domain)
dispositionNofilter by disposition: none / quarantine / reject
dkim_domainNofilter by DKIM signing domain
source_typeNofilter by source type: known / unknown / forward
dkim_selectorNofilter by DKIM selector
problems_onlyNoISP grouping only: show only rows with at least one auth failure
ip_domain_nameNofilter by hostname (ip_domain_name)
stats_period_endNoend date YYYY-MM-DD, UTC, inclusive (optional, defaults to today; a later date reads up to today)
stats_period_startNostart date YYYY-MM-DD, UTC (optional, defaults to 14 days before the end; equal to the end for a single day)

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changed
    • changedInput schema / properties / group_by / description
      Previous value: -"grouping: isp (Provider, default) / ip (Sending IP) / host (Hostname) / reporter (DMARC Reporter)"New value: +"grouping: isp (Provider, default) / ip (Sending IP) / host (Hostname) / reporter (DMARC Reporter) / report (one row per aggregate report)"
    • addedInput schema / properties / reporter
      Added value: +{
      +  "description": "filter by DMARC reporter: its name or its brand domain, as group_by=reporter shows them (e.g. Mail.Ru or google.com)",
      +  "type": "string"
      +}
    • changedInput schema / properties / stats_period_end / description
      Previous value: -"end date YYYY-MM-DD (optional defaults to yesterday)"New value: +"end date YYYY-MM-DD, UTC, inclusive (optional, defaults to today; a later date reads up to today)"
    • changedInput schema / properties / stats_period_start / description
      Previous value: -"start date YYYY-MM-DD (optional defaults to 14 days ago)"New value: +"start date YYYY-MM-DD, UTC (optional, defaults to 14 days before the end; equal to the end for a single day)"
  2. First observed

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the read-only/idempotent profile, but the description goes far beyond: it explains that a missing report may be unarrived vs dropped and that the tool cannot tell which, that reason text freezes at parse time so classifier releases create split rows, that spfRecordError's meaning depends on failedCheck, and that reporterLag figures are project-wide and capped at 50 reporters. These are real behavioral constraints an agent would otherwise get wrong.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded well, with the grouping list first and usage last, but the middle is heavily over-written for a tool definition — multi-clause sentences about 2026-10-13 parse cut-offs and per-failedCheck fix instructions read more like product documentation than invocation guidance. Much of it earns its place, yet the density and length hurt scanability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description carries the return-value burden and does so explicitly: it names the answer shape ({period, page, totalRecords, rows}), the conditional reporterLag/reporterLagScope fields, and the per-row columns. For a 20-parameter tool with five groupings and several caveat-laden fields, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3, but the description adds genuine semantics the schema lacks: the meaning and output shape of each group_by value, that only reporter of the filters applies to reporterLag, that reporter matching is exact and case-insensitive so an empty result may mean a bad value rather than missing mail, that stats_period_start == stats_period_end reads one day, and that every filter except problems_only narrows the report view.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb+resource+granularity: a per-record view of email sources for a domain, with flexible grouping and filtering. The grouping enumeration and the per-row field list make the scope unmistakable, and it is clearly a drill-down counterpart to aggregate siblings like get_domain_stats or get_geo_sources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete usage guidance per grouping mode ('isp … Best starting point for investigation', 'use it to see which reports a total is made of') and closes with when to reach for the tool. What it does not do is name a specific sibling as the alternative ('for aggregate counts use get_domain_stats'), so routing between tools is still partly inferred from scope.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.