@memberjunction/communication-ms-graph 3.4.0 → 4.1.0

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 CHANGED
@@ -1,20 +1,40 @@
1
1
  # @memberjunction/communication-ms-graph
2
2
 
3
- Microsoft Graph Provider for the MemberJunction Communication Framework. This package provides email communication capabilities through Microsoft Graph API, allowing you to send, receive, reply to, and forward emails using Azure Active Directory service accounts.
4
-
5
- ## Overview
6
-
7
- The `@memberjunction/communication-ms-graph` package implements the `BaseCommunicationProvider` interface from the MemberJunction communication framework, specifically for Microsoft Graph email operations. It uses OAuth 2.0 client credentials flow for authentication and supports full email functionality including HTML/text content, attachments, and thread management.
8
-
9
- ## Features
10
-
11
- - **Send Emails**: Send single or bulk emails with HTML/text content
12
- - **Receive Emails**: Fetch emails with filtering, pagination, and read status management
13
- - **Reply to Emails**: Reply to existing email threads
14
- - **Forward Emails**: Forward emails to multiple recipients
15
- - **HTML to Text Conversion**: Automatic conversion of HTML email content to plain text
16
- - **Thread Management**: Track email conversations using thread IDs
17
- - **Service Account Support**: Uses Azure AD service accounts for authentication
3
+ Microsoft Graph (Office 365 / Exchange Online) provider for the MemberJunction Communication Framework. This provider enables full mailbox operations -- sending, receiving, searching, managing folders, attachments, drafts, and more -- through the Microsoft Graph API with Azure AD application authentication.
4
+
5
+ ## Architecture
6
+
7
+ ```mermaid
8
+ graph TD
9
+ subgraph msgraph["@memberjunction/communication-ms-graph"]
10
+ MSP["MSGraphProvider"]
11
+ AUTH["Auth Module\n(ClientSecretCredential)"]
12
+ CFG["Config Module\n(Environment Variables)"]
13
+ CRED["MSGraphCredentials"]
14
+ end
15
+
16
+ subgraph azure["Azure / Microsoft"]
17
+ AAD["Azure AD\n(OAuth2 Client Credentials)"]
18
+ GRAPH["Microsoft Graph API\n(/users/email/...)"]
19
+ MAIL["Exchange Online\nMailbox"]
20
+ end
21
+
22
+ subgraph base["@memberjunction/communication-types"]
23
+ BCP["BaseCommunicationProvider"]
24
+ end
25
+
26
+ BCP --> MSP
27
+ MSP --> AUTH
28
+ MSP --> CFG
29
+ MSP --> CRED
30
+ AUTH --> AAD
31
+ MSP --> GRAPH
32
+ GRAPH --> MAIL
33
+
34
+ style msgraph fill:#2d6a9f,stroke:#1a4971,color:#fff
35
+ style azure fill:#7c5295,stroke:#563a6b,color:#fff
36
+ style base fill:#2d8659,stroke:#1a5c3a,color:#fff
37
+ ```
18
38
 
19
39
  ## Installation
20
40
 
@@ -24,235 +44,208 @@ npm install @memberjunction/communication-ms-graph
24
44
 
25
45
  ## Configuration
26
46
 
27
- This provider requires the following environment variables to be set:
47
+ Set the following environment variables:
28
48
 
29
49
  ```env
30
- # Azure AD Application Registration
31
- AZURE_CLIENT_ID=your-client-id
32
- AZURE_TENANT_ID=your-tenant-id
33
- AZURE_CLIENT_SECRET=your-client-secret
34
-
35
- # Azure Endpoints
36
- AZURE_AAD_ENDPOINT=https://login.microsoftonline.com
37
- AZURE_GRAPH_ENDPOINT=https://graph.microsoft.com
38
-
39
- # Service Account
40
- AZURE_ACCOUNT_EMAIL=serviceaccount@yourdomain.com
41
- AZURE_ACCOUNT_ID=optional-account-id
50
+ AZURE_TENANT_ID=your-azure-tenant-id
51
+ AZURE_CLIENT_ID=your-azure-app-client-id
52
+ AZURE_CLIENT_SECRET=your-azure-app-client-secret
53
+ AZURE_ACCOUNT_EMAIL=mailbox@yourdomain.com
42
54
  ```
