n8n-nodes-outlook-subscription 0.1.3 → 0.1.5

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.
@@ -34,7 +34,9 @@ class OutlookSubscription {
34
34
  default: "subscription",
35
35
  options: [
36
36
  { name: "Attachment", value: "attachment" },
37
+ { name: "Draft", value: "draft" },
37
38
  { name: "Message", value: "message" },
39
+ { name: "Sent Item", value: "sentItem" },
38
40
  { name: "Subscription", value: "subscription" },
39
41
  ],
40
42
  },
@@ -68,6 +70,21 @@ class OutlookSubscription {
68
70
  { name: "Reply", value: "reply" },
69
71
  { name: "Reply All", value: "replyAll" },
70
72
  { name: "Send", value: "send" },
73
+ { name: "Patch", value: "patch" },
74
+ ],
75
+ },
76
+ {
77
+ displayName: "Operation",
78
+ name: "operation",
79
+ type: "options",
80
+ noDataExpression: true,
81
+ default: "create",
82
+ displayOptions: { show: { resource: ["draft"] } },
83
+ options: [
84
+ { name: "Create", value: "create" },
85
+ { name: "Delete", value: "delete" },
86
+ { name: "Get", value: "get" },
87
+ { name: "Send", value: "send" },
71
88
  { name: "Update", value: "update" },
72
89
  ],
73
90
  },
@@ -83,6 +100,393 @@ class OutlookSubscription {
83
100
  { name: "List", value: "list" },
84
101
  ],
85
102
  },
103
+ // ── Draft ID ──
104
+ {
105
+ displayName: "Draft ID",
106
+ name: "draftId",
107
+ type: "string",
108
+ default: "",
109
+ required: true,
110
+ displayOptions: {
111
+ show: {
112
+ resource: ["draft"],
113
+ operation: ["delete", "send", "update"],
114
+ },
115
+ },
116
+ placeholder: "AAMkAG...=",
117
+ description: "The ID of the draft message",
118
+ },
119
+ // ── Draft Create: fields ──
120
+ {
121
+ displayName: "Subject",
122
+ name: "draftSubject",
123
+ type: "string",
124
+ default: "",
125
+ displayOptions: {
126
+ show: { resource: ["draft"], operation: ["create"] },
127
+ },
128
+ },
129
+ {
130
+ displayName: "Body",
131
+ name: "draftBody",
132
+ type: "string",
133
+ default: "",
134
+ typeOptions: { rows: 5 },
135
+ displayOptions: {
136
+ show: { resource: ["draft"], operation: ["create"] },
137
+ },
138
+ },
139
+ {
140
+ displayName: "Body Type",
141
+ name: "draftBodyType",
142
+ type: "options",
143
+ default: "html",
144
+ displayOptions: {
145
+ show: { resource: ["draft"], operation: ["create"] },
146
+ },
147
+ options: [
148
+ { name: "HTML", value: "html" },
149
+ { name: "Plain Text", value: "text" },
150
+ ],
151
+ },
152
+ {
153
+ displayName: "To",
154
+ name: "draftTo",
155
+ type: "string",
156
+ default: "",
157
+ displayOptions: {
158
+ show: { resource: ["draft"], operation: ["create"] },
159
+ },
160
+ placeholder: "alice@example.com, bob@example.com",
161
+ description: "Comma-separated list of recipient email addresses",
162
+ },
163
+ {
164
+ displayName: "CC",
165
+ name: "draftCc",
166
+ type: "string",
167
+ default: "",
168
+ displayOptions: {
169
+ show: { resource: ["draft"], operation: ["create"] },
170
+ },
171
+ placeholder: "cc@example.com",
172
+ description: "Comma-separated CC recipients",
173
+ },
174
+ {
175
+ displayName: "BCC",
176
+ name: "draftBcc",
177
+ type: "string",
178
+ default: "",
179
+ displayOptions: {
180
+ show: { resource: ["draft"], operation: ["create"] },
181
+ },
182
+ placeholder: "bcc@example.com",
183
+ description: "Comma-separated BCC recipients",
184
+ },
185
+ // ── Draft Create: save to folder ──
186
+ {
187
+ displayName: "Save to Folder",
188
+ name: "draftFolderId",
189
+ type: "options",
190
+ typeOptions: { loadOptionsMethod: "getMailFolders" },
191
+ default: "",
192
+ displayOptions: {
193
+ show: { resource: ["draft"], operation: ["create"] },
194
+ },
195
+ description: "Folder to save the draft into. Leave empty to save to the Drafts folder.",
196
+ },
197
+ // ── Draft Create: attachment ──
198
+ {
199
+ displayName: "Add Attachment",
200
+ name: "draftAddAttachment",
201
+ type: "boolean",
202
+ default: false,
203
+ displayOptions: {
204
+ show: { resource: ["draft"], operation: ["create"] },
205
+ },
206
+ description: "Whether to attach a binary file from the incoming item to the draft",
207
+ },
208
+ {
209
+ displayName: "Binary Field Name",
210
+ name: "draftBinaryFieldName",
211
+ type: "string",
212
+ default: "data",
213
+ displayOptions: {
214
+ show: {
215
+ resource: ["draft"],
216
+ operation: ["create"],
217
+ draftAddAttachment: [true],
218
+ },
219
+ },
220
+ placeholder: "data",
221
+ description: "Name of the binary property on the incoming item that holds the file to attach",
222
+ },
223
+ // ── Draft Create: inline images ──
224
+ {
225
+ displayName: "Inline Images",
226
+ name: "draftInlineImages",
227
+ type: "fixedCollection",
228
+ typeOptions: { multipleValues: true },
229
+ default: {},
230
+ displayOptions: {
231
+ show: {
232
+ resource: ["draft"],
233
+ operation: ["create"],
234
+ draftBodyType: ["html"],
235
+ },
236
+ },
237
+ description: 'Embed images inline in the HTML body. Reference each image as <img src="cid:your-content-id">.',
238
+ options: [
239
+ {
240
+ displayName: "Image",
241
+ name: "image",
242
+ values: [
243
+ {
244
+ displayName: "Binary Field Name",
245
+ name: "binaryFieldName",
246
+ type: "string",
247
+ default: "data",
248
+ placeholder: "data",
249
+ },
250
+ {
251
+ displayName: "Content ID",
252
+ name: "contentId",
253
+ type: "string",
254
+ default: "",
255
+ placeholder: "logo",
256
+ },
257
+ ],
258
+ },
259
+ ],
260
+ },
261
+ // ── Draft Create: adaptive card ──
262
+ {
263
+ displayName: "Include Adaptive Card",
264
+ name: "draftIncludeAdaptiveCard",
265
+ type: "boolean",
266
+ default: false,
267
+ displayOptions: {
268
+ show: { resource: ["draft"], operation: ["create"] },
269
+ },
270
+ description: "Whether to embed an Adaptive Card in the draft. Only supported with HTML body type.",
271
+ },
272
+ {
273
+ displayName: "Adaptive Card JSON",
274
+ name: "draftAdaptiveCardJson",
275
+ type: "string",
276
+ default: "",
277
+ required: true,
278
+ displayOptions: {
279
+ show: {
280
+ resource: ["draft"],
281
+ operation: ["create"],
282
+ draftIncludeAdaptiveCard: [true],
283
+ },
284
+ },
285
+ placeholder: '={{ $("Build Card").item.json.adaptiveCardJson }}',
286
+ description: "The Adaptive Card JSON string to embed in the draft.",
287
+ },
288
+ // ── Draft Get ──
289
+ {
290
+ displayName: "Draft ID",
291
+ name: "draftId",
292
+ type: "string",
293
+ default: "",
294
+ displayOptions: {
295
+ show: {
296
+ resource: ["draft"],
297
+ operation: ["get"],
298
+ },
299
+ },
300
+ placeholder: "AAMkAG...=",
301
+ description: "The ID of the draft to retrieve. Leave empty to list drafts.",
302
+ },
303
+ {
304
+ displayName: "Options",
305
+ name: "draftGetOptions",
306
+ type: "collection",
307
+ placeholder: "Add Option",
308
+ default: {},
309
+ displayOptions: {
310
+ show: { resource: ["draft"], operation: ["get"] },
311
+ },
312
+ options: [
313
+ {
314
+ displayName: "$expand",
315
+ name: "expand",
316
+ type: "string",
317
+ default: "",
318
+ typeOptions: { rows: 3 },
319
+ placeholder: "singleValueExtendedProperties($filter=id eq 'String {00020329-0000-0000-C000-000000000046} Name contentCheckSum')",
320
+ description: "OData $expand expression. Use to include extended or multi-value properties.",
321
+ },
322
+ {
323
+ displayName: "$filter",
324
+ name: "filter",
325
+ type: "string",
326
+ default: "",
327
+ typeOptions: { rows: 3 },
328
+ placeholder: "isDraft eq true and isRead eq false",
329
+ description: "OData $filter expression to restrict results",
330
+ },
331
+ {
332
+ displayName: "$orderby",
333
+ name: "orderBy",
334
+ type: "options",
335
+ default: "lastModifiedDateTime desc",
336
+ options: [
337
+ {
338
+ name: "Last Modified (Newest First)",
339
+ value: "lastModifiedDateTime desc",
340
+ },
341
+ {
342
+ name: "Last Modified (Oldest First)",
343
+ value: "lastModifiedDateTime asc",
344
+ },
345
+ {
346
+ name: "Created (Newest First)",
347
+ value: "createdDateTime desc",
348
+ },
349
+ {
350
+ name: "Created (Oldest First)",
351
+ value: "createdDateTime asc",
352
+ },
353
+ ],
354
+ },
355
+ {
356
+ displayName: "$select",
357
+ name: "select",
358
+ type: "multiOptions",
359
+ default: [],
360
+ options: [
361
+ { name: "BccRecipients", value: "bccRecipients" },
362
+ { name: "Body", value: "body" },
363
+ { name: "BodyPreview", value: "bodyPreview" },
364
+ { name: "Categories", value: "categories" },
365
+ { name: "CcRecipients", value: "ccRecipients" },
366
+ { name: "ConversationId", value: "conversationId" },
367
+ { name: "CreatedDateTime", value: "createdDateTime" },
368
+ { name: "Flag", value: "flag" },
369
+ { name: "From", value: "from" },
370
+ { name: "HasAttachments", value: "hasAttachments" },
371
+ { name: "ID", value: "id" },
372
+ { name: "Importance", value: "importance" },
373
+ { name: "IsDraft", value: "isDraft" },
374
+ { name: "IsRead", value: "isRead" },
375
+ { name: "LastModifiedDateTime", value: "lastModifiedDateTime" },
376
+ { name: "ParentFolderId", value: "parentFolderId" },
377
+ { name: "Subject", value: "subject" },
378
+ { name: "ToRecipients", value: "toRecipients" },
379
+ { name: "WebLink", value: "webLink" },
380
+ ],
381
+ description: "Fields to return. Leave empty to return all fields.",
382
+ },
383
+ {
384
+ displayName: "$top",
385
+ name: "limit",
386
+ type: "number",
387
+ default: 25,
388
+ typeOptions: { minValue: 1, maxValue: 1000 },
389
+ description: "Maximum number of drafts to return. Only applies when no Draft ID is given.",
390
+ },
391
+ {
392
+ displayName: "Convert Body to Markdown",
393
+ name: "bodyToMarkdown",
394
+ type: "boolean",
395
+ default: false,
396
+ description: "Whether to convert the HTML body content to Markdown.",
397
+ },
398
+ ],
399
+ },
400
+ // ── Draft Update ──
401
+ {
402
+ displayName: "Update Fields",
403
+ name: "draftUpdateFields",
404
+ type: "collection",
405
+ placeholder: "Add Field",
406
+ default: {},
407
+ displayOptions: {
408
+ show: { resource: ["draft"], operation: ["update"] },
409
+ },
410
+ description: "Fields to update on the draft. Only the fields you add here will be changed.",
411
+ options: [
412
+ {
413
+ displayName: "Subject",
414
+ name: "subject",
415
+ type: "string",
416
+ default: "",
417
+ },
418
+ {
419
+ displayName: "Body",
420
+ name: "body",
421
+ type: "string",
422
+ default: "",
423
+ typeOptions: { rows: 5 },
424
+ },
425
+ {
426
+ displayName: "Body Type",
427
+ name: "bodyType",
428
+ type: "options",
429
+ default: "html",
430
+ options: [
431
+ { name: "HTML", value: "html" },
432
+ { name: "Plain Text", value: "text" },
433
+ ],
434
+ },
435
+ {
436
+ displayName: "To",
437
+ name: "to",
438
+ type: "string",
439
+ default: "",
440
+ placeholder: "alice@example.com, bob@example.com",
441
+ description: "Comma-separated recipient addresses",
442
+ },
443
+ {
444
+ displayName: "CC",
445
+ name: "cc",
446
+ type: "string",
447
+ default: "",
448
+ placeholder: "cc@example.com",
449
+ description: "Comma-separated CC recipients",
450
+ },
451
+ {
452
+ displayName: "BCC",
453
+ name: "bcc",
454
+ type: "string",
455
+ default: "",
456
+ placeholder: "bcc@example.com",
457
+ description: "Comma-separated BCC recipients",
458
+ },
459
+ {
460
+ displayName: "Importance",
461
+ name: "importance",
462
+ type: "options",
463
+ default: "normal",
464
+ options: [
465
+ { name: "Low", value: "low" },
466
+ { name: "Normal", value: "normal" },
467
+ { name: "High", value: "high" },
468
+ ],
469
+ },
470
+ {
471
+ displayName: "Additional Body (JSON)",
472
+ name: "additionalBody",
473
+ type: "json",
474
+ default: "{}",
475
+ description: "Extra fields to merge into the PATCH body",
476
+ },
477
+ ],
478
+ },
479
+ {
480
+ displayName: "If-Match ETag",
481
+ name: "draftIfMatchETag",
482
+ type: "string",
483
+ default: "",
484
+ displayOptions: {
485
+ show: { resource: ["draft"], operation: ["update"] },
486
+ },
487
+ placeholder: 'W/"CQAAABYAAAB..."',
488
+ description: "Optimistic concurrency: only update if the ETag matches. Use @odata.etag from the Get response.",
489
+ },
86
490
  // ── Mailbox (subscription create only) ──
