Monday morning. Your VP sends you two emails before 8am and you need to spot them inside forty unread messages. Right now, how do you do it?
Yesterday get_email gave me a full message by ID — but I'd still have to loop the whole inbox to find the VP's emails. I need something that filters before it fetches.
Gmail has a query mini-language — the same syntax as the search bar in your browser. Strings like from:vp@company.com, is:unread, newer_than:1d, and subject:Q2 work exactly here. You can combine them:
"is:unread from:vp@company.com" # unread messages from one sender
"from:finance@company.com newer_than:3d" # last 3 days from finance
"subject:urgent is:unread" # unread with 'urgent' in subjectBut how does that string reach Gmail? Is it a different action from the one we used on Day 3 to count emails?
Same action — GMAIL_FETCH_EMAILS — you just add a query key to the params dict. Gmail applies the filter server-side before returning anything. You get back only the messages that match:
def search_emails(query: str) -> list:
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"query": query, "max_results": 20})
messages = result.get("messages", [])
print(f"Found {len(messages)} messages for query: {query}")
return messagesSo search_emails("is:unread from:vp@company.com newer_than:1d") gives me only this morning's unread messages from my VP — nothing else?
Nothing else. You just wrote the world's most over-qualified inbox filter. Your VP emails go from forty needles in a haystack to a clean list of dicts before your coffee cools.
This means I could have one call per stakeholder. search_emails("from:vp@company.com is:unread"), search_emails("from:ceo@company.com newer_than:1d") — different slices, same function. I'm building a morning triage tool.
That's exactly how query-driven functions scale — the logic stays fixed, the argument changes the scope. When you can draft a reply to those filtered messages automatically, the triage writes itself.
GMAIL_FETCH_EMAILS accepts an optional query parameter. Gmail evaluates it server-side, so only matching messages come back — no client-side filtering needed.
| Operator | Example | Matches |
|---|---|---|
from: | from:vp@company.com | Sender address |
is:unread | is:unread | Unread messages only |
newer_than: | newer_than:1d | Last N days/hours |
subject: | subject:Q2 | Subject contains keyword |
Combine operators with a space (implicit AND). The same strings work in Gmail's browser search bar — test there first, then paste into your function argument.
Monday morning. Your VP sends you two emails before 8am and you need to spot them inside forty unread messages. Right now, how do you do it?
Yesterday get_email gave me a full message by ID — but I'd still have to loop the whole inbox to find the VP's emails. I need something that filters before it fetches.
Gmail has a query mini-language — the same syntax as the search bar in your browser. Strings like from:vp@company.com, is:unread, newer_than:1d, and subject:Q2 work exactly here. You can combine them:
"is:unread from:vp@company.com" # unread messages from one sender
"from:finance@company.com newer_than:3d" # last 3 days from finance
"subject:urgent is:unread" # unread with 'urgent' in subjectBut how does that string reach Gmail? Is it a different action from the one we used on Day 3 to count emails?
Same action — GMAIL_FETCH_EMAILS — you just add a query key to the params dict. Gmail applies the filter server-side before returning anything. You get back only the messages that match:
def search_emails(query: str) -> list:
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"query": query, "max_results": 20})
messages = result.get("messages", [])
print(f"Found {len(messages)} messages for query: {query}")
return messagesSo search_emails("is:unread from:vp@company.com newer_than:1d") gives me only this morning's unread messages from my VP — nothing else?
Nothing else. You just wrote the world's most over-qualified inbox filter. Your VP emails go from forty needles in a haystack to a clean list of dicts before your coffee cools.
This means I could have one call per stakeholder. search_emails("from:vp@company.com is:unread"), search_emails("from:ceo@company.com newer_than:1d") — different slices, same function. I'm building a morning triage tool.
That's exactly how query-driven functions scale — the logic stays fixed, the argument changes the scope. When you can draft a reply to those filtered messages automatically, the triage writes itself.
GMAIL_FETCH_EMAILS accepts an optional query parameter. Gmail evaluates it server-side, so only matching messages come back — no client-side filtering needed.
| Operator | Example | Matches |
|---|---|---|
from: | from:vp@company.com | Sender address |
is:unread | is:unread | Unread messages only |
newer_than: | newer_than:1d | Last N days/hours |
subject: | subject:Q2 | Subject contains keyword |
Combine operators with a space (implicit AND). The same strings work in Gmail's browser search bar — test there first, then paste into your function argument.
Create a free account to get started. Paid plans unlock all tracks.