43
55
 
44
- ### Azure AD Setup
45
-
46
- 1. Register an application in Azure Active Directory
47
- 2. Grant the following Microsoft Graph API permissions:
48
- - `Mail.Read`
49
- - `Mail.ReadWrite`
50
- - `Mail.Send`
51
- - `User.Read.All`
52
- 3. Create a client secret for the application
53
- 4. Grant admin consent for the permissions
56
+ ### Required Azure AD App Permissions (Application type)
57
+
58
+ | Permission | Operations |
59
+ |-----------|------------|
60
+ | `Mail.Send` | SendSingleMessage, ForwardMessage, ReplyToMessage |
61
+ | `Mail.Read` | GetMessages, GetSingleMessage, SearchMessages, ListFolders, ListAttachments, DownloadAttachment |
62
+ | `Mail.ReadWrite` | CreateDraft, DeleteMessage, MoveMessage, MarkAsRead, ArchiveMessage |
63
+ | `User.Read.All` | GetServiceAccount (user lookup, optional) |
64
+
65
+ ## Supported Operations
66
+
67
+ This provider supports all 14 operations defined in `BaseCommunicationProvider`:
68
+
69
+ | Operation | Description |
70
+ |-----------|-------------|
71
+ | `SendSingleMessage` | Send email via Graph API |
72
+ | `GetMessages` | Retrieve messages with filtering and header extraction |
73
+ | `GetSingleMessage` | Retrieve a single message by ID |
74
+ | `ForwardMessage` | Forward email to new recipients |
75
+ | `ReplyToMessage` | Reply to an existing email thread |
76
+ | `CreateDraft` | Create a draft message in the mailbox |
77
+ | `DeleteMessage` | Move to Deleted Items or permanently delete |
78
+ | `MoveMessage` | Move message to a different mail folder |
79
+ | `ListFolders` | List mail folders with optional message counts |
80
+ | `MarkAsRead` | Mark messages as read or unread (batch) |
81
+ | `ArchiveMessage` | Move message to Archive folder |
82
+ | `SearchMessages` | Full-text search with KQL syntax and date filtering |
83
+ | `ListAttachments` | List attachments on a message |
84
+ | `DownloadAttachment` | Download attachment content as base64/Buffer |
54
85
 
55
86
  ## Usage
56
87
 
57
- ### Basic Setup
88
+ ### Sending Email
58
89
 
59
90
  ```typescript
60
- import { MSGraphProvider } from '@memberjunction/communication-ms-graph';
61
- import { ProcessedMessage } from '@memberjunction/communication-types';
62
-
63
- // The provider is automatically registered with the MemberJunction framework
64
- // using the @RegisterClass decorator with name 'Microsoft Graph'
65
- const provider = new MSGraphProvider();
91
+ import { CommunicationEngine } from '@memberjunction/communication-engine';
92
+ import { Message } from '@memberjunction/communication-types';
93
+
94
+ const engine = CommunicationEngine.Instance;
95
+ await engine.Config(false, contextUser);
96
+
97
+ const message = new Message();
98
+ message.From = 'user@yourdomain.com';
99
+ message.To = 'recipient@example.com';
100
+ message.Subject = 'Hello from MS Graph';
101
+ message.HTMLBody = '<h1>Hello</h1><p>Sent via Microsoft Graph.</p>';
102
+ message.ContextData = { saveToSentItems: true };
103
+
104
+ const result = await engine.SendSingleMessage(
105
+ 'Microsoft Graph',
106
+ 'Standard Email',
107
+ message
108
+ );
66
109
  ```
67
110
 
