diff --git a/README.md b/README.md index 69dc777..a942abf 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,15 @@ Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes * Mailbox * Get list of mailboxes (including status information like number of messages) - * Get status of a mailbox (number of messages, etc.) - * Create a mailbox - * Rename a mailbox - * ~Delete a mailbox~ (disabled due to danger of accidental data loss and no apparent use case) + * Get status of a mailbox (number of messages, etc.) + * Create a mailbox + * Rename a mailbox + * ~Delete a mailbox~ (disabled due to danger of accidental data loss and no apparent use case) * Email * Get list of emails in a mailbox - * Download attachments from an email - * Move an email to another mailbox + * Download attachments from an email + * Move an email to another mailbox + * Set/remove flags on an email ("seen", "answered", "flagged", "deleted", "draft") ## Credentials diff --git a/nodes/Imap/operations/email/OperationsList.ts b/nodes/Imap/operations/email/OperationsList.ts index cb1e6a1..b7882a1 100644 --- a/nodes/Imap/operations/email/OperationsList.ts +++ b/nodes/Imap/operations/email/OperationsList.ts @@ -3,6 +3,7 @@ import { resourceEmail } from "./ResourceName"; import { downloadAttachmentOperation } from "./functions/EmailDownloadAttachment"; import { getEmailsListOperation } from "./functions/EmailGetList"; import { moveEmailOperation } from "./functions/EmailMove"; +import { setEmailFlagsOperation } from "./functions/EmailSetFlags"; export const emailResourceDefinitions: IResourceDef = { resource: resourceEmail, @@ -10,6 +11,7 @@ export const emailResourceDefinitions: IResourceDef = { getEmailsListOperation, downloadAttachmentOperation, moveEmailOperation, + setEmailFlagsOperation, ], }; diff --git a/nodes/Imap/operations/email/functions/EmailMove.ts b/nodes/Imap/operations/email/functions/EmailMove.ts index 5114d0e..31ecd5d 100644 --- a/nodes/Imap/operations/email/functions/EmailMove.ts +++ b/nodes/Imap/operations/email/functions/EmailMove.ts @@ -25,6 +25,7 @@ export const moveEmailOperation: IResourceOperationDef = { type: 'string', default: '', description: 'UID of the email to move', + hint: 'You can use comma separated list of UIDs to move multiple emails at once', }, { ...parameterSelectMailbox, diff --git a/nodes/Imap/operations/email/functions/EmailSetFlags.ts b/nodes/Imap/operations/email/functions/EmailSetFlags.ts new file mode 100644 index 0000000..3d5c253 --- /dev/null +++ b/nodes/Imap/operations/email/functions/EmailSetFlags.ts @@ -0,0 +1,125 @@ +import { ImapFlow } from "imapflow"; +import { IExecuteFunctions, INodeExecutionData, NodeApiError } from "n8n-workflow"; +import { IResourceOperationDef } from "../../../utils/CommonDefinitions"; +import { getMailboxPathFromNodeParameter, parameterSelectMailbox } from '../../../utils/SearchFieldParameters'; + + +enum ImapFlags { + Answered = '\\Answered', + Flagged = '\\Flagged', + Deleted = '\\Deleted', + Seen = '\\Seen', + Draft = '\\Draft', +} + +export const setEmailFlagsOperation: IResourceOperationDef = { + operation: { + name: 'Set Flags', + value: 'setEmailFlags', + description: 'Set flags on an email like "Seen" or "Flagged"', + }, + parameters: [ + { + ...parameterSelectMailbox, + description: 'Select the mailbox', + }, + { + displayName: 'Email UID', + name: 'emailUid', + type: 'string', + default: '', + description: 'UID of the email to set flags', + hint: 'You can use comma separated list of UIDs', + }, + { + displayName: 'Flags', + name: 'flags', + type: 'collection', + default: [], + required: true, + placeholder: 'Add Flag', + options: [ + { + displayName: 'Answered', + name: ImapFlags.Answered, + type: 'boolean', + default: false, + description: 'Whether email is answered', + }, + { + displayName: 'Flagged', + name: ImapFlags.Flagged, + type: 'boolean', + default: false, + description: 'Whether email is flagged', + }, + { + displayName: 'Deleted', + name: ImapFlags.Deleted, + type: 'boolean', + default: false, + description: 'Whether email is deleted', + }, + { + displayName: 'Seen', + name: ImapFlags.Seen, + type: 'boolean', + default: false, + description: 'Whether email is seen', + }, + { + displayName: 'Draft', + name: ImapFlags.Draft, + type: 'boolean', + default: false, + description: 'Whether email is draft', + }, + ], + }, + ], + async executeImapAction(context: IExecuteFunctions, client: ImapFlow) { + var returnData: INodeExecutionData[] = []; + + const mailboxPath = getMailboxPathFromNodeParameter(context); + const emailUid = context.getNodeParameter('emailUid', 0) as string; + const flags = context.getNodeParameter('flags', 0) as unknown as { [key: string]: boolean }; + + var flagsToSet : string[] = []; + var flagsToRemove : string[] = []; + for (const flagName in flags) { + if (flags[flagName]) { + flagsToSet.push(flagName); + } else { + flagsToRemove.push(flagName); + } + } + + context.logger?.info(`Setting flags "${flagsToSet.join(',')}" and removing flags "${flagsToRemove.join(',')}" on email "${emailUid}"`); + + await client.mailboxOpen(mailboxPath, { readOnly: false }); + + if (flagsToSet.length > 0) { + const isSuccess : boolean = await client.messageFlagsAdd(emailUid, flagsToSet, { + uid: true, + }); + if (!isSuccess) { + throw new NodeApiError(context.getNode(), {}, { + message: "Unable to set flags, unknown error", + }); + } + } + if (flagsToRemove.length > 0) { + const isSuccess : boolean = await client.messageFlagsRemove(emailUid, flagsToRemove, { + uid: true, + }); + if (!isSuccess) { + throw new NodeApiError(context.getNode(), {}, { + message: "Unable to remove flags, unknown error", + }); + } + } + + client.close(); + return [returnData]; + }, +};