read_range from Week 3 reads your time log rows. send_email from Week 1 sends an email. What if you chained them — read the rows, format a summary, send it to yourself as a month-end digest?
Two function calls in sequence. Read the Sheet, format the rows into a text summary, pass the summary to send_email.
That is the first cross-app chain. The output of read_range — a list of row lists — becomes the input to the email formatter. send_email sends the result. Two apps, one function, the 15-minute monthly summary ritual gone:
rows = read_range(sheet_id, 'A:D')
lines = [f'{r[1]}: {r[2]} hours' for r in rows[1:]]
body = ' | '.join(lines)rows[1:] — why skip the first row?
Row rows[0] is the header — ["date", "client", "hours", "notes"]. Data rows start at rows[1:]. Same pattern as parse_client_csv from the Python track: skip the header, process the data rows.
And now my monthly time summary emails itself. I just call one function at month-end.
The 45 minutes that happens at 11 PM the last day of every month — gone. Two actions, one chain:
def email_sheet_summary(sheet_id: str, recipient: str) -> dict:
rows = read_range(sheet_id, 'A:D')
lines = [f'{r[1]}: {r[2]} hours' for r in rows[1:]]
body = ' | '.join(lines)
return send_email(recipient, 'Monthly Hours Summary', body)I just replaced 15 minutes of monthly copy-pasting with a function call.
Always send to self first. Confirm the body looks right before pointing it at a client.
The cross-app pattern: fetch data from one app, format it, send it via another:
rows = read_range(sheet_id, 'A:D')
lines = [f'{r[1]}: {r[2]} hours' for r in rows[1:]]
body = ' | '.join(lines)
send_email(recipient, 'Monthly Hours Summary', body)Each row is a list: [date, client, hours, note]. Build a human-readable summary by joining formatted row strings. The recipient gets a plain-text email.
Safety: always pass your own email as recipient during testing. Only switch to a client address after verifying the body content in your own inbox.
read_range from Week 3 reads your time log rows. send_email from Week 1 sends an email. What if you chained them — read the rows, format a summary, send it to yourself as a month-end digest?
Two function calls in sequence. Read the Sheet, format the rows into a text summary, pass the summary to send_email.
That is the first cross-app chain. The output of read_range — a list of row lists — becomes the input to the email formatter. send_email sends the result. Two apps, one function, the 15-minute monthly summary ritual gone:
rows = read_range(sheet_id, 'A:D')
lines = [f'{r[1]}: {r[2]} hours' for r in rows[1:]]
body = ' | '.join(lines)rows[1:] — why skip the first row?
Row rows[0] is the header — ["date", "client", "hours", "notes"]. Data rows start at rows[1:]. Same pattern as parse_client_csv from the Python track: skip the header, process the data rows.
And now my monthly time summary emails itself. I just call one function at month-end.
The 45 minutes that happens at 11 PM the last day of every month — gone. Two actions, one chain:
def email_sheet_summary(sheet_id: str, recipient: str) -> dict:
rows = read_range(sheet_id, 'A:D')
lines = [f'{r[1]}: {r[2]} hours' for r in rows[1:]]
body = ' | '.join(lines)
return send_email(recipient, 'Monthly Hours Summary', body)I just replaced 15 minutes of monthly copy-pasting with a function call.
Always send to self first. Confirm the body looks right before pointing it at a client.
The cross-app pattern: fetch data from one app, format it, send it via another:
rows = read_range(sheet_id, 'A:D')
lines = [f'{r[1]}: {r[2]} hours' for r in rows[1:]]
body = ' | '.join(lines)
send_email(recipient, 'Monthly Hours Summary', body)Each row is a list: [date, client, hours, note]. Build a human-readable summary by joining formatted row strings. The recipient gets a plain-text email.
Safety: always pass your own email as recipient during testing. Only switch to a client address after verifying the body content in your own inbox.
Create a free account to get started. Paid plans unlock all tracks.