UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 10.1 kB
{"version":3,"file":"send-email.mjs","names":[],"sources":["../../../../src/services/email/jobs/send-email.ts"],"sourcesContent":["import { normalizeEmailAttachments } from \"../../../libs/email/attachments.js\";\nimport isEmailSimulated from \"../../../libs/email/is-simulated.js\";\nimport {\n\tcreateStoredEmailData,\n\thasNeverStoreEmailStorageRules,\n\tresolveEmailData,\n\tstripNeverStoreEmailData,\n} from \"../../../libs/email/storage/index.js\";\nimport renderMustacheTemplate from \"../../../libs/email/templates/render-mustache-template.js\";\nimport type { EmailStrategyResponse } from \"../../../libs/email/types.js\";\nimport { copy } from \"../../../libs/i18n/index.js\";\nimport {\n\tEmailsRepository,\n\tEmailTransactionsRepository,\n} from \"../../../libs/repositories/index.js\";\nimport type { LucidErrorData } from \"../../../types/errors.js\";\nimport type { ServiceFn } from \"../../../utils/services/types.js\";\n\nconst sendEmail: ServiceFn<\n\t[\n\t\t{\n\t\t\temailId: number;\n\t\t\ttransactionId: number;\n\t\t},\n\t],\n\tundefined\n> = async (context, data) => {\n\tconst Emails = new EmailsRepository(context.db.client, context.config.db);\n\tconst EmailTransactions = new EmailTransactionsRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\n\tconst emailRes = await Emails.selectSingleById({\n\t\tid: data.emailId,\n\t\tvalidation: {\n\t\t\tenabled: true,\n\t\t\tdefaultError: {\n\t\t\t\tmessage: copy(\"server:core.email.not.found.message\"),\n\t\t\t\tstatus: 404,\n\t\t\t},\n\t\t},\n\t});\n\tif (emailRes.error) return emailRes;\n\n\tconst sendDataRes = resolveEmailData({\n\t\tdata: emailRes.data.data,\n\t\tstorage: emailRes.data.storage_strategy,\n\t\tencryptionKey: context.config.secrets.encryption,\n\t\tmode: \"send\",\n\t});\n\tconst hasNeverStoreRes = hasNeverStoreEmailStorageRules(\n\t\temailRes.data.storage_strategy,\n\t);\n\tconst attachmentsRes = normalizeEmailAttachments(\n\t\temailRes.data.attachments?.map((attachment) => ({\n\t\t\ttype: attachment.type,\n\t\t\turl: attachment.url,\n\t\t\tfilename: attachment.filename,\n\t\t\tcontentType: attachment.content_type ?? undefined,\n\t\t\t...(attachment.disposition === \"inline\"\n\t\t\t\t? {\n\t\t\t\t\t\tdisposition: \"inline\" as const,\n\t\t\t\t\t\tcontentId: attachment.content_id ?? undefined,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tdisposition: \"attachment\" as const,\n\t\t\t\t\t}),\n\t\t})),\n\t);\n\n\tlet preSendError: LucidErrorData | undefined =\n\t\tsendDataRes.error ?? hasNeverStoreRes.error ?? attachmentsRes.error;\n\tlet sendData: Record<string, unknown> | null = null;\n\tlet hasNeverStore = false;\n\tlet htmlData: string | undefined;\n\n\tif (preSendError === undefined) {\n\t\tsendData = sendDataRes.error ? null : sendDataRes.data;\n\t\thasNeverStore = hasNeverStoreRes.error ? false : hasNeverStoreRes.data;\n\n\t\tconst html = await renderMustacheTemplate(context, {\n\t\t\ttemplate: emailRes.data.template,\n\t\t\tdata: sendData,\n\t\t});\n\t\tif (html.error) {\n\t\t\tpreSendError = html.error;\n\t\t} else {\n\t\t\thtmlData = html.data;\n\t\t}\n\t}\n\n\tif (preSendError) {\n\t\tawait Promise.all([\n\t\t\tEmails.updateSingle({\n\t\t\t\twhere: [{ key: \"id\", operator: \"=\", value: emailRes.data.id }],\n\t\t\t\tdata: {\n\t\t\t\t\tcurrent_status: \"failed\",\n\t\t\t\t\tattempt_count: (emailRes.data.attempt_count ?? 0) + 1,\n\t\t\t\t\tlast_attempted_at: new Date().toISOString(),\n\t\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t\t},\n\t\t\t}),\n\t\t\tEmailTransactions.updateSingle({\n\t\t\t\twhere: [{ key: \"id\", operator: \"=\", value: data.transactionId }],\n\t\t\t\tdata: {\n\t\t\t\t\tdelivery_status: \"failed\",\n\t\t\t\t\tmessage: context.translate.english(preSendError.message) ?? null,\n\t\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t\t},\n\t\t\t}),\n\t\t]);\n\n\t\treturn {\n\t\t\terror: preSendError,\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tlet result: EmailStrategyResponse;\n\tif (isEmailSimulated(context)) {\n\t\tresult = {\n\t\t\tsuccess: true,\n\t\t\tdeliveryStatus: \"sent\",\n\t\t\tmessage: copy(\"server:core.email.successfully.sent\"),\n\t\t\tdata: null,\n\t\t};\n\t} else {\n\t\ttry {\n\t\t\tresult = await context.email.send(context, {\n\t\t\t\tto: emailRes.data.to_address,\n\t\t\t\tsubject: emailRes.data.subject ?? \"\",\n\t\t\t\tfrom: {\n\t\t\t\t\temail: emailRes.data.from_address,\n\t\t\t\t\tname: emailRes.data.from_name,\n\t\t\t\t},\n\t\t\t\thtml: htmlData ?? \"\",\n\t\t\t\tcc: emailRes.data.cc ?? undefined,\n\t\t\t\tbcc: emailRes.data.bcc ?? undefined,\n\t\t\t\tpriority: emailRes.data.priority,\n\t\t\t\theaders: emailRes.data.headers,\n\t\t\t\tattachments: attachmentsRes.data,\n\t\t\t\tdata: sendData ?? {},\n\t\t\t\ttemplate: emailRes.data.template,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tresult = {\n\t\t\t\tsuccess: false,\n\t\t\t\tdeliveryStatus: \"failed\",\n\t\t\t\tmessage:\n\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t? copy.literal(error.message)\n\t\t\t\t\t\t: copy(\"server:core.email.failed.to.send\"),\n\t\t\t\texternalMessageId: null,\n\t\t\t};\n\t\t}\n\t}\n\n\tconst shouldStripNeverStore =\n\t\tresult.success === true && hasNeverStore === true;\n\tlet cleanedData: Record<string, unknown> | null | undefined;\n\n\tif (shouldStripNeverStore) {\n\t\tconst strippedDataRes = stripNeverStoreEmailData({\n\t\t\tdata: sendData,\n\t\t\tstorage: emailRes.data.storage_strategy,\n\t\t});\n\t\tif (strippedDataRes.error) return strippedDataRes;\n\n\t\tconst cleanedDataRes = createStoredEmailData({\n\t\t\tdata: strippedDataRes.data,\n\t\t\tstorage: emailRes.data.storage_strategy,\n\t\t\tencryptionKey: context.config.secrets.encryption,\n\t\t\toptions: {\n\t\t\t\tencryptNeverStore: false,\n\t\t\t},\n\t\t});\n\t\tif (cleanedDataRes.error) return cleanedDataRes;\n\n\t\tcleanedData = cleanedDataRes.data;\n\t}\n\n\tconst [updateRes, emailTransactionRes] = await Promise.all([\n\t\tEmails.updateSingle({\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"id\",\n\t\t\t\t\toperator: \"=\",\n\t\t\t\t\tvalue: emailRes.data.id,\n\t\t\t\t},\n\t\t\t],\n\t\t\tdata: {\n\t\t\t\tcurrent_status: result.deliveryStatus,\n\t\t\t\tattempt_count: (emailRes.data.attempt_count ?? 0) + 1,\n\t\t\t\tlast_attempted_at: new Date().toISOString(),\n\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t\t...(cleanedData !== undefined ? { data: cleanedData } : {}),\n\t\t\t},\n\t\t}),\n\t\tEmailTransactions.updateSingle({\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"id\",\n\t\t\t\t\toperator: \"=\",\n\t\t\t\t\tvalue: data.transactionId,\n\t\t\t\t},\n\t\t\t],\n\t\t\tdata: {\n\t\t\t\tdelivery_status: result.deliveryStatus,\n\t\t\t\tmessage: result.success\n\t\t\t\t\t? null\n\t\t\t\t\t: (context.translate.english(result.message) ?? null),\n\t\t\t\tstrategy_data: result.data,\n\t\t\t\texternal_message_id: result.externalMessageId,\n\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t},\n\t\t}),\n\t]);\n\n\tif (updateRes.error) return updateRes;\n\tif (emailTransactionRes.error) return emailTransactionRes;\n\n\treturn {\n\t\terror: undefined,\n\t\tdata: undefined,\n\t};\n};\n\nexport default sendEmail;\n"],"mappings":"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"}