From 30a98746ef41a200ef44ac89946b6dc0780ffa32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20Akca?= Date: Wed, 24 Apr 2024 11:38:08 +0200 Subject: [PATCH] feat(gmail): add reply to email action --- .../backend/src/apps/gmail/actions/index.js | 3 +- .../gmail/actions/reply-to-email/index.js | 228 ++++++++++++++++++ .../src/apps/gmail/dynamic-data/index.js | 3 +- .../gmail/dynamic-data/list-threads/index.js | 31 +++ packages/docs/pages/apps/gmail/actions.md | 2 + 5 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 packages/backend/src/apps/gmail/actions/reply-to-email/index.js create mode 100644 packages/backend/src/apps/gmail/dynamic-data/list-threads/index.js diff --git a/packages/backend/src/apps/gmail/actions/index.js b/packages/backend/src/apps/gmail/actions/index.js index e1d8a996..2c7da906 100644 --- a/packages/backend/src/apps/gmail/actions/index.js +++ b/packages/backend/src/apps/gmail/actions/index.js @@ -1,3 +1,4 @@ +import replyToEmail from './reply-to-email/index.js'; import sendEmail from './send-email/index.js'; -export default [sendEmail]; +export default [replyToEmail, sendEmail]; diff --git a/packages/backend/src/apps/gmail/actions/reply-to-email/index.js b/packages/backend/src/apps/gmail/actions/reply-to-email/index.js new file mode 100644 index 00000000..5585e6b1 --- /dev/null +++ b/packages/backend/src/apps/gmail/actions/reply-to-email/index.js @@ -0,0 +1,228 @@ +import defineAction from '../../../../helpers/define-action.js'; + +export default defineAction({ + name: 'Reply to email', + key: 'replyToEmail', + description: 'Respond to an email.', + arguments: [ + { + label: 'Thread', + key: 'threadId', + type: 'dropdown', + required: false, + description: '', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listThreads', + }, + ], + }, + }, + { + label: 'TOs', + key: 'tos', + type: 'dynamic', + required: false, + description: 'Who will receive this email?', + fields: [ + { + label: 'To', + key: 'to', + type: 'string', + required: false, + variables: true, + }, + ], + }, + { + label: 'CCs', + key: 'ccs', + type: 'dynamic', + required: false, + description: + 'Who else needs to be included in the CC field of this email?', + fields: [ + { + label: 'CC', + key: 'cc', + type: 'string', + required: false, + variables: true, + }, + ], + }, + { + label: 'BCCs', + key: 'bccs', + type: 'dynamic', + required: false, + description: + 'Who else needs to be included in the BCC field of this email?', + fields: [ + { + label: 'BCC', + key: 'bcc', + type: 'string', + required: false, + variables: true, + }, + ], + }, + { + label: 'From', + key: 'from', + type: 'dropdown', + required: false, + description: + 'Choose an email address or alias from your Gmail Account. This defaults to the primary email address.', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listEmails', + }, + ], + }, + }, + { + label: 'From Name', + key: 'fromName', + type: 'string', + required: false, + description: '', + variables: true, + }, + { + label: 'Reply To', + key: 'replyTo', + type: 'string', + required: false, + description: 'Specify a single reply address other than your own.', + variables: true, + }, + { + label: 'Body Type', + key: 'bodyType', + type: 'dropdown', + required: false, + description: '', + variables: true, + options: [ + { + label: 'plain', + value: 'plain', + }, + { + label: 'html', + value: 'html', + }, + ], + }, + { + label: 'Body', + key: 'emailBody', + type: 'string', + required: true, + description: '', + variables: true, + }, + { + label: 'Label', + key: 'labelId', + type: 'dropdown', + required: false, + description: '', + variables: true, + source: { + type: 'query', + name: 'getDynamicData', + arguments: [ + { + name: 'key', + value: 'listLabels', + }, + ], + }, + }, + ], + + async run($) { + const { + tos, + ccs, + bccs, + from, + fromName, + replyTo, + threadId, + bodyType, + emailBody, + labelId, + } = $.step.parameters; + const userId = $.auth.data.userId; + + const allTos = tos?.map((entry) => entry.to); + const allCcs = ccs?.map((entry) => entry.cc); + const allBccs = bccs?.map((entry) => entry.bcc); + const contentType = + bodyType === 'html' + ? 'text/html; charset="UTF-8"' + : 'text/plain; charset="UTF-8"'; + + const email = + 'From: ' + + fromName + + ' <' + + from + + '>' + + '\r\n' + + 'In-Reply-To: ' + + threadId + + '\r\n' + + 'References: ' + + threadId + + '\r\n' + + 'Reply-To: ' + + replyTo + + '\r\n' + + 'To: ' + + allTos.join(',') + + '\r\n' + + 'Cc: ' + + allCcs.join(',') + + '\r\n' + + 'Bcc: ' + + allBccs.join(',') + + '\r\n' + + 'Content-Type: ' + + contentType + + '\r\n' + + '\r\n' + + emailBody; + + const base64EncodedEmailBody = Buffer.from(email).toString('base64'); + + const body = { + threadId: threadId, + labelIds: [labelId], + raw: base64EncodedEmailBody, + }; + + const { data } = await $.http.post( + `/gmail/v1/users/${userId}/messages/send`, + body + ); + + $.setActionItem({ + raw: data, + }); + }, +}); diff --git a/packages/backend/src/apps/gmail/dynamic-data/index.js b/packages/backend/src/apps/gmail/dynamic-data/index.js index 46af300e..a89b1b9b 100644 --- a/packages/backend/src/apps/gmail/dynamic-data/index.js +++ b/packages/backend/src/apps/gmail/dynamic-data/index.js @@ -1,5 +1,6 @@ import listEmails from './list-emails/index.js'; import listLabels from './list-labels/index.js'; import listSignatures from './list-signatures/index.js'; +import listThreads from './list-threads/index.js'; -export default [listEmails, listLabels, listSignatures]; +export default [listEmails, listLabels, listSignatures, listThreads]; diff --git a/packages/backend/src/apps/gmail/dynamic-data/list-threads/index.js b/packages/backend/src/apps/gmail/dynamic-data/list-threads/index.js new file mode 100644 index 00000000..6d40fa2f --- /dev/null +++ b/packages/backend/src/apps/gmail/dynamic-data/list-threads/index.js @@ -0,0 +1,31 @@ +export default { + name: 'List threads', + key: 'listThreads', + + async run($) { + const threads = { + data: [], + }; + const userId = $.auth.data.userId; + + const { data } = await $.http.get(`/gmail/v1/users/${userId}/threads`); + + if (data.threads) { + for (const thread of data.threads) { + const { data: threadData } = await $.http.get( + `/gmail/v1/users/${userId}/threads/${thread.id}` + ); + const subject = threadData.messages[0].payload.headers.find( + (header) => header.name === 'Subject' + ); + + threads.data.push({ + value: thread.id, + name: subject?.value, + }); + } + } + + return threads; + }, +}; diff --git a/packages/docs/pages/apps/gmail/actions.md b/packages/docs/pages/apps/gmail/actions.md index 2f12fe51..7b979195 100644 --- a/packages/docs/pages/apps/gmail/actions.md +++ b/packages/docs/pages/apps/gmail/actions.md @@ -1,6 +1,8 @@ --- favicon: /favicons/gmail.svg items: + - name: Reply to email + desc: Respond to an email. - name: Send email desc: Send a new email message. ---