diff --git a/src/batch/batch.ts b/src/batch/batch.ts index e0dc97d0..18829170 100644 --- a/src/batch/batch.ts +++ b/src/batch/batch.ts @@ -1,4 +1,6 @@ import type * as React from 'react'; +import type { EmailApiOptions } from '../common/interfaces/email-api-options.interface'; +import { parseEmailToApiOptions } from '../common/utils/parse-email-to-api-options'; import type { Resend } from '../resend'; import type { CreateBatchOptions, @@ -22,6 +24,8 @@ export class Batch { payload: CreateBatchOptions, options: CreateBatchRequestOptions = {}, ): Promise { + const emails: EmailApiOptions[] = []; + for (const email of payload) { if (email.react) { if (!this.renderAsync) { @@ -38,11 +42,13 @@ export class Batch { email.html = await this.renderAsync(email.react as React.ReactElement); email.react = undefined; } + + emails.push(parseEmailToApiOptions(email)); } const data = await this.resend.post( '/emails/batch', - payload, + emails, options, ); diff --git a/src/common/interfaces/email-api-options.interface.ts b/src/common/interfaces/email-api-options.interface.ts new file mode 100644 index 00000000..f13a3b85 --- /dev/null +++ b/src/common/interfaces/email-api-options.interface.ts @@ -0,0 +1,18 @@ +import type { Attachment } from '../../emails/interfaces/create-email-options.interface'; +import type { Tag } from '../../interfaces'; + +export interface EmailApiOptions { + from: string; + to: string | string[]; + subject: string; + region?: string; + headers?: Record; + html?: string; + text?: string; + bcc?: string | string[]; + cc?: string | string[]; + reply_to?: string | string[]; + scheduled_at?: string; + tags?: Tag[]; + attachments?: Attachment[]; +} diff --git a/src/common/utils/parse-email-to-api-options.spec.ts b/src/common/utils/parse-email-to-api-options.spec.ts new file mode 100644 index 00000000..9e1b7350 --- /dev/null +++ b/src/common/utils/parse-email-to-api-options.spec.ts @@ -0,0 +1,44 @@ +import type { CreateEmailOptions } from '../../emails/interfaces/create-email-options.interface'; +import { parseEmailToApiOptions } from './parse-email-to-api-options'; + +describe('parseEmailToApiOptions', () => { + it('should handle minimal email with only required fields', () => { + const emailPayload: CreateEmailOptions = { + from: 'joao@resend.com', + to: 'bu@resend.com', + subject: 'Hey, there!', + html: '

Hey, there!

', + }; + + const apiOptions = parseEmailToApiOptions(emailPayload); + + expect(apiOptions).toEqual({ + from: 'joao@resend.com', + to: 'bu@resend.com', + subject: 'Hey, there!', + html: '

Hey, there!

', + }); + }); + + it('should properly parse camel case to snake case', () => { + const emailPayload: CreateEmailOptions = { + from: 'joao@resend.com', + to: 'bu@resend.com', + subject: 'Hey, there!', + html: '

Hey, there!

', + replyTo: 'zeno@resend.com', + scheduledAt: 'in 1 min', + }; + + const apiOptions = parseEmailToApiOptions(emailPayload); + + expect(apiOptions).toEqual({ + from: 'joao@resend.com', + to: 'bu@resend.com', + subject: 'Hey, there!', + html: '

Hey, there!

', + reply_to: 'zeno@resend.com', + scheduled_at: 'in 1 min', + }); + }); +}); diff --git a/src/common/utils/parse-email-to-api-options.ts b/src/common/utils/parse-email-to-api-options.ts new file mode 100644 index 00000000..cd935ace --- /dev/null +++ b/src/common/utils/parse-email-to-api-options.ts @@ -0,0 +1,21 @@ +import type { CreateEmailOptions } from '../../emails/interfaces/create-email-options.interface'; +import type { EmailApiOptions } from '../interfaces/email-api-options.interface'; + +export function parseEmailToApiOptions( + email: CreateEmailOptions, +): EmailApiOptions { + return { + attachments: email.attachments, + bcc: email.bcc, + cc: email.cc, + from: email.from, + headers: email.headers, + html: email.html, + reply_to: email.replyTo, + scheduled_at: email.scheduledAt, + subject: email.subject, + tags: email.tags, + text: email.text, + to: email.to, + }; +} diff --git a/src/emails/emails.ts b/src/emails/emails.ts index 952aff3b..23c13b0c 100644 --- a/src/emails/emails.ts +++ b/src/emails/emails.ts @@ -1,4 +1,5 @@ import type * as React from 'react'; +import { parseEmailToApiOptions } from '../common/utils/parse-email-to-api-options'; import type { Resend } from '../resend'; import type { CancelEmailResponse, @@ -54,20 +55,7 @@ export class Emails { const data = await this.resend.post( '/emails', - { - attachments: payload.attachments, - bcc: payload.bcc, - cc: payload.cc, - from: payload.from, - headers: payload.headers, - html: payload.html, - reply_to: payload.replyTo, - scheduled_at: payload.scheduledAt, - subject: payload.subject, - tags: payload.tags, - text: payload.text, - to: payload.to, - }, + parseEmailToApiOptions(payload), options, ); diff --git a/src/emails/interfaces/create-email-options.interface.ts b/src/emails/interfaces/create-email-options.interface.ts index 0e4a5921..f76d561e 100644 --- a/src/emails/interfaces/create-email-options.interface.ts +++ b/src/emails/interfaces/create-email-options.interface.ts @@ -103,7 +103,7 @@ export interface CreateEmailResponse { error: ErrorResponse | null; } -interface Attachment { +export interface Attachment { /** Content of an attached file. */ content?: string | Buffer; /** Name of attached file. */