87
491
  {
88
492
  displayName: "Mailbox",
@@ -122,9 +526,18 @@ class OutlookSubscription {
122
526
  show: { resource: ["subscription"], operation: ["create"] },
123
527
  },
124
528
  options: [
125
- { name: "Message", value: "message" },
126
- { name: "Folder", value: "folder" },
529
+ {
530
+ name: "Message",
531
+ value: "message",
532
+ description: "Subscribe to individual emails inside a folder. Notifications fire when messages are created, updated, or deleted. This is the most common choice.",
533
+ },
534
+ {
535
+ name: "Folder",
536
+ value: "folder",
537
+ description: "Subscribe to the mail folder itself. Notifications fire when the folder properties change (e.g. renamed). Only the 'Updated' change type is supported — emails inside the folder do not trigger notifications.",
538
+ },
127
539
  ],
540
+ description: "What to watch: individual messages inside a folder, or the folder container itself",
128
541
  },
129
542
  {
130
543
  displayName: "Folder",
@@ -179,13 +592,33 @@ class OutlookSubscription {
179
592
  type: "multiOptions",
180
593
  default: ["created", "updated"],
181
594
  displayOptions: {
182
- show: { resource: ["subscription"], operation: ["create"] },
595
+ show: {
596
+ resource: ["subscription"],
597
+ operation: ["create"],
598
+ entity: ["message"],
599
+ },
183
600
  },
184
601
  options: [
185
602
  { name: "Created", value: "created" },
186
603
  { name: "Updated", value: "updated" },
187
604
  { name: "Deleted", value: "deleted" },
188
605
  ],
606
+ description: "Events to subscribe to. Message subscriptions support created, updated, and deleted.",
607
+ },
608
+ {
609
+ displayName: "Change Types",
610
+ name: "changeTypes",
611
+ type: "multiOptions",
612
+ default: ["updated"],
613
+ displayOptions: {
614
+ show: {
615
+ resource: ["subscription"],
616
+ operation: ["create"],
617
+ entity: ["folder"],
618
+ },
619
+ },
620
+ options: [{ name: "Updated", value: "updated" }],
621
+ description: "Events to subscribe to. Folder subscriptions only support updated — Microsoft Graph does not allow created or deleted for mailFolder resources.",
189
622
  },
190
623
  {
191
624
  displayName: "Notification URL",
@@ -209,21 +642,6 @@ class OutlookSubscription {
209
642
  },
210
643
  description: "Optional shared secret used later to verify notifications",
211
644
  },
212
- {
213
- displayName: "Lifetime Minutes",
214
- name: "lifetimeMinutes",
215
- type: "number",
216
- default: 4230,
217
- typeOptions: {
218
- minValue: 45,
219
- },
220
- displayOptions: {
221
- show: {
222
- resource: ["subscription"],
223
- operation: ["create", "renew"],
224
- },
225
- },
226
- },
227
645
  {
228
646
  displayName: "Auto Renew",
229
647
  name: "autoRenew",
@@ -249,6 +667,21 @@ class OutlookSubscription {
249
667
  placeholder: "https://example.com/webhooks/outlook-lifecycle",
250
668
  },
251
669
  // ── Subscription Delete / Renew ──
670
+ {
671
+ displayName: "Lifetime Minutes",
672
+ name: "lifetimeMinutes",
673
+ type: "number",
674
+ default: 4230,
675
+ typeOptions: {
676
+ minValue: 45,
677
+ },
678
+ displayOptions: {
679
+ show: {
680
+ resource: ["subscription"],
681
+ operation: ["create", "renew"],
682
+ },
683
+ },
684
+ },
252
685
  {
253
686
  displayName: "Subscription ID",
254
687
  name: "subscriptionId",
@@ -273,7 +706,7 @@ class OutlookSubscription {
273
706
  displayOptions: { show: { resource: ["attachment"] } },
274
707
  placeholder: "AAMkAG...=",
275
708
  },
276
- // For message resource: only ops that act on a specific message
709
+ // For message resource: ops that require a specific message
277
710
  {
278
711
  displayName: "Message ID",
279
712
  name: "messageId",
@@ -283,7 +716,7 @@ class OutlookSubscription {
283
716
  displayOptions: {
284
717
  show: {
285
718
  resource: ["message"],
286
- operation: ["delete", "get", "move", "reply", "replyAll", "update"],
719
+ operation: ["delete", "move", "reply", "replyAll", "patch"],
287
720
  },
288
721
  },
289
722
  placeholder: "AAMkAG...=",
@@ -300,61 +733,268 @@ class OutlookSubscription {
300
733
  },
301
734
  placeholder: "AAMkAG...=",
302
735
  },
303
- // ── Message Get: Query Options ──
736
+ // ── Message Get: optional ID + Options ──
304
737
  {
305
- displayName: "$expand",
306
- name: "expand",
738
+ displayName: "Message ID",
739
+ name: "messageId",
307
740
  type: "string",
308
741
  default: "",
309
- typeOptions: { rows: 3 },
310
742
  displayOptions: {
311
- show: { resource: ["message"], operation: ["get"] },
743
+ show: {
744
+ resource: ["message"],
745
+ operation: ["get"],
746
+ },
312
747
  },
313
- placeholder: "singleValueExtendedProperties($filter=id eq 'String {00020329-0000-0000-C000-000000000046} Name contentCheckSum')",
314
- description: "Expand related entities (e.g. extended properties)",
748
+ placeholder: "AAMkAG...=",
749
+ description: "ID of the message to retrieve. Leave empty to list messages.",
315
750
  },
316
751
  {
317
- displayName: "$select",
318
- name: "select",
319
- type: "multiOptions",
320
- default: [],
752
+ displayName: "Options",
753
+ name: "messageGetOptions",
754
+ type: "collection",
755
+ placeholder: "Add Option",
756
+ default: {},
321
757
  displayOptions: {
322
758
  show: { resource: ["message"], operation: ["get"] },
323
759
  },
324
760
  options: [
325
- { name: "BccRecipients", value: "bccRecipients" },
326
- { name: "Body", value: "body" },
327
- { name: "BodyPreview", value: "bodyPreview" },
328
- { name: "Categories", value: "categories" },
329
- { name: "CcRecipients", value: "ccRecipients" },
330
- { name: "ChangeKey", value: "changeKey" },
331
- { name: "ConversationId", value: "conversationId" },
332
- { name: "CreatedDateTime", value: "createdDateTime" },
333
- { name: "Flag", value: "flag" },
334
- { name: "From", value: "from" },
335
- { name: "HasAttachments", value: "hasAttachments" },
336
- { name: "ID", value: "id" },
337
- { name: "Importance", value: "importance" },
338
- { name: "InternetMessageHeaders", value: "internetMessageHeaders" },
339
- { name: "InternetMessageId", value: "internetMessageId" },
340
761
  {
341
- name: "IsDeliveryReceiptRequested",
342
- value: "isDeliveryReceiptRequested",
762
+ displayName: "$expand",
763
+ name: "expand",
764
+ type: "string",
765
+ default: "",
766
+ typeOptions: { rows: 3 },
767
+ placeholder: "singleValueExtendedProperties($filter=id eq 'String {00020329-0000-0000-C000-000000000046} Name contentCheckSum')",
768
+ description: "OData $expand expression for related entities or extended properties",
769
+ },
770
+ {
771
+ displayName: "$filter",
772
+ name: "filter",
773
+ type: "string",
774
+ default: "",
775
+ typeOptions: { rows: 3 },
776
+ placeholder: "isRead eq false",
777
+ description: "OData $filter expression to restrict results",
778
+ },
779
+ {
780
+ displayName: "$orderby",
781
+ name: "orderBy",
782
+ type: "options",
783
+ default: "receivedDateTime desc",
784
+ options: [
785
+ {
786
+ name: "Received (Newest First)",
787
+ value: "receivedDateTime desc",
788
+ },
789
+ {
790
+ name: "Received (Oldest First)",
791
+ value: "receivedDateTime asc",
792
+ },
793
+ { name: "Sent (Newest First)", value: "sentDateTime desc" },
794
+ {
795
+ name: "Last Modified (Newest First)",
796
+ value: "lastModifiedDateTime desc",
797
+ },
798
+ ],
799
+ },
800
+ {
801
+ displayName: "$select",
802
+ name: "select",
803
+ type: "multiOptions",
804
+ default: [],
805
+ options: [
806
+ { name: "BccRecipients", value: "bccRecipients" },
807
+ { name: "Body", value: "body" },
808
+ { name: "BodyPreview", value: "bodyPreview" },
809
+ { name: "Categories", value: "categories" },
810
+ { name: "CcRecipients", value: "ccRecipients" },
811
+ { name: "ChangeKey", value: "changeKey" },
812
+ { name: "ConversationId", value: "conversationId" },
813
+ { name: "CreatedDateTime", value: "createdDateTime" },
814
+ { name: "Flag", value: "flag" },
815
+ { name: "From", value: "from" },
816
+ { name: "HasAttachments", value: "hasAttachments" },
817
+ { name: "ID", value: "id" },
818
+ { name: "Importance", value: "importance" },
819
+ {
820
+ name: "InternetMessageHeaders",
821
+ value: "internetMessageHeaders",
822
+ },
823
+ { name: "InternetMessageId", value: "internetMessageId" },
824
+ {
825
+ name: "IsDeliveryReceiptRequested",
826
+ value: "isDeliveryReceiptRequested",
827
+ },
828
+ { name: "IsDraft", value: "isDraft" },
829
+ { name: "IsRead", value: "isRead" },
830
+ {
831
+ name: "IsReadReceiptRequested",
832
+ value: "isReadReceiptRequested",
833
+ },
834
+ { name: "LastModifiedDateTime", value: "lastModifiedDateTime" },
835
+ { name: "ParentFolderId", value: "parentFolderId" },
836
+ { name: "ReceivedDateTime", value: "receivedDateTime" },
837
+ { name: "ReplyTo", value: "replyTo" },
838
+ { name: "Sender", value: "sender" },
839
+ { name: "SentDateTime", value: "sentDateTime" },
840
+ { name: "Subject", value: "subject" },
841
+ { name: "ToRecipients", value: "toRecipients" },
842
+ { name: "WebLink", value: "webLink" },
843
+ ],
844
+ description: "Fields to return. Leave empty to return all fields.",
845
+ },
846
+ {
847
+ displayName: "Folder ID",
848
+ name: "folderId",
849
+ type: "string",
850
+ default: "",
851
+ placeholder: "AAMkAG...=",
852
+ description: "Restrict results to a specific folder. Only applies when listing (no Message ID). Leave empty to query all mailbox messages.",
853
+ },
854
+ {
855
+ displayName: "$top",
856
+ name: "limit",
857
+ type: "number",
858
+ default: 25,
859
+ typeOptions: { minValue: 1, maxValue: 1000 },
860
+ description: "Maximum number of messages to return. Only applies when no Message ID is given.",
861
+ },
862
+ {
863
+ displayName: "Convert Body to Markdown",
864
+ name: "bodyToMarkdown",
865
+ type: "boolean",
866
+ default: false,
867
+ description: "Whether to convert the HTML body content to Markdown. Only applied when the body field is returned and its contentType is html.",
868
+ },
869
+ ],
870
+ },
871
+ // ── Sent Item Operation ──
872
+ {
873
+ displayName: "Operation",
874
+ name: "operation",
875
+ type: "options",
876
+ noDataExpression: true,
877
+ default: "get",
878
+ displayOptions: { show: { resource: ["sentItem"] } },
879
+ options: [{ name: "Get", value: "get" }],
880
+ },
881
+ // ── Sent Item: Message ID (single item) ──
882
+ {
883
+ displayName: "Message ID",
884
+ name: "sentItemMessageId",
885
+ type: "string",
886
+ default: "",
887
+ displayOptions: {
888
+ show: { resource: ["sentItem"], operation: ["get"] },
889
+ },
890
+ placeholder: "AAMkAG...=",
891
+ description: "ID of the sent message to retrieve. Leave empty to list sent items.",
892
+ },
893
+ // ── Sent Item: Query Options ──
894
+ {
895
+ displayName: "Options",
896
+ name: "sentItemOptions",
897
+ type: "collection",
898
+ placeholder: "Add Option",
899
+ default: {},
900
+ displayOptions: {
901
+ show: { resource: ["sentItem"], operation: ["get"] },
902
+ },
903
+ options: [
904
+ {
905
+ displayName: "$expand",
906
+ name: "expand",
907
+ type: "string",
908
+ default: "",
909
+ typeOptions: { rows: 3 },
910
+ placeholder: "singleValueExtendedProperties($filter=id eq 'String {00020329-0000-0000-C000-000000000046} Name approvedBy' or id eq 'String {00020329-0000-0000-C000-000000000046} Name approvedAt')",
911
+ description: "OData $expand expression. Use to include extended properties or related entities.",
912
+ },
913
+ {
914
+ displayName: "$filter",
915
+ name: "filter",
916
+ type: "string",
917
+ default: "",
918
+ typeOptions: { rows: 3 },
919
+ placeholder: "singleValueExtendedProperties/any(ep: ep/id eq 'String {guid} Name replyId' and ep/value eq 'abc')",
920
+ description: "OData $filter expression to restrict results",
921
+ },
922
+ {
923
+ displayName: "$orderby",
924
+ name: "orderBy",
925
+ type: "options",
926
+ default: "receivedDateTime desc",
927
+ options: [
928
+ {
929
+ name: "Received (Newest First)",
930
+ value: "receivedDateTime desc",
931
+ },
932
+ {
933
+ name: "Received (Oldest First)",
934
+ value: "receivedDateTime asc",
935
+ },
936
+ { name: "Sent (Newest First)", value: "sentDateTime desc" },
937
+ { name: "Sent (Oldest First)", value: "sentDateTime asc" },
938
+ {
939
+ name: "Last Modified (Newest First)",
940
+ value: "lastModifiedDateTime desc",
941
+ },
942
+ ],
943
+ },
944
+ {
945
+ displayName: "$select",
946
+ name: "select",
947
+ type: "multiOptions",
948
+ default: [],
949
+ options: [
950
+ { name: "BccRecipients", value: "bccRecipients" },
951
+ { name: "Body", value: "body" },
952
+ { name: "BodyPreview", value: "bodyPreview" },
953
+ { name: "Categories", value: "categories" },
954
+ { name: "CcRecipients", value: "ccRecipients" },
955
+ { name: "ChangeKey", value: "changeKey" },
956
+ { name: "ConversationId", value: "conversationId" },
957
+ { name: "CreatedDateTime", value: "createdDateTime" },
958
+ { name: "Flag", value: "flag" },
959
+ { name: "From", value: "from" },
960
+ { name: "HasAttachments", value: "hasAttachments" },
961
+ { name: "ID", value: "id" },
962
+ { name: "Importance", value: "importance" },
963
+ {
964
+ name: "InternetMessageHeaders",
965
+ value: "internetMessageHeaders",
966
+ },
967
+ { name: "InternetMessageId", value: "internetMessageId" },
968
+ { name: "IsDraft", value: "isDraft" },
969
+ { name: "IsRead", value: "isRead" },
970
+ { name: "LastModifiedDateTime", value: "lastModifiedDateTime" },
971
+ { name: "ParentFolderId", value: "parentFolderId" },
972
+ { name: "ReceivedDateTime", value: "receivedDateTime" },
973
+ { name: "ReplyTo", value: "replyTo" },
974
+ { name: "Sender", value: "sender" },
975
+ { name: "SentDateTime", value: "sentDateTime" },
976
+ { name: "Subject", value: "subject" },
977
+ { name: "ToRecipients", value: "toRecipients" },
978
+ { name: "WebLink", value: "webLink" },
979
+ ],
980
+ description: "Fields to return. Leave empty to return all fields.",
981
+ },
982
+ {
983
+ displayName: "$top",
984
+ name: "limit",
985
+ type: "number",
986
+ default: 25,
987
+ typeOptions: { minValue: 1, maxValue: 1000 },
988
+ description: "Maximum number of items to return. Only applies when no Message ID is given.",
989
+ },
990
+ {
991
+ displayName: "Convert Body to Markdown",
992
+ name: "bodyToMarkdown",
993
+ type: "boolean",
994
+ default: false,
995
+ description: "Whether to convert the HTML body content to Markdown.",
343
996
  },
344
- { name: "IsDraft", value: "isDraft" },
345
- { name: "IsRead", value: "isRead" },
346
- { name: "IsReadReceiptRequested", value: "isReadReceiptRequested" },
347
- { name: "LastModifiedDateTime", value: "lastModifiedDateTime" },
348
- { name: "ParentFolderId", value: "parentFolderId" },
349
- { name: "ReceivedDateTime", value: "receivedDateTime" },
350
- { name: "ReplyTo", value: "replyTo" },
351
- { name: "Sender", value: "sender" },
352
- { name: "SentDateTime", value: "sentDateTime" },
353
- { name: "Subject", value: "subject" },
354
- { name: "ToRecipients", value: "toRecipients" },
355
- { name: "WebLink", value: "webLink" },
356
997
  ],
357
- description: "Fields to return. Leave empty to return all fields. In expression mode, enter field names separated by commas.",
358
998
  },
359
999
  // ── Message Update: Fields ──
360
1000
  {
@@ -363,7 +1003,7 @@ class OutlookSubscription {
363
1003
  type: "options",
364
1004
  default: "none",
365
1005
  displayOptions: {
366
- show: { resource: ["message"], operation: ["update"] },
1006
+ show: { resource: ["message"], operation: ["patch"] },
367
1007
  },
368
1008
  options: [
369
1009
  { name: "Don't Change", value: "none" },
@@ -372,6 +1012,90 @@ class OutlookSubscription {
372
1012
  { name: "Not Flagged", value: "notFlagged" },
373
1013
  ],
374
1014
  },
1015
+ {
1016
+ displayName: "Completed Date/Time",
1017
+ name: "completedDateTime",
1018
+ type: "dateTime",
1019
+ default: "",
1020
+ displayOptions: {
1021
+ show: {
1022
+ resource: ["message"],
1023
+ operation: ["patch"],
1024
+ flagStatus: ["complete"],
1025
+ },
1026
+ },
1027
+ description: "The date and time the flag was completed. Only applies when Flag Status is Complete. Leave empty to use the current time.",
1028
+ },
1029
+ {
1030
+ displayName: "Completed Time Zone",
1031
+ name: "completedTimeZone",
1032
+ type: "string",
1033
+ default: "UTC",
1034
+ displayOptions: {
1035
+ show: {
1036
+ resource: ["message"],
1037
+ operation: ["patch"],
1038
+ flagStatus: ["complete"],
1039
+ },
1040
+ },
1041
+ description: "IANA time zone for the completed date/time, e.g. Asia/Hong_Kong",
1042
+ },
1043
+ {
1044
+ displayName: "Start Date/Time",
1045
+ name: "startDateTime",
1046
+ type: "dateTime",
1047
+ default: "",
1048
+ displayOptions: {
1049
+ show: {
1050
+ resource: ["message"],
1051
+ operation: ["patch"],
1052
+ flagStatus: ["flagged"],
1053
+ },
1054
+ },
1055
+ description: "The date and time the flag starts. Only applies when Flag Status is Flagged.",
1056
+ },
1057
+ {
1058
+ displayName: "Start Time Zone",
1059
+ name: "startTimeZone",
1060
+ type: "string",
1061
+ default: "UTC",
1062
+ displayOptions: {
1063
+ show: {
1064
+ resource: ["message"],
1065
+ operation: ["patch"],
1066
+ flagStatus: ["flagged"],
1067
+ },
1068
+ },
1069
+ description: "IANA time zone for the start date/time, e.g. Asia/Hong_Kong",
1070
+ },
1071
+ {
1072
+ displayName: "Due Date/Time",
1073
+ name: "dueDateTime",
1074
+ type: "dateTime",
1075
+ default: "",
1076
+ displayOptions: {
1077
+ show: {
1078
+ resource: ["message"],
1079
+ operation: ["patch"],
1080
+ flagStatus: ["flagged"],
1081
+ },
1082
+ },
1083
+ description: "The date and time the flag is due. Only applies when Flag Status is Flagged.",
1084
+ },
1085
+ {
1086
+ displayName: "Due Time Zone",
1087
+ name: "dueTimeZone",
1088
+ type: "string",
1089
+ default: "UTC",
1090
+ displayOptions: {
1091
+ show: {
1092
+ resource: ["message"],
1093
+ operation: ["patch"],
1094
+ flagStatus: ["flagged"],
1095
+ },
1096
+ },
1097
+ description: "IANA time zone for the due date/time, e.g. Asia/Hong_Kong",
1098
+ },
375
1099
  {
376
1100
  displayName: "Extended Properties",
377
1101
  name: "extendedProperties",
@@ -379,7 +1103,7 @@ class OutlookSubscription {
379
1103
  typeOptions: { multipleValues: true },
380
1104
  default: {},
381
1105
  displayOptions: {
382
- show: { resource: ["message"], operation: ["update"] },
1106
+ show: { resource: ["message"], operation: ["patch"] },
383
1107
  },
384
1108
  options: [
385
1109
  {
@@ -410,7 +1134,7 @@ class OutlookSubscription {
410
1134
  type: "string",
411
1135
  default: "",
412
1136
  displayOptions: {
413
- show: { resource: ["message"], operation: ["update"] },
1137
+ show: { resource: ["message"], operation: ["patch"] },
414
1138
  },
415
1139
  placeholder: 'W/"CQAAABYAAAB..."',
416
1140
  description: 'Optimistic concurrency: only update if the server-side message state matches. Use the @odata.etag value from the Get response, or format the changeKey as W/"<changeKey>"',
@@ -421,7 +1145,7 @@ class OutlookSubscription {
421
1145
  type: "json",
422
1146
  default: "{}",
423
1147
  displayOptions: {
424
- show: { resource: ["message"], operation: ["update"] },
1148
+ show: { resource: ["message"], operation: ["patch"] },
425
1149
  },
426
1150
  description: "Additional fields to include in the PATCH body, merged with the fields above",
427
1151
  },
@@ -744,6 +1468,32 @@ class OutlookSubscription {
744
1468
  },
745
1469
  ],
746
1470
  },
1471
+ {
1472
+ displayName: "Include Adaptive Card",
1473
+ name: "includeAdaptiveCard",
1474
+ type: "boolean",
1475
+ default: false,
1476
+ displayOptions: {
1477
+ show: { resource: ["message"], operation: ["send"] },
1478
+ },
1479
+ description: "Whether to embed an Adaptive Card in the email for Outlook Actionable Messages. Only supported with HTML body type.",
1480
+ },
1481
+ {
1482
+ displayName: "Adaptive Card JSON",
1483
+ name: "adaptiveCardJson",
1484
+ type: "string",
1485
+ default: "",
1486
+ required: true,
1487
+ displayOptions: {
1488
+ show: {
1489
+ resource: ["message"],
1490
+ operation: ["send"],
1491
+ includeAdaptiveCard: [true],
1492
+ },
1493
+ },
1494
+ placeholder: '={{ $("Build Card").item.json.adaptiveCardJson }}',
1495
+ description: "The Adaptive Card JSON string to embed. Reference the output of an Adaptive Card build step, or paste the JSON directly.",
1496
+ },
747
1497
  {
748
1498
  displayName: "Comment",
749
1499
  name: "replyComment",
@@ -769,6 +1519,70 @@ class OutlookSubscription {
769
1519
  { name: "Plain Text", value: "text" },
770
1520
  ],
771
1521
  },
1522
+ {
1523
+ displayName: "Add Attachment",
1524
+ name: "replyAddAttachment",
1525
+ type: "boolean",
1526
+ default: false,
1527
+ displayOptions: {
1528
+ show: { resource: ["message"], operation: ["reply", "replyAll"] },
1529
+ },
1530
+ description: "Whether to attach a binary file from the incoming item to the reply",
1531
+ },
1532
+ {
1533
+ displayName: "Binary Field Name",
1534
+ name: "replyBinaryFieldName",
1535
+ type: "string",
1536
+ default: "data",
1537
+ displayOptions: {
1538
+ show: {
1539
+ resource: ["message"],
1540
+ operation: ["reply", "replyAll"],
1541
+ replyAddAttachment: [true],
1542
+ },
1543
+ },
1544
+ placeholder: "data",
1545
+ description: "Name of the binary property on the incoming item that holds the file to attach",
1546
+ },
1547
+ {
1548
+ displayName: "Inline Images",
1549
+ name: "replyInlineImages",
1550
+ type: "fixedCollection",
1551
+ typeOptions: { multipleValues: true },
1552
+ default: {},
1553
+ displayOptions: {
1554
+ show: {
1555
+ resource: ["message"],
1556
+ operation: ["reply", "replyAll"],
1557
+ replyBodyType: ["html"],
1558
+ },
1559
+ },
1560
+ description: 'Embed images inline in the HTML reply body. Reference each image in the body as &lt;img src="cid:your-content-id" &gt;.',
1561
+ options: [
1562
+ {
1563
+ displayName: "Image",
1564
+ name: "image",
1565
+ values: [
1566
+ {
1567
+ displayName: "Binary Field Name",
1568
+ name: "binaryFieldName",
1569
+ type: "string",
1570
+ default: "data",
1571
+ placeholder: "data",
1572
+ description: "Name of the binary property on the incoming item that holds the image file",
1573
+ },
1574
+ {
1575
+ displayName: "Content ID",
1576
+ name: "contentId",
1577
+ type: "string",
1578
+ default: "",
1579
+ placeholder: "logo",
1580
+ description: 'Unique identifier for this image. Use it in the HTML body as &lt;img src="cid:logo"&gt;',
1581
+ },
1582
+ ],
1583
+ },
1584
+ ],
1585
+ },
772
1586
  ],
773
1587
  };
774
1588
  this.methods = {
@@ -780,7 +1594,7 @@ class OutlookSubscription {
780
1594
  };
781
1595
  }
782
1596
  async execute() {
783
- var _a, _b;
1597
+ var _a, _b, _c, _d, _e, _f, _g, _h;
784
1598
  const items = this.getInputData();
785
1599
  const returnData = [];
786
1600
  for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
@@ -830,7 +1644,7 @@ class OutlookSubscription {
830
1644
  const notificationUrl = this.getNodeParameter("notificationUrl", itemIndex);
831
1645
  const changeTypes = this.getNodeParameter("changeTypes", itemIndex);
832
1646
  const changeType = (0, graph_1.normalizeChangeTypes)(changeTypes);
833
- const lifetimeMinutes = (0, graph_1.clampLifetimeMinutes)(this.getNodeParameter("lifetimeMinutes", itemIndex));
1647
+ const lifetimeMinutesCreate = (0, graph_1.clampLifetimeMinutes)(this.getNodeParameter("lifetimeMinutes", itemIndex));
834
1648
  const autoRenew = this.getNodeParameter("autoRenew", itemIndex);
835
1649
  const lifecycleNotificationUrl = this.getNodeParameter("lifecycleNotificationUrl", itemIndex, "");
836
1650
  const clientState = (0, graph_1.buildClientState)(this.getNodeParameter("clientState", itemIndex, ""));
@@ -854,7 +1668,7 @@ class OutlookSubscription {
854
1668
  notificationUrl,
855
1669
  existing: duplicates,
856
1670
  autoRenew,
857
- lifetimeMinutes,
1671
+ lifetimeMinutes: lifetimeMinutesCreate,
858
1672
  },
859
1673
  });
860
1674
  continue;
@@ -863,7 +1677,7 @@ class OutlookSubscription {
863
1677
  changeType,
864
1678
  notificationUrl,
865
1679
  clientState,
866
- expirationDateTime: (0, graph_1.buildExpirationDateTime)(lifetimeMinutes),
1680
+ expirationDateTime: (0, graph_1.buildExpirationDateTime)(lifetimeMinutesCreate),
867
1681
  resource: target,
868
1682
  latestSupportedTlsVersion: "v1_2",
869
1683
  ...(autoRenew && lifecycleNotificationUrl
@@ -878,7 +1692,7 @@ class OutlookSubscription {
878
1692
  changeType,
879
1693
  notificationUrl,
880
1694
  autoRenew,
881
- lifetimeMinutes,
1695
+ lifetimeMinutes: lifetimeMinutesCreate,
882
1696
  subscription: created,
883
1697
  },
884
1698
  });
@@ -957,12 +1771,69 @@ class OutlookSubscription {
957
1771
  cc: sendCc || undefined,
958
1772
  bcc: sendBcc || undefined,
959
1773
  saveToSentItems,
1774
+ adaptiveCardJson: (() => {
1775
+ const include = this.getNodeParameter("includeAdaptiveCard", itemIndex, false);
1776
+ if (!include)
1777
+ return undefined;
1778
+ const raw = this.getNodeParameter("adaptiveCardJson", itemIndex, "").trim();
1779
+ return raw || undefined;
1780
+ })(),
960
1781
  attachments: attachments.length > 0 ? attachments : undefined,
961
1782
  inlineImages: inlineImages.length > 0 ? inlineImages : undefined,
962
1783
  });
963
1784
  returnData.push({ json: { success: true, operation: "send" } });
964
1785
  continue;
965
1786
  }
1787
+ // ── get ──
1788
+ if (operation === "get") {
1789
+ const opts = this.getNodeParameter("messageGetOptions", itemIndex, {});
1790
+ const expand = (opts.expand || "").trim();
1791
+ const filter = (opts.filter || "").trim();
1792
+ const orderBy = opts.orderBy || "receivedDateTime desc";
1793
+ const selectRaw = opts.select;
1794
+ const selectFields = Array.isArray(selectRaw)
1795
+ ? selectRaw.join(",")
1796
+ : typeof selectRaw === "string"
1797
+ ? selectRaw
1798
+ .split(",")
1799
+ .map((s) => s.trim())
1800
+ .filter(Boolean)
1801
+ .join(",")
1802
+ : "";
1803
+ const bodyToMarkdown = (_c = opts.bodyToMarkdown) !== null && _c !== void 0 ? _c : false;
1804
+ const msgId = this.getNodeParameter("messageId", itemIndex, "").trim();
1805
+ if (msgId) {
1806
+ const qs = {};
1807
+ if (expand)
1808
+ qs.$expand = expand;
1809
+ if (selectFields)
1810
+ qs.$select = selectFields;
1811
+ const message = await graph_1.getMessage.call(this, config, msgId, Object.keys(qs).length > 0 ? qs : undefined);
1812
+ returnData.push({
1813
+ json: bodyToMarkdown ? (0, graph_1.convertBodyToMarkdown)(message) : message,
1814
+ });
1815
+ }
1816
+ else {
1817
+ const limit = typeof opts.limit === "number" ? opts.limit : 25;
1818
+ const folderIdOpt = (opts.folderId || "").trim();
1819
+ const qs = {
1820
+ $orderby: orderBy,
1821
+ $top: Math.min(limit, 1000),
1822
+ };
1823
+ if (filter)
1824
+ qs.$filter = filter;
1825
+ if (expand)
1826
+ qs.$expand = expand;
1827
+ if (selectFields)
1828
+ qs.$select = selectFields;
1829
+ const messages = await graph_1.listMessages.call(this, config, folderIdOpt || undefined, qs, false);
1830
+ const mapped = bodyToMarkdown
1831
+ ? messages.map(graph_1.convertBodyToMarkdown)
1832
+ : messages;
1833
+ returnData.push(...this.helpers.returnJsonArray(mapped));
1834
+ }
1835
+ continue;
1836
+ }
966
1837
  // All remaining message operations require a messageId
967
1838
  const messageId = this.getNodeParameter("messageId", itemIndex);
968
1839
  // ── delete ──
@@ -996,37 +1867,76 @@ class OutlookSubscription {
996
1867
  if (operation === "reply" || operation === "replyAll") {
997
1868
  const replyComment = this.getNodeParameter("replyComment", itemIndex);
998
1869
  const replyBodyType = this.getNodeParameter("replyBodyType", itemIndex, "html");
999
- await graph_1.replyToMessage.call(this, config, messageId, replyComment, replyBodyType, operation === "replyAll");
1870
+ const replyAddAttachment = this.getNodeParameter("replyAddAttachment", itemIndex, false);
1871
+ const replyAttachments = [];
1872
+ if (replyAddAttachment) {
1873
+ const replyBinaryFieldName = this.getNodeParameter("replyBinaryFieldName", itemIndex, "data").trim();
1874
+ const binaryData = this.helpers.assertBinaryData(itemIndex, replyBinaryFieldName);
1875
+ const buffer = await this.helpers.getBinaryDataBuffer(itemIndex, replyBinaryFieldName);
1876
+ replyAttachments.push({
1877
+ name: binaryData.fileName || replyBinaryFieldName,
1878
+ contentType: binaryData.mimeType || "application/octet-stream",
1879
+ contentBytes: buffer.toString("base64"),
1880
+ });
1881
+ }
1882
+ const replyInlineImagesCollection = this.getNodeParameter("replyInlineImages", itemIndex, {});
1883
+ const replyInlineImageEntries = (_d = replyInlineImagesCollection.image) !== null && _d !== void 0 ? _d : [];
1884
+ const replyInlineImages = [];
1885
+ for (const entry of replyInlineImageEntries) {
1886
+ const imgField = entry.binaryFieldName.trim() || "data";
1887
+ const imgBinary = this.helpers.assertBinaryData(itemIndex, imgField);
1888
+ const imgBuffer = await this.helpers.getBinaryDataBuffer(itemIndex, imgField);
1889
+ replyInlineImages.push({
1890
+ name: imgBinary.fileName || imgField,
1891
+ contentType: imgBinary.mimeType || "application/octet-stream",
1892
+ contentBytes: imgBuffer.toString("base64"),
1893
+ contentId: entry.contentId.trim() || imgField,
1894
+ });
1895
+ }
1896
+ await graph_1.replyToMessage.call(this, config, messageId, replyComment, replyBodyType, operation === "replyAll", replyAttachments.length > 0 ? replyAttachments : undefined, replyInlineImages.length > 0 ? replyInlineImages : undefined);
1000
1897
  returnData.push({
1001
1898
  json: { success: true, operation, messageId },
1002
1899
  });
1003
1900
  continue;
1004
1901
  }
1005
- if (operation === "get") {
1006
- const expand = this.getNodeParameter("expand", itemIndex, "");
1007
- const selectRaw = this.getNodeParameter("select", itemIndex, []);
1008
- const selectFields = Array.isArray(selectRaw)
1009
- ? selectRaw.join(",")
1010
- : selectRaw
1011
- .split(",")
1012
- .map((s) => s.trim())
1013
- .filter(Boolean)
1014
- .join(",");
1015
- const qs = {};
1016
- if (expand)
1017
- qs.$expand = expand;
1018
- if (selectFields)
1019
- qs.$select = selectFields;
1020
- const message = await graph_1.getMessage.call(this, config, messageId, Object.keys(qs).length > 0 ? qs : undefined);
1021
- returnData.push({ json: message });
1022
- continue;
1023
- }
1024
- if (operation === "update") {
1902
+ if (operation === "patch") {
1025
1903
  const body = {};
1026
1904
  // Flag status
1027
1905
  const flagStatus = this.getNodeParameter("flagStatus", itemIndex, "none");
1028
1906
  if (flagStatus && flagStatus !== "none") {
1029
- body.flag = { flagStatus };
1907
+ const flagObj = { flagStatus };
1908
+ if (flagStatus === "complete") {
1909
+ const completedDateTime = this.getNodeParameter("completedDateTime", itemIndex, "");
1910
+ const completedTimeZone = this.getNodeParameter("completedTimeZone", itemIndex, "UTC");
1911
+ const dt = completedDateTime
1912
+ ? new Date(completedDateTime).toISOString().split(".")[0]
1913
+ : new Date().toISOString().split(".")[0];
1914
+ flagObj.completedDateTime = {
1915
+ dateTime: dt,
1916
+ timeZone: completedTimeZone || "UTC",
1917
+ };
1918
+ }
1919
+ else if (flagStatus === "flagged") {
1920
+ const startDateTime = this.getNodeParameter("startDateTime", itemIndex, "");
1921
+ const startTimeZone = this.getNodeParameter("startTimeZone", itemIndex, "UTC");
1922
+ const dueDateTime = this.getNodeParameter("dueDateTime", itemIndex, "");
1923
+ const dueTimeZone = this.getNodeParameter("dueTimeZone", itemIndex, "UTC");
1924
+ if (startDateTime) {
1925
+ flagObj.startDateTime = {
1926
+ dateTime: new Date(startDateTime)
1927
+ .toISOString()
1928
+ .split(".")[0],
1929
+ timeZone: startTimeZone || "UTC",
1930
+ };
1931
+ }
1932
+ if (dueDateTime) {
1933
+ flagObj.dueDateTime = {
1934
+ dateTime: new Date(dueDateTime).toISOString().split(".")[0],
1935
+ timeZone: dueTimeZone || "UTC",
1936
+ };
1937
+ }
1938
+ }
1939
+ body.flag = flagObj;
1030
1940
  }
1031
1941
  // Extended properties
1032
1942
  const extProps = this.getNodeParameter("extendedProperties", itemIndex, {});
@@ -1055,6 +1965,233 @@ class OutlookSubscription {
1055
1965
  continue;
1056
1966
  }
1057
1967
  }
1968
+ // ── DRAFT ──
1969
+ if (resource === "draft") {
1970
+ const config = { mailboxMode: "current" };
1971
+ if (operation === "create") {
1972
+ const draftSubject = this.getNodeParameter("draftSubject", itemIndex, "");
1973
+ const draftBody = this.getNodeParameter("draftBody", itemIndex, "");
1974
+ const draftBodyType = this.getNodeParameter("draftBodyType", itemIndex, "html");
1975
+ const draftTo = this.getNodeParameter("draftTo", itemIndex, "").trim();
1976
+ const draftCc = this.getNodeParameter("draftCc", itemIndex, "").trim();
1977
+ const draftBcc = this.getNodeParameter("draftBcc", itemIndex, "").trim();
1978
+ const draftFolderId = this.getNodeParameter("draftFolderId", itemIndex, "").trim();
1979
+ const draftAddAttachment = this.getNodeParameter("draftAddAttachment", itemIndex, false);
1980
+ const attachments = [];
1981
+ if (draftAddAttachment) {
1982
+ const draftBinaryFieldName = this.getNodeParameter("draftBinaryFieldName", itemIndex, "data").trim();
1983
+ const binaryData = this.helpers.assertBinaryData(itemIndex, draftBinaryFieldName);
1984
+ const buffer = await this.helpers.getBinaryDataBuffer(itemIndex, draftBinaryFieldName);
1985
+ attachments.push({
1986
+ name: binaryData.fileName || draftBinaryFieldName,
1987
+ contentType: binaryData.mimeType || "application/octet-stream",
1988
+ contentBytes: buffer.toString("base64"),
1989
+ });
1990
+ }
1991
+ const draftInlineImagesCollection = this.getNodeParameter("draftInlineImages", itemIndex, {});
1992
+ const draftInlineImageEntries = (_e = draftInlineImagesCollection.image) !== null && _e !== void 0 ? _e : [];
1993
+ const inlineImages = [];
1994
+ for (const entry of draftInlineImageEntries) {
1995
+ const imgField = entry.binaryFieldName.trim() || "data";
1996
+ const imgBinary = this.helpers.assertBinaryData(itemIndex, imgField);
1997
+ const imgBuffer = await this.helpers.getBinaryDataBuffer(itemIndex, imgField);
1998
+ inlineImages.push({
1999
+ name: imgBinary.fileName || imgField,
2000
+ contentType: imgBinary.mimeType || "application/octet-stream",
2001
+ contentBytes: imgBuffer.toString("base64"),
2002
+ contentId: entry.contentId.trim() || imgField,
2003
+ });
2004
+ }
2005
+ const adaptiveCardJson = (() => {
2006
+ const include = this.getNodeParameter("draftIncludeAdaptiveCard", itemIndex, false);
2007
+ if (!include)
2008
+ return undefined;
2009
+ const raw = this.getNodeParameter("draftAdaptiveCardJson", itemIndex, "").trim();
2010
+ return raw || undefined;
2011
+ })();
2012
+ const draft = await graph_1.createDraft.call(this, config, draftFolderId || undefined, {
2013
+ subject: draftSubject || undefined,
2014
+ body: draftBody || undefined,
2015
+ bodyType: draftBodyType,
2016
+ to: draftTo || undefined,
2017
+ cc: draftCc || undefined,
2018
+ bcc: draftBcc || undefined,
2019
+ adaptiveCardJson,
2020
+ attachments: attachments.length > 0 ? attachments : undefined,
2021
+ inlineImages: inlineImages.length > 0 ? inlineImages : undefined,
2022
+ });
2023
+ returnData.push({ json: draft });
2024
+ continue;
2025
+ }
2026
+ if (operation === "get") {
2027
+ const opts = this.getNodeParameter("draftGetOptions", itemIndex, {});
2028
+ const expand = (opts.expand || "").trim();
2029
+ const filter = (opts.filter || "").trim();
2030
+ const orderBy = opts.orderBy || "lastModifiedDateTime desc";
2031
+ const selectRaw = opts.select;
2032
+ const selectFields = Array.isArray(selectRaw)
2033
+ ? selectRaw.join(",")
2034
+ : typeof selectRaw === "string"
2035
+ ? selectRaw
2036
+ .split(",")
2037
+ .map((s) => s.trim())
2038
+ .filter(Boolean)
2039
+ .join(",")
2040
+ : "";
2041
+ const bodyToMarkdown = (_f = opts.bodyToMarkdown) !== null && _f !== void 0 ? _f : false;
2042
+ const draftGetId = this.getNodeParameter("draftId", itemIndex, "").trim();
2043
+ if (draftGetId) {
2044
+ const qs = {};
2045
+ if (expand)
2046
+ qs.$expand = expand;
2047
+ if (selectFields)
2048
+ qs.$select = selectFields;
2049
+ const message = await graph_1.getMessage.call(this, config, draftGetId, Object.keys(qs).length > 0 ? qs : undefined);
2050
+ returnData.push({
2051
+ json: bodyToMarkdown ? (0, graph_1.convertBodyToMarkdown)(message) : message,
2052
+ });
2053
+ }
2054
+ else {
2055
+ const limit = typeof opts.limit === "number" ? opts.limit : 25;
2056
+ const qs = {
2057
+ $orderby: orderBy,
2058
+ $top: Math.min(limit, 1000),
2059
+ };
2060
+ if (filter)
2061
+ qs.$filter = filter;
2062
+ if (expand)
2063
+ qs.$expand = expand;
2064
+ if (selectFields)
2065
+ qs.$select = selectFields;
2066
+ const messages = await graph_1.listMessages.call(this, config, "Drafts", qs, false);
2067
+ const mapped = bodyToMarkdown
2068
+ ? messages.map(graph_1.convertBodyToMarkdown)
2069
+ : messages;
2070
+ returnData.push(...this.helpers.returnJsonArray(mapped));
2071
+ }
2072
+ continue;
2073
+ }
2074
+ const draftId = this.getNodeParameter("draftId", itemIndex);
2075
+ if (operation === "delete") {
2076
+ await graph_1.deleteMessage.call(this, config, draftId);
2077
+ returnData.push({
2078
+ json: { success: true, operation: "delete", draftId },
2079
+ });
2080
+ continue;
2081
+ }
2082
+ if (operation === "send") {
2083
+ await graph_1.sendDraft.call(this, config, draftId);
2084
+ returnData.push({
2085
+ json: { success: true, operation: "send", draftId },
2086
+ });
2087
+ continue;
2088
+ }
2089
+ if (operation === "update") {
2090
+ const f = this.getNodeParameter("draftUpdateFields", itemIndex, {});
2091
+ const body = {};
2092
+ if (f.subject)
2093
+ body.subject = f.subject.trim();
2094
+ if (f.body) {
2095
+ body.body = {
2096
+ contentType: f.bodyType === "html" ? "HTML" : "Text",
2097
+ content: f.body.trim(),
2098
+ };
2099
+ }
2100
+ if (f.to) {
2101
+ body.toRecipients = f.to
2102
+ .split(",")
2103
+ .map((a) => a.trim())
2104
+ .filter(Boolean)
2105
+ .map((address) => ({ emailAddress: { address } }));
2106
+ }
2107
+ if (f.cc) {
2108
+ body.ccRecipients = f.cc
2109
+ .split(",")
2110
+ .map((a) => a.trim())
2111
+ .filter(Boolean)
2112
+ .map((address) => ({ emailAddress: { address } }));
2113
+ }
2114
+ if (f.bcc) {
2115
+ body.bccRecipients = f.bcc
2116
+ .split(",")
2117
+ .map((a) => a.trim())
2118
+ .filter(Boolean)
2119
+ .map((address) => ({ emailAddress: { address } }));
2120
+ }
2121
+ if (f.importance)
2122
+ body.importance = f.importance;
2123
+ let additionalBody = (_g = f.additionalBody) !== null && _g !== void 0 ? _g : "{}";
2124
+ if (typeof additionalBody === "string") {
2125
+ try {
2126
+ additionalBody = JSON.parse(additionalBody);
2127
+ }
2128
+ catch {
2129
+ throw new Error("Invalid JSON in Additional Body (JSON) field");
2130
+ }
2131
+ }
2132
+ if (additionalBody &&
2133
+ typeof additionalBody === "object" &&
2134
+ Object.keys(additionalBody).length > 0) {
2135
+ Object.assign(body, additionalBody);
2136
+ }
2137
+ const draftEtag = this.getNodeParameter("draftIfMatchETag", itemIndex, "").trim();
2138
+ const updated = await graph_1.updateMessage.call(this, config, draftId, body, draftEtag || undefined);
2139
+ returnData.push({ json: updated });
2140
+ continue;
2141
+ }
2142
+ }
2143
+ // ── SENT ITEM ──
2144
+ if (resource === "sentItem") {
2145
+ const config = { mailboxMode: "current" };
2146
+ if (operation === "get") {
2147
+ const opts = this.getNodeParameter("sentItemOptions", itemIndex, {});
2148
+ const expand = (opts.expand || "").trim();
2149
+ const filter = (opts.filter || "").trim();
2150
+ const orderBy = opts.orderBy || "receivedDateTime desc";
2151
+ const selectRaw = opts.select;
2152
+ const selectFields = Array.isArray(selectRaw)
2153
+ ? selectRaw.join(",")
2154
+ : typeof selectRaw === "string"
2155
+ ? selectRaw
2156
+ .split(",")
2157
+ .map((s) => s.trim())
2158
+ .filter(Boolean)
2159
+ .join(",")
2160
+ : "";
2161
+ const bodyToMarkdown = (_h = opts.bodyToMarkdown) !== null && _h !== void 0 ? _h : false;
2162
+ const sentItemMessageId = this.getNodeParameter("sentItemMessageId", itemIndex, "").trim();
2163
+ if (sentItemMessageId) {
2164
+ const qs = {};
2165
+ if (expand)
2166
+ qs.$expand = expand;
2167
+ if (selectFields)
2168
+ qs.$select = selectFields;
2169
+ const msg = await graph_1.getSentMessage.call(this, config, sentItemMessageId, Object.keys(qs).length > 0 ? qs : undefined);
2170
+ returnData.push({
2171
+ json: bodyToMarkdown ? (0, graph_1.convertBodyToMarkdown)(msg) : msg,
2172
+ });
2173
+ }
2174
+ else {
2175
+ const limit = typeof opts.limit === "number" ? opts.limit : 25;
2176
+ const qs = {
2177
+ $orderby: orderBy,
2178
+ $top: Math.min(limit, 1000),
2179
+ };
2180
+ if (filter)
2181
+ qs.$filter = filter;
2182
+ if (expand)
2183
+ qs.$expand = expand;
2184
+ if (selectFields)
2185
+ qs.$select = selectFields;
2186
+ const messages = await graph_1.listSentMessages.call(this, config, qs, false);
2187
+ const mapped = bodyToMarkdown
2188
+ ? messages.map(graph_1.convertBodyToMarkdown)
2189
+ : messages;
2190
+ returnData.push(...this.helpers.returnJsonArray(mapped));
2191
+ }
2192
+ continue;
2193
+ }
2194
+ }
1058
2195
  // ── ATTACHMENT ──
1059
2196
  if (resource === "attachment") {
1060
2197
  const messageId = this.getNodeParameter("messageId", itemIndex);