/start-10-4.en
Lesson command
$ npx -y skills add minicoohei/ai-agent-camp --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/start-10-4.en
Context preview
What this command does when you run it.
Lesson command
Command definition
start-10-4.en.mddescription: "Lesson command"
chapter: "courses/aiagent/lesson03-core/module10-gas"
duration: "~25 min"
prerequisites: ["start-10-1"]
level: "intermediate"
tags: ["gas", "gmail", "sheets", "automation", "clasp"]
nonInteractiveMode: deferred
๐ Lesson 10-4: GmailApp Email Search/Extraction โ Sheet Organization
๐ What You'll Do
**Lesson 10-4: GmailApp Email Search/Extraction โ Sheet Organization**!
| Item | Details | |------|------| | Goal | Search and extract emails with GAS GmailApp, then automatically organize them in a spreadsheet | | Duration | ~25 min | | Skills used | GAS (GmailApp, SpreadsheetApp), clasp | | Prerequisites | Lesson 10-1 completed (clasp authenticated) |
**Session flow:** 1. Add Gmail scope to appsscript.json 2. Search emails with GmailApp.search() 3. Extract info from threads/messages 4. Write data to a sheet with SpreadsheetApp 5. Set up a scheduled trigger
By the end of this session, you'll have a complete GAS script that automatically searches, extracts, and organizes emails in a spreadsheet.
> **๐ก Hint**: If the AI response stops midway, type "please continue" or "keep going" to resume.
---
๐ฏ Readiness Check
Let's first check that everything is ready.
**AskQuestion configuration:**
{
"title": "๐ฏ Pre-session check",
"questions": [{
"id": "readiness",
"prompt": "Are you ready?",
"options": [
{"id": "ready", "label": "Ready! Let's start"},
{"id": "check_prereq", "label": "Check prerequisites"},
{"id": "different_lesson", "label": "Go to a different lesson"}
]
}]
}(ready โ Go to Step 1) (check_prereq โ Verify Lesson 10-1 completion. Check auth status with `clasp login --status`) (different_lesson โ Display module list)
---
๐ Step 1: Add Gmail Scope to appsscript.json
{
"title": "๐ Step 1: Add Gmail Scope",
"questions": [{
"id": "step_action",
"prompt": "Add the Gmail read scope to appsscript.json.",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review current appsscript.json"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Add the following to `oauthScopes` in `gas-example/appsscript.json`:
{
"timeZone": "Asia/Tokyo",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/script.scriptapp"
]
}After adding, deploy with `clasp push`:
cd gas-example && npx -y @google/clasp push
**Expected result:** The `gmail.readonly` scope is added to `appsscript.json` and the push succeeds.
---
๐ Step 2: Search Emails with GmailApp.search()
{
"title": "๐ Step 2: Email Search",
"questions": [{
"id": "step_action",
"prompt": "Create a function that searches emails using GmailApp.search().",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review Gmail search query syntax"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Create the `searchEmails` function in `gas-example/Gmail.gs`:
function searchEmails(query, maxResults) {
query = query || "is:unread newer_than:7d";
maxResults = maxResults || 50;
var threads = GmailApp.search(query, 0, maxResults);
Logger.log("Search results: " + threads.length + " threads");
return threads;
}**Gmail search query examples:**
| Query | Meaning | |--------|------| | `is:unread` | Unread emails | | `newer_than:7d` | Within the last 7 days | | `from:example@company.com` | From a specific sender | | `subject:meeting` | Subject contains "meeting" | | `has:attachment` | Has attachments | | `is:unread newer_than:3d` | Combined conditions |
Run `clasp push` โ `clasp open` to open the GAS editor, then execute `searchEmails` and check the logs.
**Expected result:** The number of matching threads is displayed in the logs.
---
๐ Step 3: Extract Email Information
{
"title": "๐ Step 3: Extract Email Info",
"questions": [{
"id": "step_action",
"prompt": "Extract email information (sender, subject, date, body) from threads.",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review the GmailMessage API"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Add the `extractEmailData` function:
function extractEmailData(threads) {
var data = [];
threads.forEach(function(thread) {
var messages = thread.getMessages();
var lastMessage = messages[messages.length - 1];
data.push({
subject: lastMessage.getSubject(),
from: lastMessage.getFrom(),
date: lastMessage.getDate(),
body: lastMessage.getPlainBody().substring(0, 200),
isUnread: lastMessage.isUnread(),
messageCount: messages.length
});
});
return data;
}**Key methods:**
| Method | Returns | |---------|---------| | `getSubject()` | Subject | | `getFrom()` | Sender | | `getDate()` | Date/time | | `getPlainBody()` | Body (plain text) | | `isUnread()` | Whether the email is unread | | `getMessages().length` | Number of messages in the thread |
**Expected result:** Email information is extracted as an array of objects.
---
๐ Step 4: Write Data to a Spreadsheet
{
"title": "๐ Step 4: Write to Sheet",
"questions": [{
"id": "step_action",
"prompt": "Write the extracted email data to a spreadsheet.",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review the SpreadsheetApp API"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Add the `writeToSheet` function and the main function `extractAndOrganizeEmails`:
function writeToSheet(data, sheetName) {Read more
description: "Lesson command" chapter: "courses/aiagent/lesson03-core/module10-gas" duration: "~25 min" prerequisites: ["start-10-1"] level: "intermediate" tags: ["gas", "gmail", "sheets", "automation", "clasp"] nonInteractiveMode: deferred
๐ Lesson 10-4: GmailApp Email Search/Extraction โ Sheet Organization
๐ What You'll Do
**Lesson 10-4: GmailApp Email Search/Extraction โ Sheet Organization**!
| Item | Details | |------|------| | Goal | Search and extract emails with GAS GmailApp, then automatically organize them in a spreadsheet | | Duration | ~25 min | | Skills used | GAS (GmailApp, SpreadsheetApp), clasp | | Prerequisites | Lesson 10-1 completed (clasp authenticated) |
**Session flow:** 1. Add Gmail scope to appsscript.json 2. Search emails with GmailApp.search() 3. Extract info from threads/messages 4. Write data to a sheet with SpreadsheetApp 5. Set up a scheduled trigger
By the end of this session, you'll have a complete GAS script that automatically searches, extracts, and organizes emails in a spreadsheet.
> **๐ก Hint**: If the AI response stops midway, type "please continue" or "keep going" to resume.
---
๐ฏ Readiness Check
Let's first check that everything is ready.
**AskQuestion configuration:**
{
"title": "๐ฏ Pre-session check",
"questions": [{
"id": "readiness",
"prompt": "Are you ready?",
"options": [
{"id": "ready", "label": "Ready! Let's start"},
{"id": "check_prereq", "label": "Check prerequisites"},
{"id": "different_lesson", "label": "Go to a different lesson"}
]
}]
}(ready โ Go to Step 1) (check_prereq โ Verify Lesson 10-1 completion. Check auth status with `clasp login --status`) (different_lesson โ Display module list)
---
๐ Step 1: Add Gmail Scope to appsscript.json
{
"title": "๐ Step 1: Add Gmail Scope",
"questions": [{
"id": "step_action",
"prompt": "Add the Gmail read scope to appsscript.json.",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review current appsscript.json"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Add the following to `oauthScopes` in `gas-example/appsscript.json`:
{
"timeZone": "Asia/Tokyo",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/script.scriptapp"
]
}After adding, deploy with `clasp push`:
cd gas-example && npx -y @google/clasp push
**Expected result:** The `gmail.readonly` scope is added to `appsscript.json` and the push succeeds.
---
๐ Step 2: Search Emails with GmailApp.search()
{
"title": "๐ Step 2: Email Search",
"questions": [{
"id": "step_action",
"prompt": "Create a function that searches emails using GmailApp.search().",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review Gmail search query syntax"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Create the `searchEmails` function in `gas-example/Gmail.gs`:
function searchEmails(query, maxResults) {
query = query || "is:unread newer_than:7d";
maxResults = maxResults || 50;
var threads = GmailApp.search(query, 0, maxResults);
Logger.log("Search results: " + threads.length + " threads");
return threads;
}**Gmail search query examples:**
| Query | Meaning | |--------|------| | `is:unread` | Unread emails | | `newer_than:7d` | Within the last 7 days | | `from:example@company.com` | From a specific sender | | `subject:meeting` | Subject contains "meeting" | | `has:attachment` | Has attachments | | `is:unread newer_than:3d` | Combined conditions |
Run `clasp push` โ `clasp open` to open the GAS editor, then execute `searchEmails` and check the logs.
**Expected result:** The number of matching threads is displayed in the logs.
---
๐ Step 3: Extract Email Information
{
"title": "๐ Step 3: Extract Email Info",
"questions": [{
"id": "step_action",
"prompt": "Extract email information (sender, subject, date, body) from threads.",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review the GmailMessage API"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Add the `extractEmailData` function:
function extractEmailData(threads) {
var data = [];
threads.forEach(function(thread) {
var messages = thread.getMessages();
var lastMessage = messages[messages.length - 1];
data.push({
subject: lastMessage.getSubject(),
from: lastMessage.getFrom(),
date: lastMessage.getDate(),
body: lastMessage.getPlainBody().substring(0, 200),
isUnread: lastMessage.isUnread(),
messageCount: messages.length
});
});
return data;
}**Key methods:**
| Method | Returns | |---------|---------| | `getSubject()` | Subject | | `getFrom()` | Sender | | `getDate()` | Date/time | | `getPlainBody()` | Body (plain text) | | `isUnread()` | Whether the email is unread | | `getMessages().length` | Number of messages in the thread |
**Expected result:** Email information is extracted as an array of objects.
---
๐ Step 4: Write Data to a Spreadsheet
{
"title": "๐ Step 4: Write to Sheet",
"questions": [{
"id": "step_action",
"prompt": "Write the extracted email data to a spreadsheet.",
"options": [
{"id": "practice", "label": "Proceed"},
{"id": "review", "label": "Review the SpreadsheetApp API"},
{"id": "skip", "label": "Skip"}
]
}]
}**Guidance after selection:**
Add the `writeToSheet` function and the main function `extractAndOrganizeEmails`:
function writeToSheet(data, sheetName) {AI Agent Training for Non-Engineers - Complete Guide to Claude Code / Cursor / Codex ### โ ๏ธ Before you clone Official repository (maintained by the authors): Running AI agents from this repo grants them shell, file-write, and external-API permissions on your
Other commands on ai-agent-camp.
- /check-setup.en
Top-level alias โ see lesson/check-setup.en.md for the full body.
Open command - /check-setup.es
Alias de nivel superior โ el cuerpo completo estรก en lesson/check-setup.es.md.
Open command - /check-setup
Top-level alias โ see lesson/check-setup.md for the full body.
Open command - /check-security.en
Lesson command
Open command - /check-security.es
Lesson command
Open command - /check-security
Lesson command
Open command

