Your research group has 40 emails in the inbox from the last revision round. In your current workflow, how long does it take to triage them before the morning meeting?
Probably 20 minutes. Half are "sounds good" replies I can ignore. But I have to open each one to know.
In Python, that scan is one call. You ask Composio to fetch up to N messages, you get back a dict with a messages key, and len(messages) is your count. No browser needed:
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 40})
count = len(result.get("messages", []))
print(f"Found {count} emails in your inbox")Wait — that's actually my inbox coming back? Real emails from my co-authors, right now?
Real emails. Your inbox. Right now. Welcome to the part where automation gets personal — your data, not toy data.
Why .get("messages", []) instead of just result["messages"]? Isn't bracket access the standard way?
On an empty inbox, Gmail may drop the messages key entirely. result["messages"] raises KeyError and your script crashes before the morning meeting. .get("messages", []) falls back to an empty list, so len() returns 0 cleanly. Make .get(key, default) your reflex for every API response dict:
def count_emails(max_results: int) -> int:
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": max_results})
messages = result.get("messages", [])
count = len(messages)
print(f"Found {count} emails in your inbox")
return countFive lines and I've replaced my entire morning inbox scan. My reproducibility instinct is firing — this is auditable.
That moment never gets old. Every app in this track follows the same shape — one action, one dict response, one safe parse. The count is a starting point; the message IDs inside each dict unlock the rest.
Every Composio action has the same shape: call toolset.execute_action with an Action enum and a params dict, parse what comes back.
Gmail returns {"messages": [{"id": "abc"}, {"id": "def"}]}. The messages key holds a list; each object has an id you can use to fetch full details.
.get() beats []| Access | Empty inbox |
|---|---|
result["messages"] | KeyError — crashes |
result.get("messages", []) | [] — len() returns 0 |
.get(key, default) is the reflex for every API response dict you'll parse.
Your research group has 40 emails in the inbox from the last revision round. In your current workflow, how long does it take to triage them before the morning meeting?
Probably 20 minutes. Half are "sounds good" replies I can ignore. But I have to open each one to know.
In Python, that scan is one call. You ask Composio to fetch up to N messages, you get back a dict with a messages key, and len(messages) is your count. No browser needed:
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": 40})
count = len(result.get("messages", []))
print(f"Found {count} emails in your inbox")Wait — that's actually my inbox coming back? Real emails from my co-authors, right now?
Real emails. Your inbox. Right now. Welcome to the part where automation gets personal — your data, not toy data.
Why .get("messages", []) instead of just result["messages"]? Isn't bracket access the standard way?
On an empty inbox, Gmail may drop the messages key entirely. result["messages"] raises KeyError and your script crashes before the morning meeting. .get("messages", []) falls back to an empty list, so len() returns 0 cleanly. Make .get(key, default) your reflex for every API response dict:
def count_emails(max_results: int) -> int:
result = toolset.execute_action(Action.GMAIL_FETCH_EMAILS, {"max_results": max_results})
messages = result.get("messages", [])
count = len(messages)
print(f"Found {count} emails in your inbox")
return countFive lines and I've replaced my entire morning inbox scan. My reproducibility instinct is firing — this is auditable.
That moment never gets old. Every app in this track follows the same shape — one action, one dict response, one safe parse. The count is a starting point; the message IDs inside each dict unlock the rest.
Every Composio action has the same shape: call toolset.execute_action with an Action enum and a params dict, parse what comes back.
Gmail returns {"messages": [{"id": "abc"}, {"id": "def"}]}. The messages key holds a list; each object has an id you can use to fetch full details.
.get() beats []| Access | Empty inbox |
|---|---|
result["messages"] | KeyError — crashes |
result.get("messages", []) | [] — len() returns 0 |
.get(key, default) is the reflex for every API response dict you'll parse.
Create a free account to get started. Paid plans unlock all tracks.