@memberjunction/communication-ms-graph 4.0.0 → 4.2.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 +251 -0
- package/package.json +9 -9
- package/readme.md +188 -195
package/README.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# @memberjunction/communication-ms-graph
|
|
2
|
+
|
|
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
|
+
```
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @memberjunction/communication-ms-graph
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
Set the following environment variables:
|
|
48
|
+
|
|
49
|
+
```env
|
|
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
|
|
54
|
+
```
|
|
55
|
+
|
|
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 |
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
### Sending Email
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
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
|
+
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Per-Request Credentials
|
|
112
|
+
|
|
113
|
+
Override credentials on a per-request basis for multi-tenant scenarios:
|
|
114
|
+
|
|
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
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Reading Messages
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const provider = engine.GetProvider('Microsoft Graph');
|
|
137
|
+
|
|
138
|
+
const result = await provider.GetMessages({
|
|
139
|
+
NumMessages: 10,
|
|
140
|
+
UnreadOnly: true,
|
|
141
|
+
IncludeHeaders: true,
|
|
142
|
+
ContextData: {
|
|
143
|
+
ReturnAsPlainText: true,
|
|
144
|
+
MarkAsRead: true
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
result.Messages.forEach(msg => {
|
|
149
|
+
console.log(`${msg.From}: ${msg.Subject}`);
|
|
150
|
+
console.log(`Thread: ${msg.ThreadID}`);
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Searching Messages
|
|
155
|
+
|
|
156
|
+
MS Graph supports KQL (Keyword Query Language) for search:
|
|
157
|
+
|
|
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
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Creating Drafts
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const result = await engine.CreateDraft(message, 'Microsoft Graph', contextUser);
|
|
171
|
+
if (result.Success) {
|
|
172
|
+
console.log(`Draft ID: ${result.DraftID}`);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Managing Folders
|
|
177
|
+
|
|
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
|
+
```
|
|
200
|
+
|
|
201
|
+
### Downloading Attachments
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
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
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Client Caching
|
|
216
|
+
|
|
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`.
|
|
218
|
+
|
|
219
|
+
## System Folder Mapping
|
|
220
|
+
|
|
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` |
|
|
230
|
+
|
|
231
|
+
## HTML to Text Conversion
|
|
232
|
+
|
|
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.
|
|
234
|
+
|
|
235
|
+
## Dependencies
|
|
236
|
+
|
|
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 |
|
|
245
|
+
|
|
246
|
+
## Development
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
npm run build # Compile TypeScript
|
|
250
|
+
npm run clean # Remove dist directory
|
|
251
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/communication-ms-graph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.2.0",
|
|
5
5
|
"description": "MemberJunction: Microsoft Graph Provider for the MJ Communication Framework",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@azure/identity": "^4.13.0",
|
|
25
25
|
"@azure/msal-node": "^5.0.3",
|
|
26
|
-
"@memberjunction/ai": "4.
|
|
27
|
-
"@memberjunction/ai-provider-bundle": "4.
|
|
28
|
-
"@memberjunction/aiengine": "4.
|
|
29
|
-
"@memberjunction/communication-types": "4.
|
|
30
|
-
"@memberjunction/core": "4.
|
|
31
|
-
"@memberjunction/core-entities": "4.
|
|
32
|
-
"@memberjunction/global": "4.
|
|
33
|
-
"@memberjunction/sqlserver-dataprovider": "4.
|
|
26
|
+
"@memberjunction/ai": "4.2.0",
|
|
27
|
+
"@memberjunction/ai-provider-bundle": "4.2.0",
|
|
28
|
+
"@memberjunction/aiengine": "4.2.0",
|
|
29
|
+
"@memberjunction/communication-types": "4.2.0",
|
|
30
|
+
"@memberjunction/core": "4.2.0",
|
|
31
|
+
"@memberjunction/core-entities": "4.2.0",
|
|
32
|
+
"@memberjunction/global": "4.2.0",
|
|
33
|
+
"@memberjunction/sqlserver-dataprovider": "4.2.0",
|
|
34
34
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
35
35
|
"@microsoft/microsoft-graph-types": "^2.43.1",
|
|
36
36
|
"@types/html-to-text": "^9.0.4",
|
package/readme.md
CHANGED
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
# @memberjunction/communication-ms-graph
|
|
2
2
|
|
|
3
|
-
Microsoft Graph
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
47
|
+
Set the following environment variables:
|
|
28
48
|
|
|
29
49
|
```env
|
|
30
|
-
|
|
31
|
-
AZURE_CLIENT_ID=your-client-id
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
###
|
|
88
|
+
### Sending Email
|
|
58
89
|
|
|
59
90
|
```typescript
|
|
60
|
-
import {
|
|
61
|
-
import {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
113
|
+
Override credentials on a per-request basis for multi-tenant scenarios:
|
|
81
114
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
###
|
|
133
|
+
### Reading Messages
|
|
90
134
|
|
|
91
135
|
```typescript
|
|
92
|
-
|
|
93
|
-
import { GetMessagesContextDataParams } from '@memberjunction/communication-ms-graph';
|
|
136
|
+
const provider = engine.GetProvider('Microsoft Graph');
|
|
94
137
|
|
|
95
|
-
const
|
|
138
|
+
const result = await provider.GetMessages({
|
|
96
139
|
NumMessages: 10,
|
|
97
140
|
UnreadOnly: true,
|
|
141
|
+
IncludeHeaders: true,
|
|
98
142
|
ContextData: {
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
156
|
+
MS Graph supports KQL (Keyword Query Language) for search:
|
|
135
157
|
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
###
|
|
167
|
+
### Creating Drafts
|
|
142
168
|
|
|
143
169
|
```typescript
|
|
144
|
-
|
|
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(
|
|
172
|
+
console.log(`Draft ID: ${result.DraftID}`);
|
|
158
173
|
}
|
|
159
174
|
```
|
|
160
175
|
|
|
161
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
184
|
-
Context data specific to MS Graph operations:
|
|
201
|
+
### Downloading Attachments
|
|
185
202
|
|
|
186
203
|
```typescript
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
231
|
+
## HTML to Text Conversion
|
|
219
232
|
|
|
220
|
-
|
|
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
|
-
##
|
|
235
|
+
## Dependencies
|
|
226
236
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
232
|
-
npm start
|
|
246
|
+
## Development
|
|
233
247
|
|
|
234
|
-
|
|
235
|
-
npm
|
|
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
|