@matimo/gmail 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1316 @@
1
+ # @matimo/gmail - Gmail Tools for Matimo
2
+
3
+ Gmail integration tools for Matimo's universal AI tools ecosystem. Send emails, manage drafts, and read messages through YAML-defined tools that work with any AI framework.
4
+
5
+ ## 📦 Installation
6
+
7
+ ```bash
8
+ npm install @matimo/gmail
9
+ # or
10
+ pnpm add @matimo/gmail
11
+ ```
12
+
13
+ ## 🛠️ Available Tools
14
+
15
+ | Tool | Description | API Method |
16
+ |------|-------------|------------|
17
+ | `gmail-send-email` | Send email to recipients | Gmail API send |
18
+ | `gmail-create-draft` | Create email draft | Gmail API drafts.create |
19
+ | `gmail-list-messages` | List recent messages | Gmail API messages.list |
20
+
21
+ ## 🚀 Quick Start
22
+
23
+ ```typescript
24
+ import { MatimoInstance } from 'matimo';
25
+
26
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
27
+
28
+ // Send an email
29
+ await matimo.execute('gmail-send-email', {
30
+ to: 'recipient@example.com',
31
+ subject: 'Hello from Matimo',
32
+ body: 'This email was sent by AI!'
33
+ });
34
+
35
+ // List recent messages
36
+ const messages = await matimo.execute('gmail-list-messages', {
37
+ maxResults: 10
38
+ });
39
+ ```
40
+
41
+ ## 🔐 Authentication
42
+
43
+ Set your Gmail OAuth2 access token:
44
+
45
+ ```bash
46
+ export GMAIL_ACCESS_TOKEN="ya29.a0AfH6SMBx..."
47
+ ```
48
+
49
+ Or use environment variables in your application.
50
+
51
+ ## 📚 Integration Examples
52
+
53
+ ### With LangChain
54
+
55
+ ```typescript
56
+ import { MatimoInstance } from 'matimo';
57
+ import { ChatOpenAI } from '@langchain/openai';
58
+
59
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
60
+ const tools = matimo.listTools().filter(t => t.name.startsWith('gmail'));
61
+
62
+ // Use with LangChain agent
63
+ ```
64
+
65
+ ### With Custom Code
66
+
67
+ ```typescript
68
+ import { MatimoInstance } from 'matimo';
69
+
70
+ class GmailAgent {
71
+ private matimo: MatimoInstance;
72
+
73
+ constructor() {
74
+ this.matimo = await MatimoInstance.init({ autoDiscover: true });
75
+ }
76
+
77
+ async sendEmail(to: string, subject: string, body: string) {
78
+ return await this.matimo.execute('gmail-send-email', { to, subject, body });
79
+ }
80
+ }
81
+ ```
82
+
83
+ ## 🔗 API Reference
84
+
85
+ All tools are based on the official Gmail REST API. See [Gmail API Documentation](https://developers.google.com/gmail/api).
86
+
87
+ | Tool | Gmail API Method | OAuth Scopes |
88
+ |------|------------------|--------------|
89
+ | gmail-send-email | gmail.send | https://www.googleapis.com/auth/gmail.send |
90
+ | gmail-create-draft | drafts.create | https://www.googleapis.com/auth/gmail.compose |
91
+ | gmail-list-messages | messages.list | https://www.googleapis.com/auth/gmail.readonly |
92
+
93
+ ## 📋 Tool Specifications
94
+
95
+ Each tool is defined in YAML with complete parameter validation and error handling. Tools include:
96
+
97
+ - **Parameter validation** with Zod schemas
98
+ - **OAuth2 authentication** with automatic token injection
99
+ - **Error handling** with structured error codes
100
+ - **Output validation** against defined schemas
101
+
102
+ ## 🤝 Contributing
103
+
104
+ Found a bug or want to add a Gmail tool? See [Contributing Guide](../../CONTRIBUTING.md) and [Adding Tools Guide](../tool-development/ADDING_TOOLS.md).
105
+
106
+ ---
107
+
108
+ **Part of the Matimo ecosystem** - Define tools once, use them everywhere! 🎯
109
+
110
+ YAML keeps tool definitions **maintainable, readable, and contributor-friendly**:
111
+
112
+ ```yaml
113
+ # Human-readable
114
+ name: send-email
115
+ description: Send an email via Gmail
116
+
117
+ # Parameters clearly defined
118
+ parameters:
119
+ to:
120
+ type: string
121
+ description: Recipient email address
122
+ required: true
123
+ subject:
124
+ type: string
125
+ required: true
126
+ body:
127
+ type: string
128
+ required: true
129
+
130
+ # Auth declared once (used everywhere)
131
+ authentication:
132
+ type: oauth2
133
+ provider: google
134
+
135
+ # Execution details (HTTP call)
136
+ execution:
137
+ type: http
138
+ method: POST
139
+ url: https://www.googleapis.com/gmail/v1/users/me/messages/send
140
+ headers:
141
+ Authorization: 'Bearer {GMAIL_ACCESS_TOKEN}'
142
+
143
+ # Output schema for validation
144
+ output_schema:
145
+ type: object
146
+ properties:
147
+ id:
148
+ type: string
149
+ description: Message ID
150
+ ```
151
+
152
+ ### How Matimo Uses YAML
153
+
154
+ 1. **Load & Parse** - YAML → Tool object
155
+ 2. **Validate** - Check parameters against schema
156
+ 3. **Execute** - Run HTTP request with auth
157
+ 4. **Transform** - Apply parameter encodings (MIME, base64, etc.)
158
+ 5. **Return** - Validate output against schema
159
+
160
+ This is what makes Matimo **framework-agnostic** and **scalable**.
161
+
162
+ ## YAML-Based Tool Architecture
163
+
164
+ ### File Structure
165
+
166
+ ```
167
+ tools/gmail/
168
+ ├── README.md # This file
169
+ ├── send-email/
170
+ │ ├── definition.yaml # Tool definition
171
+ ├── list-messages/
172
+ │ ├── definition.yaml
173
+ ├── create-draft/
174
+ │ ├── definition.yaml
175
+ ├── get-message/
176
+ │ ├── definition.yaml
177
+ └── delete-message/
178
+ ├── definition.yaml
179
+ ```
180
+
181
+ ### Anatomy of a Tool Definition (YAML)
182
+
183
+ Every tool has these sections:
184
+
185
+ #### 1. **Metadata**
186
+
187
+ ```yaml
188
+ name: send-email
189
+ version: '1.0.0'
190
+ description: Send an email via Gmail
191
+ tags: [email, gmail, messaging]
192
+ ```
193
+
194
+ #### 2. **Parameters** (Input Schema)
195
+
196
+ ```yaml
197
+ parameters:
198
+ to:
199
+ type: string
200
+ description: Recipient email address
201
+ required: true
202
+ example: 'user@example.com'
203
+
204
+ subject:
205
+ type: string
206
+ required: true
207
+ example: 'Hello World'
208
+
209
+ body:
210
+ type: string
211
+ required: true
212
+ example: 'This is the email body'
213
+
214
+ cc:
215
+ type: string
216
+ required: false # Optional
217
+ example: 'cc@example.com'
218
+
219
+ isHtml:
220
+ type: boolean
221
+ required: false
222
+ default: false
223
+ ```
224
+
225
+ #### 3. **Authentication** (Credentials)
226
+
227
+ ```yaml
228
+ authentication:
229
+ type: oauth2 # How to authenticate
230
+ provider: google # Which service
231
+ scopes: # Permissions needed
232
+ - gmail.readonly # Read emails
233
+ - gmail.send # Send emails
234
+ - gmail.compose # Create drafts
235
+ ```
236
+
237
+ Matimo auto-injects tokens from environment:
238
+
239
+ ```typescript
240
+ // No explicit token passing - Matimo handles it!
241
+ await matimo.execute('gmail-send-email', {
242
+ to: 'user@example.com',
243
+ subject: 'Hello',
244
+ body: 'Message',
245
+ // GMAIL_ACCESS_TOKEN auto-added from process.env
246
+ });
247
+ ```
248
+
249
+ #### 4. **Execution** (How to run the tool)
250
+
251
+ ```yaml
252
+ execution:
253
+ type: http # Command or HTTP
254
+ method: POST # HTTP method
255
+ url: https://www.googleapis.com/... # API endpoint
256
+
257
+ headers:
258
+ Authorization: 'Bearer {GMAIL_ACCESS_TOKEN}' # Auth header
259
+ Content-Type: application/json
260
+
261
+ body:
262
+ # Parameter encoding: Convert params to Gmail's format
263
+ # Gmail requires MIME message in base64url
264
+ message:
265
+ raw: '{raw}' # Special encoding directive
266
+ ```
267
+
268
+ #### 5. **Parameter Encoding** (Transformation)
269
+
270
+ ```yaml
271
+ parameter_encoding:
272
+ - source: [to, subject, body, cc, bcc, isHtml]
273
+ target: raw
274
+ encoding: mime_rfc2822_base64url # Convert to MIME format
275
+ ```
276
+
277
+ This is how Matimo handles complex transformations:
278
+
279
+ - 🔄 **mime_rfc2822_base64url** - Encode email as MIME message
280
+ - 🔗 **url_encoded** - URL-encode form data
281
+ - 📦 **json_compact** - Minify JSON
282
+
283
+ #### 6. **Output Schema** (Result Validation)
284
+
285
+ ```yaml
286
+ output_schema:
287
+ type: object
288
+ properties:
289
+ id:
290
+ type: string
291
+ description: 'Gmail message ID'
292
+ threadId:
293
+ type: string
294
+ description: 'Thread ID for grouping conversations'
295
+ required: [id, threadId]
296
+ ```
297
+
298
+ ### Why This Architecture Matters
299
+
300
+ | Aspect | Benefit |
301
+ | ---------------- | --------------------------------------------------- |
302
+ | **Declarative** | Tool behavior defined in human-readable YAML |
303
+ | **Validated** | Schema validation at load time + execution time |
304
+ | **Reusable** | Same YAML works with any framework (SDK, MCP, REST) |
305
+ | **Maintainable** | Update tool = edit YAML, no code changes needed |
306
+ | **Scalable** | Add 1000s of tools without changing core code |
307
+ | **Secure** | Auth tokens never in source code or YAML |
308
+ | **Transparent** | LLMs can see tool definitions and understand them |
309
+
310
+ ## Provider YAML Architecture
311
+
312
+ ### Why Provider YAML?
313
+
314
+ In addition to individual tool definitions, Matimo uses **Provider YAML** files to centralize OAuth2 configuration and shared settings across all tools for a single provider (in this case, Google).
315
+
316
+ ```
317
+ tools/gmail/
318
+ ├── definition.yaml # ← PROVIDER YAML (Google OAuth2 config)
319
+ │ All Gmail tools reference this
320
+ ├── send-email/
321
+ │ ├── definition.yaml # Individual tool definition
322
+ │ └── ...
323
+ ├── create-draft/
324
+ │ ├── definition.yaml
325
+ │ └── ...
326
+ └── list-messages/
327
+ ├── definition.yaml
328
+ └── ...
329
+ ```
330
+
331
+ ### Provider YAML: `tools/gmail/definition.yaml`
332
+
333
+ The provider-level YAML file serves multiple purposes:
334
+
335
+ **1. Centralize OAuth2 Configuration**
336
+
337
+ ```yaml
338
+ name: google-provider
339
+ type: provider
340
+
341
+ provider:
342
+ name: google
343
+ displayName: Google
344
+
345
+ # OAuth2 endpoints - used by all Google-dependent tools
346
+ endpoints:
347
+ authorizationUrl: https://accounts.google.com/o/oauth2/v2/auth
348
+ tokenUrl: https://oauth2.googleapis.com/token
349
+ revokeUrl: https://oauth2.googleapis.com/revoke
350
+ ```
351
+
352
+ **Benefits:**
353
+
354
+ - ✅ **Single source of truth** - All Gmail tools reference these endpoints
355
+ - ✅ **Override capability** - Users can change endpoints via environment variables
356
+ - ✅ **Extensibility** - Easy to add new Google-dependent tools
357
+ - ✅ **Maintainability** - If Google changes endpoints, update once
358
+
359
+ **2. Define Standard Scopes**
360
+
361
+ The provider file defines OAuth2 scopes required by Gmail tools:
362
+
363
+ ```yaml
364
+ # From definition.yaml
365
+ scopes:
366
+ - gmail.readonly # Read emails
367
+ - gmail.send # Send emails
368
+ - gmail.compose # Create drafts
369
+ - gmail.modify # Delete/modify emails
370
+ ```
371
+
372
+ Each individual tool declares which scopes it needs:
373
+
374
+ ```yaml
375
+ # In send-email/definition.yaml
376
+ authentication:
377
+ type: oauth2
378
+ provider: google
379
+ scopes:
380
+ - gmail.send # This tool needs to send emails
381
+ ```
382
+
383
+ **3. Configuration Override Pattern**
384
+
385
+ The provider YAML enables this priority system:
386
+
387
+ ```
388
+ Priority (High → Low):
389
+ 1. Runtime configuration (programmatic)
390
+ 2. Environment variables: OAUTH_GOOGLE_AUTH_URL, etc.
391
+ 3. Provider YAML: definition.yaml
392
+ ```
393
+
394
+ Example - Change endpoints for custom proxy:
395
+
396
+ ```bash
397
+ # Option A: Environment variable (highest priority)
398
+ export OAUTH_GOOGLE_AUTH_URL="https://my-proxy.example.com/auth"
399
+
400
+ # Option B: Edit definition.yaml (lowest priority)
401
+ # endpoints:
402
+ # authorizationUrl: https://my-proxy.example.com/auth
403
+ ```
404
+
405
+ ### How Tool Definition References Provider
406
+
407
+ Each individual tool declares its dependency on the provider:
408
+
409
+ **send-email/definition.yaml:**
410
+
411
+ ```yaml
412
+ name: gmail-send-email
413
+ version: '1.0.0'
414
+
415
+ authentication:
416
+ type: oauth2
417
+ provider: google # ← References the provider
418
+ scopes:
419
+ - gmail.send # Specific scopes for this tool
420
+ - gmail.compose
421
+
422
+ execution:
423
+ type: http
424
+ url: https://www.googleapis.com/gmail/v1/users/me/messages/send
425
+ headers:
426
+ # Uses GMAIL_ACCESS_TOKEN from provider's OAuth2 flow
427
+ Authorization: 'Bearer {GMAIL_ACCESS_TOKEN}'
428
+ ```
429
+
430
+ **Matimo's Resolution:**
431
+
432
+ 1. Load tool: `gmail-send-email`
433
+ 2. Read `authentication.provider: google`
434
+ 3. Find provider YAML: `tools/gmail/definition.yaml`
435
+ 4. Load OAuth2 endpoints and scopes from provider
436
+ 5. Merge with tool-specific requirements
437
+ 6. Ready to execute!
438
+
439
+ ### Multi-Provider Scenario
440
+
441
+ When Matimo has tools from multiple providers, provider YAML keeps them isolated:
442
+
443
+ ```
444
+ tools/
445
+ ├── gmail/
446
+ │ ├── definition.yaml # ← Provider: Google
447
+ │ ├── send-email/
448
+ │ ├── create-draft/
449
+ │ └── list-messages/
450
+
451
+ ├── slack/
452
+ │ ├── definition.yaml # ← Provider: Slack
453
+ │ ├── send-message/
454
+ │ ├── post-channel/
455
+ │ └── get-users/
456
+
457
+ └── github/
458
+ ├── definition.yaml # ← Provider: GitHub
459
+ ├── create-issue/
460
+ ├── list-repos/
461
+ └── create-pr/
462
+ ```
463
+
464
+ Each provider has:
465
+
466
+ - ✅ Its own OAuth2 endpoints
467
+ - ✅ Its own scopes/permissions
468
+ - ✅ Its own credentials (CLIENT_ID, CLIENT_SECRET)
469
+ - ✅ Its own authentication flow
470
+
471
+ Matimo loads all providers and their tools - **no code changes needed**.
472
+
473
+ ### Why Not Hardcode in Code?
474
+
475
+ ❌ **Bad approach:**
476
+
477
+ ```typescript
478
+ // Tools/Gmail.ts - Code changes for each provider
479
+ if (provider === 'google') {
480
+ authUrl = 'https://accounts.google.com/...';
481
+ scopes = ['gmail.readonly', 'gmail.send'];
482
+ }
483
+ if (provider === 'slack') {
484
+ authUrl = 'https://slack.com/oauth...';
485
+ scopes = ['chat:write', 'users:read'];
486
+ }
487
+ ```
488
+
489
+ **Problems:**
490
+
491
+ - Non-technical contributors can't add providers
492
+ - Code must be modified for each provider
493
+ - Doesn't scale to 100s of providers
494
+ - Risk of bugs during refactoring
495
+
496
+ ✅ **Good approach (Matimo):**
497
+
498
+ ```yaml
499
+ # tools/gmail/definition.yaml
500
+ provider: google
501
+ endpoints:
502
+ authorizationUrl: https://accounts.google.com/...
503
+ scopes:
504
+ - gmail.readonly
505
+ - gmail.send
506
+ ```
507
+
508
+ **Benefits:**
509
+
510
+ - Maintainers submit YAML, not code
511
+ - Matimo loads all providers dynamically
512
+ - Scales to 1000s of providers
513
+ - Single deployment handles all tools
514
+ - Contributors can add providers without code knowledge
515
+
516
+ ### Real-World Example: Adding GitHub Tools
517
+
518
+ To add GitHub tools to Matimo:
519
+
520
+ **Step 1:** Create provider file:
521
+
522
+ ```bash
523
+ tools/github/definition.yaml
524
+ ```
525
+
526
+ **Step 2:** Define GitHub OAuth2 endpoints:
527
+
528
+ ```yaml
529
+ name: github-provider
530
+ type: provider
531
+ provider:
532
+ name: github
533
+ endpoints:
534
+ authorizationUrl: https://github.com/login/oauth/authorize
535
+ tokenUrl: https://github.com/login/oauth/access_token
536
+ ```
537
+
538
+ **Step 3:** Add tool definitions:
539
+
540
+ ```bash
541
+ tools/github/create-issue/definition.yaml
542
+ tools/github/list-repos/definition.yaml
543
+ tools/github/create-pr/definition.yaml
544
+ ```
545
+
546
+ **Step 4:** Each tool references provider:
547
+
548
+ ```yaml
549
+ # In create-issue/definition.yaml
550
+ authentication:
551
+ type: oauth2
552
+ provider: github # ← Links to github/definition.yaml
553
+ scopes:
554
+ - repo
555
+ - issues
556
+ ```
557
+
558
+ **Done!** No code changes needed. Matimo automatically:
559
+
560
+ - ✅ Loads the provider
561
+ - ✅ Loads all GitHub tools
562
+ - ✅ Sets up OAuth2 with GitHub endpoints
563
+ - ✅ Makes tools available to SDK, MCP, REST API
564
+
565
+ This is the **"Define Once, Use Everywhere"** principle in action!
566
+
567
+ ## Quick Start
568
+
569
+ Get started with Gmail tools in 5 minutes.
570
+
571
+ ### 1️⃣ Get OAuth Token (2 minutes)
572
+
573
+ #### Easiest: Google OAuth Playground
574
+
575
+ 1. **Visit** https://developers.google.com/oauthplayground
576
+ 2. **Configure** (⚙️ settings, top right):
577
+ - ☑️ Check "Use your own OAuth credentials"
578
+ - Enter **Client ID** (from [Google Cloud Console](https://console.cloud.google.com/apis/credentials))
579
+ - Enter **Client Secret**
580
+ 3. **Select Scopes** (left panel):
581
+ ```
582
+ https://www.googleapis.com/auth/gmail.readonly # Read emails
583
+ https://www.googleapis.com/auth/gmail.send # Send emails
584
+ https://www.googleapis.com/auth/gmail.compose # Create drafts
585
+ ```
586
+ 4. **Authorize & Copy Token**:
587
+ - Click "Authorize APIs"
588
+ - Grant permission
589
+ - Copy the **Access Token** (starts with `ya29.a0...`)
590
+
591
+ #### Production: Set Up Your Own OAuth App
592
+
593
+ 1. Go to https://console.cloud.google.com
594
+ 2. Create project: "My Gmail App"
595
+ 3. Enable **Gmail API**:
596
+ - Search "Gmail API"
597
+ - Click "Enable"
598
+ 4. Create **OAuth 2.0 Credentials**:
599
+ - Credentials → "Create Credentials" → "OAuth 2.0 Client ID"
600
+ - App type: **Desktop app** (testing) or **Web application** (production)
601
+ - Add redirect URIs:
602
+ ```
603
+ http://localhost:3000/callback
604
+ http://localhost:3000/auth/gmail/callback
605
+ ```
606
+ - Download JSON credentials
607
+
608
+ ### 2️⃣ Set Environment Variable (1 minute)
609
+
610
+ #### Option A: `.env` file (Recommended)
611
+
612
+ ```bash
613
+ # Create .env in your project root
614
+ cat > .env << EOF
615
+ GMAIL_ACCESS_TOKEN=ya29.a0AfH6SMBx...your-token...
616
+ EOF
617
+
618
+ # Add to .gitignore
619
+ echo ".env" >> .gitignore
620
+ ```
621
+
622
+ #### Option B: Export in shell
623
+
624
+ ```bash
625
+ export GMAIL_ACCESS_TOKEN="ya29.a0AfH6SMBx...your-token..."
626
+ ```
627
+
628
+ ### 3️⃣ Test It! (2 minutes)
629
+
630
+ ```bash
631
+ cd /Users/sajesh/My\ Work\ Directory/matimo/examples/tools
632
+
633
+ # Install dependencies
634
+ pnpm install
635
+
636
+ # Run factory pattern test
637
+ pnpm run gmail:factory --email:youremail@gmail.com
638
+ ```
639
+
640
+ **Expected output:**
641
+
642
+ ```
643
+ 📬 Example 1: List Your Recent Messages
644
+ ✅ Found 5 recent messages
645
+
646
+ 📧 Example 2: Send Email
647
+ ✅ Email sent successfully!
648
+
649
+ ✏️ Example 3: Create Draft
650
+ ✅ Draft created successfully!
651
+ ```
652
+
653
+ ## Available Tools
654
+
655
+ ### Overview
656
+
657
+ | Tool | Purpose | Input | Output |
658
+ | ---------------------- | ---------------------- | ------------------------------------ | -------------------------- |
659
+ | `gmail-list-messages` | List emails from inbox | `maxResults`, `query`, `labelIds` | `messages[]` |
660
+ | `gmail-get-message` | Get full email details | `messageId`, `format` | `id`, `payload`, `headers` |
661
+ | `gmail-send-email` | Send email | `to`, `subject`, `body`, `cc`, `bcc` | `id` |
662
+ | `gmail-create-draft` | Create draft email | `to`, `subject`, `body`, `cc`, `bcc` | `id` |
663
+ | `gmail-delete-message` | Delete email | `messageId` | `success` |
664
+
665
+ ### Tool Reference
666
+
667
+ #### 1. gmail-list-messages
668
+
669
+ **Description:** List recent emails from your inbox with optional filtering.
670
+
671
+ **Parameters:**
672
+
673
+ ```typescript
674
+ {
675
+ query?: string; // Gmail search syntax
676
+ // Examples:
677
+ // "from:alice@example.com"
678
+ // "subject:meeting"
679
+ // "is:unread"
680
+ // "is:starred"
681
+ maxResults?: number; // 1-500 (default: 10)
682
+ pageToken?: string; // For pagination
683
+ labelIds?: string[]; // Filter by labels
684
+ // Common: ["INBOX", "SENT", "DRAFT"]
685
+ includeSpamTrash?: boolean; // Include spam/trash
686
+ }
687
+ ```
688
+
689
+ **Returns:**
690
+
691
+ ```typescript
692
+ {
693
+ messages: Array<{
694
+ id: string; // Gmail message ID
695
+ threadId: string; // For conversation grouping
696
+ snippet: string; // Email preview
697
+ }>,
698
+ resultSizeEstimate: number;
699
+ }
700
+ ```
701
+
702
+ **Example:**
703
+
704
+ ```typescript
705
+ const result = await matimo.execute('gmail-list-messages', {
706
+ maxResults: 5,
707
+ query: 'from:alice@example.com',
708
+ });
709
+ ```
710
+
711
+ ---
712
+
713
+ #### 2. gmail-send-email
714
+
715
+ **Description:** Send an email via Gmail.
716
+
717
+ **Parameters:**
718
+
719
+ ```typescript
720
+ {
721
+ to: string; // Required: Recipient email
722
+ subject: string; // Required: Email subject
723
+ body: string; // Required: Email body
724
+ cc?: string; // Optional: CC recipient(s)
725
+ bcc?: string; // Optional: BCC recipient(s)
726
+ isHtml?: boolean; // Optional: HTML body (default: false)
727
+ }
728
+ ```
729
+
730
+ **Returns:**
731
+
732
+ ```typescript
733
+ {
734
+ id: string; // Sent message ID
735
+ threadId: string; // Thread ID
736
+ labelIds: string[]; // ["SENT"]
737
+ }
738
+ ```
739
+
740
+ **How It Works:**
741
+
742
+ 1. Matimo converts `to`, `subject`, `body` → MIME message
743
+ 2. Encodes as base64url (required by Gmail API)
744
+ 3. Sends via POST to Gmail API
745
+ 4. Returns message ID
746
+
747
+ **Example:**
748
+
749
+ ```typescript
750
+ const result = await matimo.execute('gmail-send-email', {
751
+ to: 'user@example.com',
752
+ subject: 'Hello from Matimo',
753
+ body: 'This email was sent via Gmail tools!',
754
+ isHtml: false,
755
+ });
756
+ ```
757
+
758
+ ---
759
+
760
+ #### 3. gmail-create-draft
761
+
762
+ **Description:** Create a draft email (not sent).
763
+
764
+ **Parameters:**
765
+
766
+ ```typescript
767
+ {
768
+ to: string; // Required: Draft recipient
769
+ subject: string; // Required: Draft subject
770
+ body: string; // Required: Draft body
771
+ cc?: string; // Optional: CC recipient(s)
772
+ bcc?: string; // Optional: BCC recipient(s)
773
+ isHtml?: boolean; // Optional: HTML body (default: false)
774
+ }
775
+ ```
776
+
777
+ **Returns:**
778
+
779
+ ```typescript
780
+ {
781
+ id: string; // Draft ID
782
+ message: {
783
+ id: string;
784
+ threadId: string;
785
+ labelIds: string[]; // ["DRAFT"]
786
+ }
787
+ }
788
+ ```
789
+
790
+ **Use Case:** AI agents generating email content for review before sending.
791
+
792
+ **Example:**
793
+
794
+ ```typescript
795
+ const result = await matimo.execute('gmail-create-draft', {
796
+ to: 'user@example.com',
797
+ subject: 'Weekly Summary',
798
+ body: 'Generated by AI agent...',
799
+ isHtml: true,
800
+ });
801
+ // User can manually review and send from Gmail
802
+ ```
803
+
804
+ ---
805
+
806
+ #### 4. gmail-get-message
807
+
808
+ **Description:** Get full details of a specific email.
809
+
810
+ **Parameters:**
811
+
812
+ ```typescript
813
+ {
814
+ messageId: string; // Required: Email ID (from list-messages)
815
+ format?: string; // Optional: "minimal" | "full" | "raw"
816
+ // Default: "full"
817
+ }
818
+ ```
819
+
820
+ **Returns:**
821
+
822
+ ```typescript
823
+ {
824
+ id: string;
825
+ threadId: string;
826
+ labelIds: string[];
827
+ snippet: string;
828
+ payload: {
829
+ mimeType: string;
830
+ headers: Array<{
831
+ name: string; // "Subject", "From", etc.
832
+ value: string;
833
+ }>,
834
+ parts?: Array<...>; // Email parts (attachments, etc.)
835
+ body: {
836
+ size: number;
837
+ data?: string; // Base64 encoded body (if format=full)
838
+ }
839
+ }
840
+ }
841
+ ```
842
+
843
+ **Example:**
844
+
845
+ ```typescript
846
+ const result = await matimo.execute('gmail-get-message', {
847
+ messageId: '18b8f4a2a1c5e3d2',
848
+ format: 'full',
849
+ });
850
+ ```
851
+
852
+ ---
853
+
854
+ #### 5. gmail-delete-message
855
+
856
+ **Description:** Delete an email (moves to trash).
857
+
858
+ **Parameters:**
859
+
860
+ ```typescript
861
+ {
862
+ messageId: string; // Required: Email ID to delete
863
+ }
864
+ ```
865
+
866
+ **Returns:**
867
+
868
+ ```typescript
869
+ {
870
+ success: boolean;
871
+ messageId: string;
872
+ }
873
+ ```
874
+
875
+ **Example:**
876
+
877
+ ```typescript
878
+ const result = await matimo.execute('gmail-delete-message', {
879
+ messageId: '18b8f4a2a1c5e3d2',
880
+ });
881
+ ```
882
+
883
+ ## Integration Patterns
884
+
885
+ ### Pattern 1: Factory Pattern (Direct SDK)
886
+
887
+ Use when you have explicit parameters:
888
+
889
+ ```typescript
890
+ import { MatimoInstance } from 'matimo';
891
+ import path from 'path';
892
+
893
+ const matimo = await MatimoInstance.init(path.join(__dirname, 'tools'));
894
+
895
+ // Tool executes, token auto-injected from GMAIL_ACCESS_TOKEN env var
896
+ const result = await matimo.execute('gmail-send-email', {
897
+ to: 'user@example.com',
898
+ subject: 'Hello',
899
+ body: 'Message',
900
+ });
901
+ ```
902
+
903
+ **When to use:** Scripts, cron jobs, simple automation
904
+
905
+ ---
906
+
907
+ ### Pattern 2: Decorator Pattern (LangChain Decorators)
908
+
909
+ Use when building agent frameworks:
910
+
911
+ ```typescript
912
+ import { tool } from 'langchain';
913
+
914
+ class EmailAgent {
915
+ @tool('gmail-send-email')
916
+ async sendEmail(to: string, subject: string, body: string) {
917
+ return undefined; // Matimo intercepts and executes
918
+ }
919
+ }
920
+ ```
921
+
922
+ **When to use:** Framework integration, reusable agents
923
+
924
+ ---
925
+
926
+ ### Pattern 3: AI Agent Pattern (OpenAI + LangChain)
927
+
928
+ Use when you want LLM to decide which tool to use:
929
+
930
+ ```typescript
931
+ import { createAgent } from 'langchain';
932
+ import { ChatOpenAI } from '@langchain/openai';
933
+
934
+ const agent = await createAgent({
935
+ model: new ChatOpenAI({ modelName: 'gpt-4o-mini' }),
936
+ tools: gmailTools,
937
+ });
938
+
939
+ // Natural language request
940
+ await agent.invoke({
941
+ messages: [
942
+ {
943
+ role: 'user',
944
+ content: 'Send me a test email',
945
+ },
946
+ ],
947
+ });
948
+ // Agent decides which tool to use and calls it!
949
+ ```
950
+
951
+ **When to use:** Autonomous agents, natural language interfaces
952
+
953
+ ---
954
+
955
+ ## Advanced Usage
956
+
957
+ ### Gmail Search Query Syntax
958
+
959
+ Use powerful Gmail search in `list-messages`:
960
+
961
+ ```typescript
962
+ // Single condition
963
+ await matimo.execute('gmail-list-messages', {
964
+ query: 'from:alice@example.com',
965
+ maxResults: 10,
966
+ });
967
+
968
+ // Multiple conditions
969
+ await matimo.execute('gmail-list-messages', {
970
+ query: 'from:alice@example.com subject:meeting is:unread',
971
+ maxResults: 10,
972
+ });
973
+ ```
974
+
975
+ **Common search operators:**
976
+
977
+ ```
978
+ from:alice@example.com # From specific sender
979
+ to:bob@example.com # To specific recipient
980
+ subject:meeting # Keywords in subject
981
+ body:coffee # Keywords in body
982
+ has:attachment # Has attachments
983
+ is:unread # Unread emails
984
+ is:starred # Starred emails
985
+ is:important # Marked important
986
+ label:work # With specific label
987
+ before:2024/01/01 # Before date
988
+ after:2023/12/01 # After date
989
+ filename:pdf # Specific attachment type
990
+ ```
991
+
992
+ ---
993
+
994
+ ### Pagination
995
+
996
+ For large email lists, use pagination:
997
+
998
+ ```typescript
999
+ let pageToken: string | undefined = undefined;
1000
+ let allMessages = [];
1001
+
1002
+ while (true) {
1003
+ const result = await matimo.execute('gmail-list-messages', {
1004
+ maxResults: 100,
1005
+ pageToken: pageToken,
1006
+ });
1007
+
1008
+ allMessages = allMessages.concat(result.messages);
1009
+
1010
+ if (!result.nextPageToken) break;
1011
+ pageToken = result.nextPageToken;
1012
+ }
1013
+
1014
+ console.log(`Total messages: ${allMessages.length}`);
1015
+ ```
1016
+
1017
+ ---
1018
+
1019
+ ### HTML Emails
1020
+
1021
+ Send formatted HTML emails:
1022
+
1023
+ ```typescript
1024
+ await matimo.execute('gmail-send-email', {
1025
+ to: 'user@example.com',
1026
+ subject: 'HTML Email Example',
1027
+ body: `
1028
+ <h1>Hello!</h1>
1029
+ <p>This is an <strong>HTML</strong> email.</p>
1030
+ <a href="https://example.com">Click here</a>
1031
+ `,
1032
+ isHtml: true, // Enable HTML parsing
1033
+ });
1034
+ ```
1035
+
1036
+ ---
1037
+
1038
+ ### Multiple Recipients
1039
+
1040
+ Send to CC/BCC recipients:
1041
+
1042
+ ```typescript
1043
+ await matimo.execute('gmail-send-email', {
1044
+ to: 'primary@example.com',
1045
+ cc: 'cc1@example.com,cc2@example.com', // Comma-separated
1046
+ bcc: 'bcc@example.com',
1047
+ subject: 'Team Update',
1048
+ body: 'Status update for the team',
1049
+ });
1050
+ ```
1051
+
1052
+ ---
1053
+
1054
+ ### How Parameter Encoding Works
1055
+
1056
+ Gmail requires emails in MIME format (base64url). Matimo handles this automatically via YAML:
1057
+
1058
+ **Your code:**
1059
+
1060
+ ```typescript
1061
+ await matimo.execute('gmail-send-email', {
1062
+ to: 'user@example.com',
1063
+ subject: 'Hello',
1064
+ body: 'Message',
1065
+ });
1066
+ ```
1067
+
1068
+ **What Matimo does:**
1069
+
1070
+ ```
1071
+ 1. Read parameters: to, subject, body
1072
+ 2. Build MIME message:
1073
+ From: <your-account>
1074
+ To: user@example.com
1075
+ Subject: Hello
1076
+
1077
+ Message
1078
+
1079
+ 3. Encode as base64url (required by Gmail API)
1080
+ 4. Send as: POST /send with {message: {raw: "base64string"}}
1081
+ ```
1082
+
1083
+ **This is defined in YAML:**
1084
+
1085
+ ```yaml
1086
+ parameter_encoding:
1087
+ - source: [to, subject, body, cc, bcc, isHtml]
1088
+ target: raw
1089
+ encoding: mime_rfc2822_base64url # Handles all the above
1090
+ ```
1091
+
1092
+ ---
1093
+
1094
+ ## Security & Best Practices
1095
+
1096
+ ### "Missing GMAIL_ACCESS_TOKEN"
1097
+
1098
+ **Problem:** Error when trying to use Gmail tools without token.
1099
+
1100
+ **Solution:**
1101
+
1102
+ ```bash
1103
+ # Check if environment variable is set
1104
+ echo $GMAIL_ACCESS_TOKEN
1105
+
1106
+ # Set it if missing
1107
+ export GMAIL_ACCESS_TOKEN=ya29.a0AfH6SMBx...
1108
+ ```
1109
+
1110
+ ### "Invalid Credentials (401)"
1111
+
1112
+ **Problem:** Gmail API returns 401 Unauthorized.
1113
+
1114
+ **Possible causes:**
1115
+
1116
+ 1. Token is expired (access tokens expire after ~1 hour)
1117
+ 2. Token has wrong scopes
1118
+ 3. Token is for wrong Google account
1119
+ 4. Application not authorized in Google Cloud
1120
+
1121
+ **Solution:**
1122
+
1123
+ 1. Get a fresh token (especially if > 1 hour old)
1124
+ 2. Check scopes match your app's needs
1125
+ 3. Re-authenticate with the correct account
1126
+ 4. Verify app is authorized in Google Cloud Console
1127
+
1128
+ ### "Permission Denied (403)"
1129
+
1130
+ **Problem:** Gmail API returns 403 Forbidden.
1131
+
1132
+ **Possible causes:**
1133
+
1134
+ 1. Token missing required scope
1135
+ 2. Trying to access another user's mailbox
1136
+ 3. Gmail API not enabled in Cloud project
1137
+ 4. Rate limit exceeded
1138
+
1139
+ **Solution:**
1140
+
1141
+ 1. Add required scopes when getting token
1142
+ 2. Ensure token is for the account you're accessing
1143
+ 3. Enable Gmail API in Cloud Console
1144
+ 4. Wait before retrying (rate limited)
1145
+
1146
+ ### "Invalid Token Format"
1147
+
1148
+ **Problem:** Error when passing token parameter.
1149
+
1150
+ **Solution:**
1151
+ Ensure token is a string and properly passed:
1152
+
1153
+ ```typescript
1154
+ // ✅ Correct
1155
+ GMAIL_ACCESS_TOKEN: process.env.GMAIL_ACCESS_TOKEN;
1156
+
1157
+ // ❌ Wrong
1158
+ GMAIL_ACCESS_TOKEN: undefined; // Missing env var
1159
+ GMAIL_ACCESS_TOKEN: {
1160
+ token: 'ya29...';
1161
+ } // Object instead of string
1162
+ ```
1163
+
1164
+ ## Security Best Practices
1165
+
1166
+ ### ✅ DO
1167
+
1168
+ - Store tokens in environment variables
1169
+ - Use `.env` files locally (not in git)
1170
+ - Rotate tokens regularly
1171
+ - Use minimum required scopes
1172
+ - Implement server-side token refresh (Phase 3)
1173
+ - Log token refresh events
1174
+ - Monitor token usage for suspicious activity
1175
+
1176
+ ### ❌ DON'T
1177
+
1178
+ - Hardcode tokens in source files
1179
+ - Commit `.env` files to git
1180
+ - Share tokens between users
1181
+ - Use full account access when limited scope available
1182
+ - Log full tokens (log truncated: `ya29.a0...`)
1183
+ - Expose tokens in error messages
1184
+ - Store tokens in localStorage (browser)
1185
+ - Use same token for multiple apps
1186
+
1187
+ ## Troubleshooting
1188
+
1189
+ # Use in script
1190
+
1191
+ pnpm exec ts-node examples/gmail-oauth-usage.ts
1192
+
1193
+ # Or use in Node REPL
1194
+
1195
+ node
1196
+
1197
+ > process.env.GMAIL_ACCESS_TOKEN
1198
+ > // Use in matimo.execute()
1199
+
1200
+ ````
1201
+
1202
+ ## API Reference
1203
+
1204
+ ### send-email
1205
+
1206
+ Sends an email via Gmail API.
1207
+
1208
+ **Parameters:**
1209
+ - `to` (required): Recipient email(s), comma-separated
1210
+ - `subject` (required): Email subject
1211
+ - `body` (required): Email body (plain text or HTML)
1212
+ - `cc` (optional): CC recipients
1213
+ - `bcc` (optional): BCC recipients
1214
+ - `isHtml` (optional): Treat body as HTML (default: false)
1215
+ - `GMAIL_ACCESS_TOKEN` (required): OAuth access token
1216
+
1217
+ **Response:**
1218
+ ```typescript
1219
+ {
1220
+ id: string; // Message ID
1221
+ threadId: string; // Thread ID
1222
+ labelIds: string[]; // Applied labels
1223
+ }
1224
+ ````
1225
+
1226
+ ### list-messages
1227
+
1228
+ Lists emails from your mailbox.
1229
+
1230
+ **Parameters:**
1231
+
1232
+ - `query` (optional): Search query (e.g., "from:user@example.com")
1233
+ - `maxResults` (optional): Max messages to return (1-500)
1234
+ - `pageToken` (optional): Token for pagination
1235
+ - `labelIds` (optional): Filter by label IDs
1236
+ - `includeSpamTrash` (optional): Include spam/trash
1237
+ - `GMAIL_ACCESS_TOKEN` (required): OAuth access token
1238
+
1239
+ **Response:**
1240
+
1241
+ ```typescript
1242
+ {
1243
+ messages: Array<{ id: string; threadId: string }>;
1244
+ nextPageToken?: string; // For pagination
1245
+ resultSizeEstimate: number;
1246
+ }
1247
+ ```
1248
+
1249
+ ### get-message
1250
+
1251
+ Gets a specific message with full details.
1252
+
1253
+ **Parameters:**
1254
+
1255
+ - `messageId` (required): Message ID to retrieve
1256
+ - `format` (optional): Response format ("minimal" | "full" | "raw")
1257
+ - `GMAIL_ACCESS_TOKEN` (required): OAuth access token
1258
+
1259
+ **Response:**
1260
+
1261
+ ```typescript
1262
+ {
1263
+ id: string;
1264
+ threadId: string;
1265
+ headers: Record<string, string>;
1266
+ body: { data?: string };
1267
+ attachments?: any[];
1268
+ }
1269
+ ```
1270
+
1271
+ ### create-draft
1272
+
1273
+ Creates a draft email.
1274
+
1275
+ **Parameters:**
1276
+
1277
+ - `to` (required): Draft recipient
1278
+ - `subject` (required): Draft subject
1279
+ - `body` (required): Draft body
1280
+ - `cc` (optional): CC recipients
1281
+ - `bcc` (optional): BCC recipients
1282
+ - `isHtml` (optional): Treat body as HTML
1283
+ - `GMAIL_ACCESS_TOKEN` (required): OAuth access token
1284
+
1285
+ **Response:**
1286
+
1287
+ ```typescript
1288
+ {
1289
+ id: string; // Draft ID
1290
+ }
1291
+ ```
1292
+
1293
+ ### delete-message
1294
+
1295
+ Permanently deletes a message.
1296
+
1297
+ **Parameters:**
1298
+
1299
+ - `messageId` (required): Message ID to delete
1300
+ - `GMAIL_ACCESS_TOKEN` (required): OAuth access token
1301
+
1302
+ **Response:**
1303
+
1304
+ ```typescript
1305
+ {
1306
+ success: boolean;
1307
+ }
1308
+ ```
1309
+
1310
+ ## Additional Resources
1311
+
1312
+ - [Gmail API Documentation](https://developers.google.com/gmail/api)
1313
+ - [Gmail API Authentication Guide](https://developers.google.com/gmail/api/auth/about-auth)
1314
+ - [OAuth 2.0 Playground](https://developers.google.com/oauthplayground)
1315
+ - [Google Cloud Console](https://console.cloud.google.com/)
1316
+ - [Matimo Documentation](../../README.md)