Skip to content

Commit 5281e31

Browse files
committed
donotmerge: send fake email action
1 parent 8ae3855 commit 5281e31

File tree

3 files changed

+138
-7
lines changed
  • packages/backend/src/apps

3 files changed

+138
-7
lines changed

packages/backend/src/apps/postman-sms/actions/send-fake-sms/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { ZodError } from 'zod'
55

66
import HttpError from '@/errors/http'
77
import StepError, { GenericSolution } from '@/errors/step'
8-
import logger from '@/helpers/logger'
98
import { ensureZodObjectKey, firstZodParseError } from '@/helpers/zod-utils'
109

1110
import { authDataSchema } from '../../auth/schema'
@@ -76,11 +75,6 @@ const action = {
7675
},
7776
)
7877

79-
logger.error('Postman send single SMS response changed', {
80-
event: 'api-response-change',
81-
appName: 'postman-sms',
82-
eventName: 'sendSms',
83-
})
8478
$.setActionItem({
8579
raw: {
8680
// Signal to the user that an SMS has at least been created by now.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sendFakeTransactionalEmail from './send-fake-transactional-email'
12
import sendTransactionalEmail from './send-transactional-email'
23

3-
export default [sendTransactionalEmail]
4+
export default [sendTransactionalEmail, sendFakeTransactionalEmail]
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { IJSONArray, IRawAction } from '@plumber/types'
2+
3+
import axios from 'axios'
4+
import FormData from 'form-data'
5+
import { SafeParseError } from 'zod'
6+
import { fromZodError } from 'zod-validation-error'
7+
8+
import appConfig from '@/config/app'
9+
import StepError from '@/errors/step'
10+
import { getObjectFromS3Id } from '@/helpers/s3'
11+
import Step from '@/models/step'
12+
13+
import {
14+
transactionalEmailFields,
15+
transactionalEmailSchema,
16+
} from '../../common/parameters'
17+
import { getDefaultReplyTo } from '../../common/parameters-helper'
18+
19+
const action: IRawAction = {
20+
name: 'Send FAKE email',
21+
key: 'sendFakeTransactionalEmail',
22+
description: 'Sends an email using Postman',
23+
arguments: transactionalEmailFields,
24+
doesFileProcessing: (step: Step) => {
25+
return (
26+
step.parameters.attachments &&
27+
(step.parameters.attachments as IJSONArray).length > 0
28+
)
29+
},
30+
31+
async run($) {
32+
const {
33+
subject,
34+
body,
35+
destinationEmail,
36+
destinationEmailCc,
37+
senderName,
38+
replyTo,
39+
attachments = [],
40+
} = $.step.parameters
41+
const result = transactionalEmailSchema.safeParse({
42+
destinationEmail,
43+
destinationEmailCc,
44+
senderName,
45+
subject,
46+
body,
47+
replyTo: replyTo || (await getDefaultReplyTo($.flow.id)),
48+
attachments,
49+
})
50+
51+
if (!result.success) {
52+
const validationError = fromZodError(
53+
(result as SafeParseError<unknown>).error,
54+
)
55+
56+
const fieldName = validationError.details[0].path[0]
57+
const stepErrorName = validationError.details[0].message
58+
const isAttachmentNotStoredError =
59+
fieldName === 'attachments' && stepErrorName.includes('not a S3 ID')
60+
const stepErrorSolution = isAttachmentNotStoredError
61+
? 'This attachment was not stored in the last submission. Please make a new submission with attachments to successfully configure this pipe.'
62+
: 'Click on set up action and reconfigure the invalid field.'
63+
64+
throw new StepError(
65+
stepErrorName,
66+
stepErrorSolution,
67+
$.step.position,
68+
$.app.name,
69+
)
70+
}
71+
72+
const attachmentFiles = await Promise.all(
73+
result.data.attachments?.map(async (attachment) => {
74+
// We verify the flowId here to ensure that the attachment is from the same flow and not
75+
// maliciously/ manually injected by another user who does not have access to this attachment
76+
const obj = await getObjectFromS3Id(
77+
attachment,
78+
{ flowId: $.flow.id },
79+
$,
80+
)
81+
return { fileName: obj.name, data: obj.data }
82+
}),
83+
)
84+
85+
const recipientsToSend = result.data.destinationEmail
86+
87+
try {
88+
// mimic sending email
89+
const requestData = new FormData()
90+
requestData.append('subject', result.data.subject)
91+
requestData.append('body', result.data.body)
92+
requestData.append('recipient', recipientsToSend[0])
93+
requestData.append(
94+
'from',
95+
`${result.data.senderName} <${appConfig.postman.fromAddress}>`,
96+
)
97+
requestData.append('disable_tracking', 'true')
98+
99+
if (result.data.destinationEmailCc?.length > 0) {
100+
requestData.append('cc', JSON.stringify(result.data.destinationEmailCc))
101+
}
102+
103+
if (result.data.replyTo) {
104+
requestData.append('reply_to', result.data.replyTo)
105+
}
106+
107+
for (const attachment of attachmentFiles ?? []) {
108+
requestData.append(
109+
'attachments',
110+
Buffer.from(attachment.data),
111+
attachment.fileName,
112+
)
113+
}
114+
115+
const response = await axios.post(
116+
'https://kqbwrjfognb7gcslkta5dq37py0tswwl.lambda-url.ap-southeast-1.on.aws/',
117+
requestData,
118+
)
119+
120+
$.setActionItem({
121+
raw: {
122+
...response.data,
123+
},
124+
})
125+
} catch (e) {
126+
throw new StepError(
127+
'Error sending email',
128+
e.message,
129+
$.step.position,
130+
$.app.name,
131+
)
132+
}
133+
},
134+
}
135+
136+
export default action

0 commit comments

Comments
 (0)