email_senders_summary
Aggregates one mailbox by sender and returns who sends the most, how much of it is unread, when they last wrote, and whether they can be unsubscribed from. Start cleanup here rather than with email_search_messages. One call replaces paging through thousands of messages, and it hands you sender addresses, which stay valid, instead of message ids, which go stale as soon as anything moves. The usual sequence: this tool to find the worst offenders, email_unsubscribe_sender to stop the ones that support it, then email_bulk_modify_messages with query 'from:<address>' to clear what already arrived. Show the user the counts from this tool before acting. Reads message metadata only, never bodies, and stores per-sender totals rather than any message. Read the result's provenance before quoting it. `source` is 'cache' or 'live'; `as_of` is when the totals were last brought current, so say 'as of an hour ago' rather than implying now; `complete` false means a scan has not yet reached the end of the mailbox and every count is a floor, not a total. `fetched` is how many messages this call actually read from the provider.
Input fields
{
"type": "object",
"properties": {
"account_id": {
"type": "string",
"minLength": 1,
"description": "The connected mailbox to act on, from email_accounts_list. Never guess this value and never reuse one across mailboxes — it selects both the credential and the permission set the call runs under."
},
"query": {
"description": "Optional filter, same syntax as email_search_messages, applied before aggregation. Use it to scope the scan — 'older_than:6m in:inbox' answers a different question than the whole mailbox.",
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"folder": {
"description": "Restrict the scan to one folder id from email_list_folders.",
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scan_limit": {
"description": "How many messages to read before aggregating. Clamped to the server's maximum. Counts in the result describe the scanned window only, so a small limit gives a fast, approximate ranking and a large one a slower, truer count. Check `truncated` before quoting a total to the user.",
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"top": {
"description": "How many senders to return, highest first. Default 50.",
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"sort_by": {
"description": "message_count (default) finds bulk. unread_count finds noise that is never opened. last_received_at finds who is still sending.",
"anyOf": [
{
"type": "string",
"enum": [
"message_count",
"unread_count",
"last_received_at"
]
},
{
"type": "null"
}
]
},
"mode": {
"description": "auto (default) answers from stored tallies after reading only the mail that arrived since the last scan — near-instant after the first run. refresh recounts the mailbox from scratch and is slow; use it when the user says the numbers look wrong. live bypasses the tallies entirely. Prefer auto. A query or folder always scans live, because the tallies do not record which messages contributed and cannot be filtered.",
"anyOf": [
{
"type": "string",
"enum": [
"auto",
"refresh",
"live"
]
},
{
"type": "null"
}
]
}
},
"required": [
"account_id"
]
}Tool behavior
Declared read-only. Actual provider grants and account access apply.
Inspect isError and per-account errors. General write tools do not all enforce exact-plan approval. This reference does not certify any current AI client version.

YOUR INBOXES.
UNDER CONTROL.
Get started Start with a free account and one read-only search. Existing accounts keep their connection.