Google Workspace Automation
Overview
Google Workspace (formerly G Suite) serves 3B+ Gmail users and 10M+ paying organizations. Its APIs provide programmatic access to Gmail, Calendar, Drive, Sheets, Docs, and Meet. AI agents with Workspace access can manage email, generate documents, update spreadsheets, and orchestrate office workflows at scale.
When to Use This Skill
- Building MCP servers for Gmail management and email triage
- Automating Google Sheets for reporting and data pipelines
- Generating Google Docs from templates or AI content
- Implementing Google Calendar scheduling and availability checking
- Creating file management workflows with Google Drive
Core Concepts
Google Workspace API Landscape
| API |
Purpose |
Key Operations |
| Gmail API |
Email management |
Send, search, labels, threads |
| Calendar API |
Scheduling |
Events, availability, reminders |
| Drive API |
File management |
Upload, share, organize, search |
| Sheets API |
Spreadsheet ops |
Read, write, format, formulas |
| Docs API |
Document generation |
Create, insert, format |
| Admin SDK |
Org management |
Users, groups, audit |
Authentication
import { google } from "googleapis";
// Service Account (server-to-server)
const auth = new google.auth.GoogleAuth({
keyFile: "service-account-key.json",
scopes: [
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/spreadsheets",
],
subject: "user@company.com", // Impersonate user (domain-wide delegation)
});
// OAuth 2.0 (user-interactive)
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_REDIRECT_URI
);
Implementation Guide
Gmail Operations
const gmail = google.gmail({ version: "v1", auth });
// Search emails
const searchResults = await gmail.users.messages.list({
userId: "me",
q: "is:unread from:client@acme.com after:2026/03/01",
maxResults: 20,
});
// Get message details
const message = await gmail.users.messages.get({
userId: "me",
id: messageId,
format: "full",
});
// Send email
const encodedMessage = Buffer.from(
`To: recipient@example.com\r\n` +
`Subject: Weekly Report\r\n` +
`Content-Type: text/html; charset=utf-8\r\n\r\n` +
`<h2>Weekly Summary</h2><p>Key metrics attached.</p>`
).toString("base64url");
await gmail.users.messages.send({
userId: "me",
requestBody: { raw: encodedMessage },
});
// Apply labels for organization
await gmail.users.messages.modify({
userId: "me",
id: messageId,
requestBody: {
addLabelIds: ["Label_Reviewed"],
removeLabelIds: ["UNREAD"],
},
});
Google Sheets Operations
const sheets = google.sheets({ version: "v4", auth });
// Read data
const data = await sheets.spreadsheets.values.get({
spreadsheetId: SHEET_ID,
range: "Pipeline!A1:F100",
});
// Write data
await sheets.spreadsheets.values.update({
spreadsheetId: SHEET_ID,
range: "Pipeline!A1",
valueInputOption: "USER_ENTERED",
requestBody: {
values: [
["Deal Name", "Stage", "Amount", "Close Date", "Owner", "Probability"],
["Acme Corp", "Negotiation", "$150,000", "2026-04-30", "Jane", "75%"],
["Beta Inc", "Proposal", "$80,000", "2026-05-15", "John", "50%"],
],
},
});
// Append rows (add to end)
await sheets.spreadsheets.values.append({
spreadsheetId: SHEET_ID,
range: "Leads!A:D",
valueInputOption: "USER_ENTERED",
requestBody: {
values: [["New Lead", "lead@example.com", "Technology", new Date().toISOString()]],
},
});
Google Drive Operations
const drive = google.drive({ version: "v3", auth });
// Search files
const files = await drive.files.list({
q: "name contains 'Q2 Report' and mimeType = 'application/pdf' and trashed = false",
fields: "files(id, name, modifiedTime, webViewLink, size)",
orderBy: "modifiedTime desc",
pageSize: 10,
});
// Upload a file
const uploadedFile = await drive.files.create({
requestBody: {
name: "Monthly-Report-March-2026.pdf",
parents: [folderId],
},
media: {
mimeType: "application/pdf",
body: fs.createReadStream("report.pdf"),
},
});
// Share with specific users
await drive.permissions.create({
fileId: uploadedFile.data.id,
requestBody: {
role: "reader",
type: "user",
emailAddress: "manager@company.com",
},
});
Workspace MCP Server
server.tool(
"search_gmail",
"Search Gmail messages using Gmail search syntax",
{
query: z.string().describe("Gmail search query (e.g., 'from:boss is:unread')"),
maxResults: z.number().default(10),
},
async ({ query, maxResults }) => {
const results = await gmail.users.messages.list({
userId: "me",
q: query,
maxResults,
});
if (!results.data.messages?.length) {
return { content: [{ type: "text", text: "No messages found." }] };
}
const messages = await Promise.all(
results.data.messages.map(async (m) => {
const full = await gmail.users.messages.get({
userId: "me", id: m.id, format: "metadata",
metadataHeaders: ["Subject", "From", "Date"],
});
const headers = Object.fromEntries(
full.data.payload.headers.map(h => [h.name, h.value])
);
return { subject: headers.Subject, from: headers.From, date: headers.Date, snippet: full.data.snippet };
})
);
return {
content: [{
type: "text",
text: messages.map(m =>
`From: ${m.from}\nSubject: ${m.subject}\nDate: ${m.date}\n${m.snippet}\n`
).join("\n---\n"),
}],
};
}
);
server.tool(
"update_spreadsheet",
"Read from or write to a Google Sheets spreadsheet",
{
spreadsheetId: z.string(),
range: z.string().describe("Cell range (e.g., 'Sheet1!A1:D10')"),
action: z.enum(["read", "write", "append"]),
data: z.array(z.array(z.string())).optional().describe("Rows of data for write/append"),
},
async ({ spreadsheetId, range, action, data }) => {
if (action === "read") {
const result = await sheets.spreadsheets.values.get({ spreadsheetId, range });
return {
content: [{
type: "text",
text: result.data.values?.map(row => row.join(" | ")).join("\n") || "Empty range",
}],
};
}
// write or append
const method = action === "append" ? "append" : "update";
await sheets.spreadsheets.values[method]({
spreadsheetId, range,
valueInputOption: "USER_ENTERED",
requestBody: { values: data },
});
return { content: [{ type: "text", text: `${data.length} rows ${action === "append" ? "appended" : "written"} to ${range}` }] };
}
);
Best Practices
- Use service accounts with domain-wide delegation for server-side automation
- Batch API calls — Google APIs support batch requests (up to 100 per batch)
- Respect quotas — Gmail: 250 messages/day (free), Drive: 1000 queries/100s
- Use push notifications over polling for real-time updates (Drive, Gmail watch)
- Paginate with nextPageToken — never assume complete results
- Scope permissions minimally — only request OAuth scopes you actually need
Resources
Changelog
| Version |
Date |
Changes |
| 1.0.0 |
2026-03-31 |
Initial documentation |
1---2name: google-workspace-automation3description: Automate Google Workspace using Gmail, Calendar, Drive, Sheets, and Docs APIs. Covers authentication, email management, document generation, spreadsheet operations, and AI-powered workspace workflows.4license: Apache 2.05---6
7# Google Workspace Automation
8
9## Overview
10
11Google Workspace (formerly G Suite) serves 3B+ Gmail users and 10M+ paying organizations. Its APIs provide programmatic access to Gmail, Calendar, Drive, Sheets, Docs, and Meet. AI agents with Workspace access can manage email, generate documents, update spreadsheets, and orchestrate office workflows at scale.
12
13## When to Use This Skill
14
15- Building MCP servers for Gmail management and email triage
16- Automating Google Sheets for reporting and data pipelines
17- Generating Google Docs from templates or AI content
18- Implementing Google Calendar scheduling and availability checking
19- Creating file management workflows with Google Drive
20
21## Core Concepts
22
23### Google Workspace API Landscape
24
25| API | Purpose | Key Operations |
26|-----|---------|---------------|
27| Gmail API | Email management | Send, search, labels, threads |
28| Calendar API | Scheduling | Events, availability, reminders |
29| Drive API | File management | Upload, share, organize, search |
30| Sheets API | Spreadsheet ops | Read, write, format, formulas |
31| Docs API | Document generation | Create, insert, format |
32| Admin SDK | Org management | Users, groups, audit |
33
34### Authentication
35
36```typescript
37import { google } from "googleapis";
38
39// Service Account (server-to-server)
40const auth = new google.auth.GoogleAuth({
41 keyFile: "service-account-key.json",
42 scopes: [
43 "https://www.googleapis.com/auth/gmail.modify",
44 "https://www.googleapis.com/auth/calendar",
45 "https://www.googleapis.com/auth/drive",
46 "https://www.googleapis.com/auth/spreadsheets",
47 ],
48 subject: "user@company.com", // Impersonate user (domain-wide delegation)
49});
50
51// OAuth 2.0 (user-interactive)
52const oauth2Client = new google.auth.OAuth2(
53 process.env.GOOGLE_CLIENT_ID,
54 process.env.GOOGLE_CLIENT_SECRET,
55 process.env.GOOGLE_REDIRECT_URI
56);
57```
58
59## Implementation Guide
60
61### Gmail Operations
62
63```typescript
64const gmail = google.gmail({ version: "v1", auth });
65
66// Search emails
67const searchResults = await gmail.users.messages.list({
68 userId: "me",
69 q: "is:unread from:client@acme.com after:2026/03/01",
70 maxResults: 20,
71});
72
73// Get message details
74const message = await gmail.users.messages.get({
75 userId: "me",
76 id: messageId,
77 format: "full",
78});
79
80// Send email
81const encodedMessage = Buffer.from(
82 `To: recipient@example.com\r\n` +
83 `Subject: Weekly Report\r\n` +
84 `Content-Type: text/html; charset=utf-8\r\n\r\n` +
85 `<h2>Weekly Summary</h2><p>Key metrics attached.</p>`
86).toString("base64url");
87
88await gmail.users.messages.send({
89 userId: "me",
90 requestBody: { raw: encodedMessage },
91});
92
93// Apply labels for organization
94await gmail.users.messages.modify({
95 userId: "me",
96 id: messageId,
97 requestBody: {
98 addLabelIds: ["Label_Reviewed"],
99 removeLabelIds: ["UNREAD"],
100 },
101});
102```
103
104### Google Sheets Operations
105
106```typescript
107const sheets = google.sheets({ version: "v4", auth });
108
109// Read data
110const data = await sheets.spreadsheets.values.get({
111 spreadsheetId: SHEET_ID,
112 range: "Pipeline!A1:F100",
113});
114
115// Write data
116await sheets.spreadsheets.values.update({
117 spreadsheetId: SHEET_ID,
118 range: "Pipeline!A1",
119 valueInputOption: "USER_ENTERED",
120 requestBody: {
121 values: [
122 ["Deal Name", "Stage", "Amount", "Close Date", "Owner", "Probability"],
123 ["Acme Corp", "Negotiation", "$150,000", "2026-04-30", "Jane", "75%"],
124 ["Beta Inc", "Proposal", "$80,000", "2026-05-15", "John", "50%"],
125 ],
126 },
127});
128
129// Append rows (add to end)
130await sheets.spreadsheets.values.append({
131 spreadsheetId: SHEET_ID,
132 range: "Leads!A:D",
133 valueInputOption: "USER_ENTERED",
134 requestBody: {
135 values: [["New Lead", "lead@example.com", "Technology", new Date().toISOString()]],
136 },
137});
138```
139
140### Google Drive Operations
141
142```typescript
143const drive = google.drive({ version: "v3", auth });
144
145// Search files
146const files = await drive.files.list({
147 q: "name contains 'Q2 Report' and mimeType = 'application/pdf' and trashed = false",
148 fields: "files(id, name, modifiedTime, webViewLink, size)",
149 orderBy: "modifiedTime desc",
150 pageSize: 10,
151});
152
153// Upload a file
154const uploadedFile = await drive.files.create({
155 requestBody: {
156 name: "Monthly-Report-March-2026.pdf",
157 parents: [folderId],
158 },
159 media: {
160 mimeType: "application/pdf",
161 body: fs.createReadStream("report.pdf"),
162 },
163});
164
165// Share with specific users
166await drive.permissions.create({
167 fileId: uploadedFile.data.id,
168 requestBody: {
169 role: "reader",
170 type: "user",
171 emailAddress: "manager@company.com",
172 },
173});
174```
175
176### Workspace MCP Server
177
178```typescript
179server.tool(
180 "search_gmail",
181 "Search Gmail messages using Gmail search syntax",
182 {
183 query: z.string().describe("Gmail search query (e.g., 'from:boss is:unread')"),
184 maxResults: z.number().default(10),
185 },
186 async ({ query, maxResults }) => {
187 const results = await gmail.users.messages.list({
188 userId: "me",
189 q: query,
190 maxResults,
191 });
192
193 if (!results.data.messages?.length) {
194 return { content: [{ type: "text", text: "No messages found." }] };
195 }
196
197 const messages = await Promise.all(
198 results.data.messages.map(async (m) => {
199 const full = await gmail.users.messages.get({
200 userId: "me", id: m.id, format: "metadata",
201 metadataHeaders: ["Subject", "From", "Date"],
202 });
203 const headers = Object.fromEntries(
204 full.data.payload.headers.map(h => [h.name, h.value])
205 );
206 return { subject: headers.Subject, from: headers.From, date: headers.Date, snippet: full.data.snippet };
207 })
208 );
209
210 return {
211 content: [{
212 type: "text",
213 text: messages.map(m =>
214 `From: ${m.from}\nSubject: ${m.subject}\nDate: ${m.date}\n${m.snippet}\n`
215 ).join("\n---\n"),
216 }],
217 };
218 }
219);
220
221server.tool(
222 "update_spreadsheet",
223 "Read from or write to a Google Sheets spreadsheet",
224 {
225 spreadsheetId: z.string(),
226 range: z.string().describe("Cell range (e.g., 'Sheet1!A1:D10')"),
227 action: z.enum(["read", "write", "append"]),
228 data: z.array(z.array(z.string())).optional().describe("Rows of data for write/append"),
229 },
230 async ({ spreadsheetId, range, action, data }) => {
231 if (action === "read") {
232 const result = await sheets.spreadsheets.values.get({ spreadsheetId, range });
233 return {
234 content: [{
235 type: "text",
236 text: result.data.values?.map(row => row.join(" | ")).join("\n") || "Empty range",
237 }],
238 };
239 }
240 // write or append
241 const method = action === "append" ? "append" : "update";
242 await sheets.spreadsheets.values[method]({
243 spreadsheetId, range,
244 valueInputOption: "USER_ENTERED",
245 requestBody: { values: data },
246 });
247 return { content: [{ type: "text", text: `${data.length} rows ${action === "append" ? "appended" : "written"} to ${range}` }] };
248 }
249);
250```
251
252## Best Practices
253
2541. **Use service accounts with domain-wide delegation** for server-side automation
2552. **Batch API calls** — Google APIs support batch requests (up to 100 per batch)
2563. **Respect quotas** — Gmail: 250 messages/day (free), Drive: 1000 queries/100s
2574. **Use push notifications** over polling for real-time updates (Drive, Gmail watch)
2585. **Paginate with nextPageToken** — never assume complete results
2596. **Scope permissions minimally** — only request OAuth scopes you actually need
260
261## Resources
262
263- [Google Workspace API Documentation](https://developers.google.com/workspace)
264- [Gmail API Reference](https://developers.google.com/gmail/api)
265- [Google Sheets API](https://developers.google.com/sheets/api)
266- [googleapis Node.js Client](https://github.com/googleapis/google-api-nodejs-client)
267
268## Changelog
269
270| Version | Date | Changes |
271|---------|------|---------|
272| 1.0.0 | 2026-03-31 | Initial documentation |