68
- ### Sending an Email
69
-
70
- ```typescript
71
- const message: ProcessedMessage = {
72
- To: 'recipient@example.com',
73
- Subject: 'Test Email',
74
- ProcessedBody: 'This is a plain text email',
75
- ProcessedHTMLBody: '<h1>This is an HTML email</h1>',
76
- CCRecipients: ['cc@example.com'],
77
- BCCRecipients: ['bcc@example.com']
78
- };
111
+ ### Per-Request Credentials
79
112
 
80
- const result = await provider.SendSingleMessage(message);
113
+ Override credentials on a per-request basis for multi-tenant scenarios:
81
114
 
82
- if (result.Success) {
83
- console.log('Email sent successfully');
84
- } else {
85
- console.error('Failed to send email:', result.Error);
86
- }
115
+ ```typescript
116
+ import { MSGraphCredentials } from '@memberjunction/communication-ms-graph';
117
+
118
+ const result = await engine.SendSingleMessage(
119
+ 'Microsoft Graph',
120
+ 'Standard Email',
121
+ message,
122
+ undefined,
123
+ false,
124
+ {
125
+ tenantId: 'customer-tenant-id',
126
+ clientId: 'customer-app-id',
127
+ clientSecret: 'customer-secret',
128
+ accountEmail: 'user@customer.com'
129
+ } as MSGraphCredentials
130
+ );
87
131
  ```
88
132
 
89
- ### Receiving Emails
133
+ ### Reading Messages
90
134
 
91
135
  ```typescript
92
- import { GetMessagesParams } from '@memberjunction/communication-types';
93
- import { GetMessagesContextDataParams } from '@memberjunction/communication-ms-graph';
136
+ const provider = engine.GetProvider('Microsoft Graph');
94
137
 
95
- const params: GetMessagesParams<GetMessagesContextDataParams> = {
138
+ const result = await provider.GetMessages({
96
139
  NumMessages: 10,
97
140
  UnreadOnly: true,
141
+ IncludeHeaders: true,
98
142
  ContextData: {
99
- Email: 'optional-service-account@domain.com', // Optional, defaults to AZURE_ACCOUNT_EMAIL
100
- ReturnAsPlainText: true, // Converts HTML to plain text
101
- MarkAsRead: true, // Marks messages as read after fetching
102
- Filter: "(importance eq 'high')", // Optional OData filter
103
- Top: 20 // Optional, overrides NumMessages
143
+ ReturnAsPlainText: true,
144
+ MarkAsRead: true
104
145
  }
105
- };
146
+ });
106
147
 
107
- const result = await provider.GetMessages(params);
108
-
109
- if (result.Success) {
110
- result.Messages.forEach(message => {
111
- console.log(`From: ${message.From}`);
112
- console.log(`Subject: ${message.Subject}`);
113
- console.log(`Body: ${message.Body}`);
114
- console.log(`Thread ID: ${message.ThreadID}`);
115
- });
116
- }
148
+ result.Messages.forEach(msg => {
149
+ console.log(`${msg.From}: ${msg.Subject}`);
150
+ console.log(`Thread: ${msg.ThreadID}`);
151
+ });
117
152
  ```
118
153
 
119
- ### Replying to an Email
120
-
121
- ```typescript
122
- import { ReplyToMessageParams } from '@memberjunction/communication-types';
123
-
124
- const replyParams: ReplyToMessageParams = {
125
- MessageID: 'original-message-id',
126
- Message: {
127
- To: 'recipient@example.com',
128
- ProcessedBody: 'This is my reply',
129
- CCRecipients: ['cc@example.com'],
130
- BCCRecipients: ['bcc@example.com']
131
- }
132
- };
154
+ ### Searching Messages
133
155
 
134
- const result = await provider.ReplyToMessage(replyParams);
156
+ MS Graph supports KQL (Keyword Query Language) for search:
135
157
 
