get_domain_source_details
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
| Name | Required | Description | Default |
|---|---|---|---|
| isp | No | filter by ISP/provider name | |
| page | No | page number starting from 1 (default 1) | |
| limit | No | results per page (default 25 max 100) | |
| domain | Yes | the domain name (e.g. example.com) | |
| eval_spf | No | filter by SPF evaluation: pass or fail | |
| group_by | No | grouping: isp (Provider, default) / ip (Sending IP) / host (Hostname) / reporter (DMARC Reporter) / report (one row per aggregate report) | |
| reporter | No | filter by DMARC reporter: its name or its brand domain, as group_by=reporter shows them (e.g. Mail.Ru or google.com) | |
| eval_dkim | No | filter by DKIM evaluation: pass or fail | |
| source_ip | No | filter by source IP address | |
| eval_dmarc | No | filter by DMARC evaluation: pass or fail | |
| project_id | Yes | the project ID | |
| spf_domain | No | filter by SPF auth domain (return-path domain) | |
| disposition | No | filter by disposition: none / quarantine / reject | |
| dkim_domain | No | filter by DKIM signing domain | |
| source_type | No | filter by source type: known / unknown / forward | |
| dkim_selector | No | filter by DKIM selector | |
| problems_only | No | ISP grouping only: show only rows with at least one auth failure | |
| ip_domain_name | No | filter by hostname (ip_domain_name) | |
| stats_period_end | No | end date YYYY-MM-DD, UTC, inclusive (optional, defaults to today; a later date reads up to today) | |
| stats_period_start | No | start date YYYY-MM-DD, UTC (optional, defaults to 14 days before the end; equal to the end for a single day) |