Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,27 @@ console.log(`Email ${data.id} with a React template has been sent`);
>});
>```

## Request options

`timeoutMs` and `retries` can be set as defaults for all requests, or overridden per call:

```ts
const resend = new Resend('re_xxx', {
timeoutMs: 10_000, // abort each request attempt after 10s
retries: 3, // retry 429s, 5xx, and network errors
});

// override for a single request
await resend.emails.send({ ... }, { timeoutMs: 30_000, retries: 1 });
```

When retrying, a `Retry-After` response header is honored; otherwise exponential backoff is applied. Timeouts and aborts are not retried. To cancel a request manually, pass an `AbortSignal`:

```ts
const controller = new AbortController();
await resend.emails.send({ ... }, { signal: controller.signal });
```

## License

MIT License
5 changes: 4 additions & 1 deletion src/api-keys/api-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ export class ApiKeys {
async list(options: ListApiKeysOptions = {}): Promise<ListApiKeysResponse> {
const url = buildPaginationUrl('/api-keys', options);

const data = await this.resend.get<ListApiKeysResponseSuccess>(url);
const data = await this.resend.get<ListApiKeysResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
5 changes: 4 additions & 1 deletion src/automation-runs/automation-runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ export class AutomationRuns {
? `/automations/${options.automationId}/runs?${qs}`
: `/automations/${options.automationId}/runs`;

const data = await this.resend.get<ListAutomationRunsResponseSuccess>(url);
const data = await this.resend.get<ListAutomationRunsResponseSuccess>(
url,
options,
);
return data;
}
}
5 changes: 4 additions & 1 deletion src/automations/automations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ export class Automations {
const qs = params.filter(Boolean).join('&');
const url = qs ? `/automations?${qs}` : '/automations';

const data = await this.resend.get<ListAutomationsResponseSuccess>(url);
const data = await this.resend.get<ListAutomationsResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
5 changes: 4 additions & 1 deletion src/broadcasts/broadcasts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ export class Broadcasts {
): Promise<ListBroadcastsResponse> {
const url = buildPaginationUrl('/broadcasts', options);

const data = await this.resend.get<ListBroadcastsResponseSuccess>(url);
const data = await this.resend.get<ListBroadcastsResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
4 changes: 3 additions & 1 deletion src/common/interfaces/delete-option.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export interface DeleteOptions {
import type { RequestOptions } from './request-options.interface';

export interface DeleteOptions extends RequestOptions {
headers?: HeadersInit;
}
4 changes: 3 additions & 1 deletion src/common/interfaces/get-option.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export interface GetOptions {
import type { RequestOptions } from './request-options.interface';

export interface GetOptions extends RequestOptions {
query?: Record<string, unknown>;
headers?: HeadersInit;
}
1 change: 1 addition & 0 deletions src/common/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export * from './pagination-options.interface';
export * from './patch-option.interface';
export * from './post-option.interface';
export * from './put-option.interface';
export * from './request-options.interface';
export * from './require-at-least-one';
5 changes: 4 additions & 1 deletion src/common/interfaces/pagination-options.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { RequestOptions } from './request-options.interface';

// Pagination options using cursor-based approach
export type PaginationOptions = {
/**
Expand All @@ -19,7 +21,8 @@ export type PaginationOptions = {
before?: string;
after?: never;
}
);
) &
RequestOptions;

export type PaginatedData<Data> = {
object: 'list';
Expand Down
4 changes: 3 additions & 1 deletion src/common/interfaces/patch-option.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export interface PatchOptions {
import type { RequestOptions } from './request-options.interface';

export interface PatchOptions extends RequestOptions {
query?: { [key: string]: unknown };
headers?: HeadersInit;
}
4 changes: 3 additions & 1 deletion src/common/interfaces/post-option.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export interface PostOptions {
import type { RequestOptions } from './request-options.interface';

export interface PostOptions extends RequestOptions {
query?: { [key: string]: unknown };
headers?: HeadersInit;
}
4 changes: 3 additions & 1 deletion src/common/interfaces/put-option.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export interface PutOptions {
import type { RequestOptions } from './request-options.interface';

export interface PutOptions extends RequestOptions {
query?: { [key: string]: unknown };
headers?: HeadersInit;
}
12 changes: 12 additions & 0 deletions src/common/interfaces/request-options.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface RequestOptions {
/** Optional AbortSignal to cancel the request (also stops any pending retries). */
signal?: AbortSignal;
/** Timeout in milliseconds per request attempt. Aborts the attempt when exceeded. */
timeoutMs?: number;
/**
* Maximum number of retries for retryable failures (HTTP 429, 5xx, and network errors).
* A Retry-After header is honored when present, otherwise exponential backoff is used.
* Timeouts and aborts are not retried.
*/
retries?: number;
}
2 changes: 1 addition & 1 deletion src/contact-properties/contact-properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class ContactProperties {
const url = buildPaginationUrl('/contact-properties', options);

const response =
await this.resend.get<ListContactPropertiesResponseSuccess>(url);
await this.resend.get<ListContactPropertiesResponseSuccess>(url, options);

if (response.data) {
return {
Expand Down
10 changes: 8 additions & 2 deletions src/contacts/contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,18 @@ export class Contacts {
const segmentId = options.segmentId ?? options.audienceId;
if (!segmentId) {
const url = buildPaginationUrl('/contacts', options);
const data = await this.resend.get<ListContactsResponseSuccess>(url);
const data = await this.resend.get<ListContactsResponseSuccess>(
url,
options,
);
return data;
}

const url = buildPaginationUrl(`/segments/${segmentId}/contacts`, options);
const data = await this.resend.get<ListContactsResponseSuccess>(url);
const data = await this.resend.get<ListContactsResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
2 changes: 1 addition & 1 deletion src/contacts/imports/contact-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class ContactImports {
? `/contacts/imports?${queryString}`
: '/contacts/imports';

return this.resend.get<ListContactImportsResponseSuccess>(url);
return this.resend.get<ListContactImportsResponseSuccess>(url, options);
}

async get(id: string): Promise<GetContactImportResponse> {
Expand Down
5 changes: 4 additions & 1 deletion src/contacts/segments/contact-segments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ export class ContactSegments {
const identifier = options.email ? options.email : options.contactId;
const url = buildPaginationUrl(`/contacts/${identifier}/segments`, options);

const data = await this.resend.get<ListContactSegmentsResponseSuccess>(url);
const data = await this.resend.get<ListContactSegmentsResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
2 changes: 1 addition & 1 deletion src/contacts/topics/contact-topics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ export class ContactTopics {
const identifier = options.email ? options.email : options.id;
const url = buildPaginationUrl(`/contacts/${identifier}/topics`, options);

return this.resend.get<ListContactTopicsResponseSuccess>(url);
return this.resend.get<ListContactTopicsResponseSuccess>(url, options);
}
}
5 changes: 4 additions & 1 deletion src/domains/domains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ export class Domains {
async list(options: ListDomainsOptions = {}): Promise<ListDomainsResponse> {
const url = buildPaginationUrl('/domains', options);

const data = await this.resend.get<ListDomainsResponseSuccess>(url);
const data = await this.resend.get<ListDomainsResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
5 changes: 4 additions & 1 deletion src/emails/attachments/attachments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ export class Attachments {

const url = buildPaginationUrl(`/emails/${emailId}/attachments`, options);

const data = await this.resend.get<ListAttachmentsResponseSuccess>(url);
const data = await this.resend.get<ListAttachmentsResponseSuccess>(
url,
options,
);

return data;
}
Expand Down
2 changes: 1 addition & 1 deletion src/emails/emails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class Emails {
async list(options: ListEmailsOptions = {}): Promise<ListEmailsResponse> {
const url = buildPaginationUrl('/emails', options);

const data = await this.resend.get<ListEmailsResponseSuccess>(url);
const data = await this.resend.get<ListEmailsResponseSuccess>(url, options);

return data;
}
Expand Down
5 changes: 4 additions & 1 deletion src/emails/receiving/attachments/attachments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ export class Attachments {
options,
);

const data = await this.resend.get<ListAttachmentsResponseSuccess>(url);
const data = await this.resend.get<ListAttachmentsResponseSuccess>(
url,
options,
);

return data;
}
Expand Down
5 changes: 4 additions & 1 deletion src/emails/receiving/receiving.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ export class Receiving {
): Promise<ListReceivingEmailsResponse> {
const url = buildPaginationUrl('/emails/receiving', options);

const data = await this.resend.get<ListReceivingEmailsResponseSuccess>(url);
const data = await this.resend.get<ListReceivingEmailsResponseSuccess>(
url,
options,
);

return data;
}
Expand Down
2 changes: 1 addition & 1 deletion src/events/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class Events {

async list(options: ListEventsOptions = {}): Promise<ListEventsResponse> {
const url = buildPaginationUrl('/events', options);
const data = await this.resend.get<ListEventsResponseSuccess>(url);
const data = await this.resend.get<ListEventsResponseSuccess>(url, options);
return data;
}

Expand Down
2 changes: 1 addition & 1 deletion src/logs/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class Logs {

async list(options: ListLogsOptions = {}): Promise<ListLogsResponse> {
const url = buildPaginationUrl('/logs', options);
const data = await this.resend.get<ListLogsResponseSuccess>(url);
const data = await this.resend.get<ListLogsResponseSuccess>(url, options);
return data;
}

Expand Down
5 changes: 4 additions & 1 deletion src/oauth-grants/oauth-grants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export class OAuthGrants {
): Promise<ListOAuthGrantsResponse> {
const url = buildPaginationUrl('/oauth/grants', options);

const data = await this.resend.get<ListOAuthGrantsResponseSuccess>(url);
const data = await this.resend.get<ListOAuthGrantsResponseSuccess>(
url,
options,
);
return data;
}

Expand Down
Loading