136
- if (result.Success) {
137
- console.log('Reply sent successfully');
138
- }
158
+ ```typescript
159
+ const result = await provider.SearchMessages({
160
+ Query: 'invoice',
161
+ FromDate: new Date('2025-01-01'),
162
+ MaxResults: 25,
163
+ FolderID: 'inbox-folder-id'
164
+ });
139
165
  ```
140
166
 
141
- ### Forwarding an Email
167
+ ### Creating Drafts
142
168
 
143
169
  ```typescript
144
- import { ForwardMessageParams } from '@memberjunction/communication-types';
145
-
146
- const forwardParams: ForwardMessageParams = {
147
- MessageID: 'original-message-id',
148
- Message: 'Please see the forwarded message below',
149
- ToRecipients: ['forward-to@example.com'],
150
- CCRecipients: ['cc@example.com'],
151
- BCCRecipients: ['bcc@example.com']
152
- };
153
-
154
- const result = await provider.ForwardMessage(forwardParams);
155
-
170
+ const result = await engine.CreateDraft(message, 'Microsoft Graph', contextUser);
156
171
  if (result.Success) {
157
- console.log('Message forwarded successfully');
172
+ console.log(`Draft ID: ${result.DraftID}`);
158
173
  }
159
174
  ```
160
175
 
161
- ## API Reference
162
-
163
- ### MSGraphProvider
164
-
165
- The main class that implements email communication through Microsoft Graph.
166
-
167
- #### Methods
168
-
169
- ##### `SendSingleMessage(message: ProcessedMessage): Promise<MessageResult>`
170
- Sends a single email message.
171
-
172
- ##### `GetMessages(params: GetMessagesParams<GetMessagesContextDataParams>): Promise<GetMessagesResult<Message>>`
173
- Retrieves emails from the service account's mailbox with optional filtering.
176
+ ### Managing Folders
174
177
 
175
- ##### `ReplyToMessage(params: ReplyToMessageParams): Promise<ReplyToMessageResult>`
176
- Replies to an existing email thread.
177
-
178
- ##### `ForwardMessage(params: ForwardMessageParams): Promise<ForwardMessageResult>`
179
- Forwards an email to specified recipients.
180
-
181
- ### Types
178
+ ```typescript
179
+ // List top-level folders
180
+ const folders = await provider.ListFolders({ IncludeCounts: true });
181
+ folders.Folders.forEach(f => {
182
+ console.log(`${f.Name}: ${f.MessageCount} total, ${f.UnreadCount} unread`);
183
+ });
184
+
185
+ // List subfolders
186
+ const subfolders = await provider.ListFolders({
187
+ ParentFolderID: 'parent-folder-id',
188
+ IncludeCounts: true
189
+ });
190
+
191
+ // Move a message
192
+ await provider.MoveMessage({
193
+ MessageID: 'msg-id',
194
+ DestinationFolderID: 'folder-id'
195
+ });
196
+
197
+ // Archive a message
198
+ await provider.ArchiveMessage({ MessageID: 'msg-id' });
199
+ ```
182
200
 
183
- #### `GetMessagesContextDataParams`
184
- Context data specific to MS Graph operations:
201
+ ### Downloading Attachments
185
202
 
186
203
  ```typescript
187
- type GetMessagesContextDataParams = {
188
- Email?: string; // Service account email (optional)
189
- ReturnAsPlainText?: boolean; // Convert HTML to plain text
190
- MarkAsRead?: boolean; // Mark messages as read after fetching
191
- Filter?: string; // OData filter for message query
192
- Top?: number; // Number of messages to return
204
+ const attachments = await provider.ListAttachments({ MessageID: 'msg-id' });
205
+ for (const att of attachments.Attachments) {
206
+ const download = await provider.DownloadAttachment({
207
+ MessageID: 'msg-id',
208
+ AttachmentID: att.ID
209
+ });
210
+ // download.Content is a Buffer
211
+ // download.ContentBase64 is the raw base64 string
193
212
  }
194
213
  ```
