# @memberjunction/communication-gmail
Gmail / Google Workspace provider for the MemberJunction Communication Framework. This provider enables full mailbox operations -- sending, receiving, searching, managing labels, attachments, drafts, and more -- through the Gmail API with OAuth2 authentication.
## Architecture
```mermaid
graph TD
subgraph gmail["@memberjunction/communication-gmail"]
GP["GmailProvider"]
AUTH["Auth Module\n(OAuth2 Client)"]
CFG["Config Module\n(Environment Variables)"]
CRED["GmailCredentials"]
end
subgraph google["Google APIs"]
OAUTH["Google OAuth2"]
GAPI["Gmail API v1\n(/users/me/...)"]
MAILBOX["Gmail Mailbox"]
end
subgraph base["@memberjunction/communication-types"]
BCP["BaseCommunicationProvider"]
end
BCP --> GP
GP --> AUTH
GP --> CFG
GP --> CRED
AUTH --> OAUTH
GP --> GAPI
GAPI --> MAILBOX
style gmail fill:#2d6a9f,stroke:#1a4971,color:#fff
style google fill:#7c5295,stroke:#563a6b,color:#fff
style base fill:#2d8659,stroke:#1a5c3a,color:#fff
```
## Installation
```bash
npm install @memberjunction/communication-gmail
```
## Configuration
Set the following environment variables:
```env
GMAIL_CLIENT_ID=your-oauth2-client-id
GMAIL_CLIENT_SECRET=your-oauth2-client-secret
GMAIL_REDIRECT_URI=your-redirect-uri
GMAIL_REFRESH_TOKEN=your-refresh-token
GMAIL_SERVICE_ACCOUNT_EMAIL=noreply@yourdomain.com # optional default sender
```
### Required OAuth2 Scopes
- `https://www.googleapis.com/auth/gmail.send`
- `https://www.googleapis.com/auth/gmail.readonly`
- `https://www.googleapis.com/auth/gmail.modify`
- `https://www.googleapis.com/auth/gmail.compose`
### Obtaining OAuth2 Credentials
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
2. Create or select a project and enable the Gmail API
3. Create OAuth 2.0 Client ID credentials
4. Configure the OAuth consent screen
5. Use the OAuth2 flow to obtain a refresh token with the required scopes
## Supported Operations
This provider supports all 14 operations defined in `BaseCommunicationProvider`:
| Operation | Gmail Implementation |
|-----------|---------------------|
| `SendSingleMessage` | Send via `users.messages.send` |
| `GetMessages` | List and fetch with Gmail search query support |
| `GetSingleMessage` | Fetch single message by ID |
| `ForwardMessage` | Reconstruct and send as RFC 822 attachment |
| `ReplyToMessage` | Send in same thread via `threadId` |
| `CreateDraft` | Create via `users.drafts.create` |
| `DeleteMessage` | Trash or permanently delete |
| `MoveMessage` | Add/remove labels via `users.messages.modify` |
| `ListFolders` | List labels with optional message/unread counts |
| `MarkAsRead` | Add/remove UNREAD label (batch) |
| `ArchiveMessage` | Remove INBOX label |
| `SearchMessages` | Gmail query syntax with date filters |
| `ListAttachments` | Parse message parts recursively for attachments |
| `DownloadAttachment` | Download via `users.messages.attachments.get` |
## Usage
### Sending Email
```typescript
import { CommunicationEngine } from '@memberjunction/communication-engine';
import { Message } from '@memberjunction/communication-types';
const engine = CommunicationEngine.Instance;
await engine.Config(false, contextUser);
const message = new Message();
message.From = 'sender@gmail.com';
message.To = 'recipient@example.com';
message.Subject = 'Hello from Gmail';
message.HTMLBody = '
Hello
';
message.CCRecipients = ['cc@example.com'];
const result = await engine.SendSingleMessage('Gmail', 'Email', message);
```
### Per-Request Credentials
Override credentials for multi-user scenarios:
```typescript
import { GmailCredentials } from '@memberjunction/communication-gmail';
const result = await provider.SendSingleMessage(processedMessage, {
clientId: 'other-client-id',
clientSecret: 'other-secret',
redirectUri: 'other-redirect',
refreshToken: 'user-specific-refresh-token'
} as GmailCredentials);
```
### Retrieving Messages
```typescript
const provider = engine.GetProvider('Gmail');
const result = await provider.GetMessages({
NumMessages: 10,
UnreadOnly: true,
ContextData: {
query: 'from:important@example.com', // Gmail search syntax
MarkAsRead: true
}
});
result.Messages.forEach(msg => {
console.log(`${msg.From}: ${msg.Subject}`);
console.log(`Thread: ${msg.ThreadID}`);
});
```
### Creating Drafts
```typescript
const result = await provider.CreateDraft({ Message: processedMessage });
if (result.Success) {
console.log(`Draft ID: ${result.DraftID}`);
// Draft appears in Gmail drafts folder
}
```
### Searching with Gmail Query Syntax
```typescript
const result = await provider.SearchMessages({
Query: 'has:attachment',
FromDate: new Date('2025-01-01'),
ToDate: new Date('2025-06-01'),
FolderID: 'INBOX', // Gmail label ID
MaxResults: 50
});
```
### Managing Labels (Folders)
```typescript
const folders = await provider.ListFolders({ IncludeCounts: true });
folders.Folders.forEach(f => {
console.log(`${f.Name} (${f.ID}): ${f.MessageCount} messages`);
console.log(` System: ${f.IsSystemFolder}, Type: ${f.SystemFolderType}`);
});
```
### Downloading Attachments
```typescript
const attachments = await provider.ListAttachments({ MessageID: 'msg-id' });
for (const att of attachments.Attachments) {
const download = await provider.DownloadAttachment({
MessageID: 'msg-id',
AttachmentID: att.ID
});
// download.Content is a Buffer
// download.ContentBase64 is base64 string
// download.Filename, download.ContentType available
}
```
## Gmail Label Mapping
Gmail uses labels instead of traditional folders. The provider maps system labels to standard folder types:
| Gmail Label | SystemFolderType |
|-------------|-----------------|
| `INBOX` | `inbox` |
| `SENT` | `sent` |
| `DRAFT` | `drafts` |
| `TRASH` | `trash` |
| `SPAM` | `spam` |
| User labels | `undefined` |
## Client Caching
The provider caches Gmail API client instances for performance. Environment credential clients are shared across all calls; per-request credential clients are cached by a key derived from `clientId` and `refreshToken`.
## Security Considerations
1. Store refresh tokens securely and never commit them to version control
2. Request only the minimum required OAuth2 scopes
3. Use secure methods to manage environment variables in production
4. Regularly rotate client secrets and monitor API usage
## Dependencies
| Package | Purpose |
|---------|---------|
| `@memberjunction/communication-types` | Base provider class and type definitions |
| `@memberjunction/core` | Logging utilities |
| `@memberjunction/global` | RegisterClass decorator |
| `googleapis` | Google APIs Node.js client |
| `dotenv` | Environment variable loading |
| `env-var` | Environment variable validation |
## Development
```bash
npm run build # Compile TypeScript
npm run clean # Remove dist directory
```