You open Gmail every morning to count unread threads before you start client work. How many minutes does that ritual cost before real billable work begins?
Open browser, go to Gmail, scan subjects, flag the invoice-related ones. Five minutes minimum, every weekday.
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 tab, no context switch:
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 is actually my inbox coming back? Real invoice threads, right now?
Your real inbox. Your invoice threads. Right now. Welcome to the part where automation gets personal — your data, not toy data.
Why .get("messages", []) instead of result["messages"]? I thought bracket access was standard.
On an empty inbox, Gmail may drop the messages key entirely. result["messages"] raises KeyError and your script crashes. .get("messages", []) falls back to an empty list, so len() returns 0 cleanly. Make .get(key, default) your reflex for every API response dict in this track:
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 replaced my entire morning inbox scan. My freelance brain is having a moment.
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 the start; the message IDs inside unlock everything else.
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.
.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 parse in this track.
You open Gmail every morning to count unread threads before you start client work. How many minutes does that ritual cost before real billable work begins?
Open browser, go to Gmail, scan subjects, flag the invoice-related ones. Five minutes minimum, every weekday.
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 tab, no context switch:
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 is actually my inbox coming back? Real invoice threads, right now?
Your real inbox. Your invoice threads. Right now. Welcome to the part where automation gets personal — your data, not toy data.
Why .get("messages", []) instead of result["messages"]? I thought bracket access was standard.
On an empty inbox, Gmail may drop the messages key entirely. result["messages"] raises KeyError and your script crashes. .get("messages", []) falls back to an empty list, so len() returns 0 cleanly. Make .get(key, default) your reflex for every API response dict in this track:
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 replaced my entire morning inbox scan. My freelance brain is having a moment.
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 the start; the message IDs inside unlock everything else.
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.
.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 parse in this track.
Create a free account to get started. Paid plans unlock all tracks.