195
214
 
196
- ## Dependencies
197
-
198
- ### Core Dependencies
199
- - `@memberjunction/communication-types`: Base types and interfaces
200
- - `@memberjunction/core`: Core MemberJunction functionality
201
- - `@memberjunction/core-entities`: Entity management
202
- - `@memberjunction/global`: Global utilities and decorators
215
+ ## Client Caching
203
216
 
204
- ### Microsoft Graph Dependencies
205
- - `@microsoft/microsoft-graph-client`: Microsoft Graph API client
206
- - `@microsoft/microsoft-graph-types`: TypeScript types for Graph API
207
- - `@azure/identity`: Azure authentication library
208
- - `@azure/msal-node`: Microsoft Authentication Library
217
+ The provider caches Microsoft Graph `Client` instances per credential set for performance. Environment credential clients are shared across all calls; per-request credential clients are cached by `tenantId:clientId`.
209
218
 
210
- ### Utility Dependencies
211
- - `html-to-text`: HTML to plain text conversion
212
- - `axios`: HTTP client
213
- - `dotenv`: Environment variable management
214
- - `env-var`: Environment variable validation
219
+ ## System Folder Mapping
215
220
 
216
- ## Integration with MemberJunction
221
+ | Exchange Display Name | SystemFolderType |
222
+ |----------------------|-----------------|
223
+ | Inbox | `inbox` |
224
+ | Sent Items | `sent` |
225
+ | Drafts | `drafts` |
226
+ | Deleted Items | `trash` |
227
+ | Junk Email | `spam` |
228
+ | Archive | `archive` |
229
+ | Other folders | `other` |
217
230
 
218
- This provider integrates seamlessly with the MemberJunction communication framework:
231
+ ## HTML to Text Conversion
219
232
 
220
- 1. **Automatic Registration**: The provider is automatically registered using the `@RegisterClass` decorator
221
- 2. **Entity Support**: Works with MemberJunction entities for message persistence
222
- 3. **AI Integration**: Compatible with AI-powered message processing through `@memberjunction/ai` packages
223
- 4. **Template Support**: Can be used with the MemberJunction template engine for dynamic content
233
+ When `ReturnAsPlainText` is set in `ContextData`, the provider uses the `html-to-text` library to convert HTML email bodies to plain text with 130-character word wrap.
224
234
 
225
- ## Build and Development
235
+ ## Dependencies
226
236
 
227
- ```bash
228
- # Build the package
229
- npm run build
237
+ | Package | Purpose |
238
+ |---------|---------|
239
+ | `@memberjunction/communication-types` | Base provider class and type definitions |
240
+ | `@memberjunction/core` | Logging utilities |
241
+ | `@memberjunction/global` | RegisterClass decorator |
242
+ | `@microsoft/microsoft-graph-client` | Microsoft Graph SDK |
243
+ | `@azure/identity` | Azure AD ClientSecretCredential |
244
+ | `html-to-text` | HTML to plain text conversion |
230
245
 
231
- # Development mode with watch
232
- npm start
246
+ ## Development
233
247
 
234
- # Run tests (not yet implemented)
235
- npm test
248
+ ```bash
249
+ npm run build # Compile TypeScript
250
+ npm run clean # Remove dist directory
236
251
  ```
237
-
238
- ## Error Handling
239
-
240
- The provider includes comprehensive error handling:
241
- - All methods return result objects with `Success` boolean and error details
242
- - Errors are logged using MemberJunction's logging system
243
- - Network and authentication errors are gracefully handled
244
-
245
- ## Security Considerations
246
-
247
- - Uses OAuth 2.0 client credentials flow
248
- - Requires admin-consented permissions
249
- - Service account credentials should be stored securely
250
- - Supports principle of least privilege through scoped permissions
251
-
252
- ## License
253
-
254
- ISC License - see LICENSE file for details.
255
-
256
- ## Author
257
-
258
- MemberJunction.com