chub-dev 0.1.0 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1271 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: email
|
|
3
|
+
description: "Modern email API platform with React Email integration, batch sending, scheduling, webhooks, and domain management"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "6.2.2"
|
|
7
|
+
updated-on: "2025-10-26"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "resend,sdk,email,messaging"
|
|
10
|
+
---
|
|
11
|
+
# Resend Node.js SDK
|
|
12
|
+
|
|
13
|
+
## Golden Rule
|
|
14
|
+
|
|
15
|
+
**Always use the official `resend` package from npm.** The current version is 6.2.2.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install resend
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Do not use unofficial or deprecated packages like `@philnash/resend` or `resend-client-sdk-python`. The official Resend Node.js SDK is maintained at https://github.com/resend/resend-node.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
Install the Resend SDK using npm, yarn, or pnpm:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install resend
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Environment Setup
|
|
32
|
+
|
|
33
|
+
Store your API key in an environment variable:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# .env
|
|
37
|
+
RESEND_API_KEY=re_xxxxxxxxx
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
You can obtain an API key from the Resend Dashboard at https://resend.com/api-keys. The API key will only be shown once, so store it securely immediately.
|
|
41
|
+
|
|
42
|
+
## Initialization
|
|
43
|
+
|
|
44
|
+
Initialize the Resend client with your API key:
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
import { Resend } from 'resend';
|
|
48
|
+
|
|
49
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or with a hardcoded key (not recommended for production):
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const resend = new Resend('re_xxxxxxxxx');
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Sending Emails
|
|
59
|
+
|
|
60
|
+
### Basic Email
|
|
61
|
+
|
|
62
|
+
Send a simple HTML email:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
import { Resend } from 'resend';
|
|
66
|
+
|
|
67
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
68
|
+
|
|
69
|
+
const { data, error } = await resend.emails.send({
|
|
70
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
71
|
+
to: ['delivered@resend.dev'],
|
|
72
|
+
subject: 'Hello World',
|
|
73
|
+
html: '<p>Congrats on sending your <strong>first email</strong>!</p>',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (error) {
|
|
77
|
+
console.error(error);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(data);
|
|
82
|
+
// { id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Email with Plain Text
|
|
86
|
+
|
|
87
|
+
Send both HTML and plain text versions:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
const { data, error } = await resend.emails.send({
|
|
91
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
92
|
+
to: ['user@example.com'],
|
|
93
|
+
subject: 'Hello World',
|
|
94
|
+
html: '<p>This is the <strong>HTML</strong> version</p>',
|
|
95
|
+
text: 'This is the plain text version',
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
If you omit the `text` parameter, it will be auto-generated from the HTML.
|
|
100
|
+
|
|
101
|
+
### Email with Multiple Recipients
|
|
102
|
+
|
|
103
|
+
Send to up to 50 recipients:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
const { data, error } = await resend.emails.send({
|
|
107
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
108
|
+
to: ['user1@example.com', 'user2@example.com', 'user3@example.com'],
|
|
109
|
+
subject: 'Hello World',
|
|
110
|
+
html: '<p>Hello everyone!</p>',
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Email with CC and BCC
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const { data, error } = await resend.emails.send({
|
|
118
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
119
|
+
to: ['primary@example.com'],
|
|
120
|
+
cc: ['cc1@example.com', 'cc2@example.com'],
|
|
121
|
+
bcc: ['bcc1@example.com', 'bcc2@example.com'],
|
|
122
|
+
subject: 'Hello World',
|
|
123
|
+
html: '<p>Email with CC and BCC</p>',
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Email with Reply-To
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
const { data, error } = await resend.emails.send({
|
|
131
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
132
|
+
to: ['user@example.com'],
|
|
133
|
+
replyTo: 'support@acme.com',
|
|
134
|
+
subject: 'Hello World',
|
|
135
|
+
html: '<p>Reply to this email!</p>',
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Multiple reply-to addresses:
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
const { data, error } = await resend.emails.send({
|
|
143
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
144
|
+
to: ['user@example.com'],
|
|
145
|
+
replyTo: ['support@acme.com', 'help@acme.com'],
|
|
146
|
+
subject: 'Hello World',
|
|
147
|
+
html: '<p>Reply to this email!</p>',
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Email with Custom Headers
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const { data, error } = await resend.emails.send({
|
|
155
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
156
|
+
to: ['user@example.com'],
|
|
157
|
+
subject: 'Hello World',
|
|
158
|
+
html: '<p>Email with custom headers</p>',
|
|
159
|
+
headers: {
|
|
160
|
+
'X-Entity-Ref-ID': '123456789',
|
|
161
|
+
'X-Custom-Header': 'Custom Value',
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Email with Tags
|
|
167
|
+
|
|
168
|
+
Tags are custom key/value pairs for tracking and categorizing emails:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const { data, error } = await resend.emails.send({
|
|
172
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
173
|
+
to: ['user@example.com'],
|
|
174
|
+
subject: 'Hello World',
|
|
175
|
+
html: '<p>Email with tags</p>',
|
|
176
|
+
tags: [
|
|
177
|
+
{ name: 'category', value: 'confirm_email' },
|
|
178
|
+
{ name: 'user_id', value: '12345' },
|
|
179
|
+
],
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Email with Attachments
|
|
184
|
+
|
|
185
|
+
Attachments support up to 40MB per email after Base64 encoding:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
import fs from 'fs';
|
|
189
|
+
|
|
190
|
+
const { data, error } = await resend.emails.send({
|
|
191
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
192
|
+
to: ['user@example.com'],
|
|
193
|
+
subject: 'Invoice',
|
|
194
|
+
html: '<p>Please find your invoice attached</p>',
|
|
195
|
+
attachments: [
|
|
196
|
+
{
|
|
197
|
+
filename: 'invoice.pdf',
|
|
198
|
+
content: fs.readFileSync('./invoice.pdf'),
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Attachment with custom content type:
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
const { data, error } = await resend.emails.send({
|
|
208
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
209
|
+
to: ['user@example.com'],
|
|
210
|
+
subject: 'Report',
|
|
211
|
+
html: '<p>Your report is attached</p>',
|
|
212
|
+
attachments: [
|
|
213
|
+
{
|
|
214
|
+
filename: 'report.csv',
|
|
215
|
+
content: 'Name,Email\nJohn,john@example.com\n',
|
|
216
|
+
contentType: 'text/csv',
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Multiple attachments:
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
const { data, error } = await resend.emails.send({
|
|
226
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
227
|
+
to: ['user@example.com'],
|
|
228
|
+
subject: 'Multiple Files',
|
|
229
|
+
html: '<p>Multiple files attached</p>',
|
|
230
|
+
attachments: [
|
|
231
|
+
{
|
|
232
|
+
filename: 'document1.pdf',
|
|
233
|
+
content: fs.readFileSync('./document1.pdf'),
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
filename: 'document2.pdf',
|
|
237
|
+
content: fs.readFileSync('./document2.pdf'),
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Scheduled Email
|
|
244
|
+
|
|
245
|
+
Schedule an email using natural language or ISO 8601 format. Emails can be scheduled up to 30 days in advance.
|
|
246
|
+
|
|
247
|
+
Natural language examples:
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
const { data, error } = await resend.emails.send({
|
|
251
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
252
|
+
to: ['user@example.com'],
|
|
253
|
+
subject: 'Scheduled Email',
|
|
254
|
+
html: '<p>This email was scheduled</p>',
|
|
255
|
+
scheduledAt: 'in 1 hour',
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
const { data, error } = await resend.emails.send({
|
|
261
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
262
|
+
to: ['user@example.com'],
|
|
263
|
+
subject: 'Scheduled Email',
|
|
264
|
+
html: '<p>This email was scheduled</p>',
|
|
265
|
+
scheduledAt: 'tomorrow at 9am',
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
const { data, error } = await resend.emails.send({
|
|
271
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
272
|
+
to: ['user@example.com'],
|
|
273
|
+
subject: 'Scheduled Email',
|
|
274
|
+
html: '<p>This email was scheduled</p>',
|
|
275
|
+
scheduledAt: 'Friday at 3pm ET',
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
ISO 8601 format:
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
const { data, error } = await resend.emails.send({
|
|
283
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
284
|
+
to: ['user@example.com'],
|
|
285
|
+
subject: 'Scheduled Email',
|
|
286
|
+
html: '<p>This email was scheduled</p>',
|
|
287
|
+
scheduledAt: '2024-08-05T11:52:01.858Z',
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Email with React Components
|
|
292
|
+
|
|
293
|
+
The Node.js SDK supports React components for email templates:
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
import { Resend } from 'resend';
|
|
297
|
+
import { EmailTemplate } from './email-template';
|
|
298
|
+
|
|
299
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
300
|
+
|
|
301
|
+
const { data, error } = await resend.emails.send({
|
|
302
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
303
|
+
to: ['user@example.com'],
|
|
304
|
+
subject: 'Welcome',
|
|
305
|
+
react: EmailTemplate({ firstName: 'John' }),
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Example React email component:
|
|
310
|
+
|
|
311
|
+
```jsx
|
|
312
|
+
// email-template.jsx
|
|
313
|
+
import * as React from 'react';
|
|
314
|
+
|
|
315
|
+
export const EmailTemplate = ({ firstName }) => (
|
|
316
|
+
<div>
|
|
317
|
+
<h1>Welcome, {firstName}!</h1>
|
|
318
|
+
<p>Thanks for signing up.</p>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
With `@react-email/components`:
|
|
324
|
+
|
|
325
|
+
```jsx
|
|
326
|
+
import { Html, Button } from '@react-email/components';
|
|
327
|
+
|
|
328
|
+
export const EmailTemplate = ({ url }) => (
|
|
329
|
+
<Html>
|
|
330
|
+
<Button href={url}>Click me</Button>
|
|
331
|
+
</Html>
|
|
332
|
+
);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Idempotency
|
|
336
|
+
|
|
337
|
+
Use idempotency keys to prevent duplicate sends. Keys expire after 24 hours and must be max 256 characters:
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
const { data, error } = await resend.emails.send({
|
|
341
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
342
|
+
to: ['user@example.com'],
|
|
343
|
+
subject: 'Hello World',
|
|
344
|
+
html: '<p>This is idempotent</p>',
|
|
345
|
+
}, {
|
|
346
|
+
headers: {
|
|
347
|
+
'Idempotency-Key': 'unique-key-123456',
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Batch Emails
|
|
353
|
+
|
|
354
|
+
Send up to 100 emails in a single API call. Note that `attachments` and `scheduledAt` are not supported in batch mode.
|
|
355
|
+
|
|
356
|
+
### Basic Batch Send
|
|
357
|
+
|
|
358
|
+
```javascript
|
|
359
|
+
const { data, error } = await resend.batch.send([
|
|
360
|
+
{
|
|
361
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
362
|
+
to: ['user1@example.com'],
|
|
363
|
+
subject: 'Hello User 1',
|
|
364
|
+
html: '<p>Hello User 1</p>',
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
368
|
+
to: ['user2@example.com'],
|
|
369
|
+
subject: 'Hello User 2',
|
|
370
|
+
html: '<p>Hello User 2</p>',
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
374
|
+
to: ['user3@example.com'],
|
|
375
|
+
subject: 'Hello User 3',
|
|
376
|
+
html: '<p>Hello User 3</p>',
|
|
377
|
+
},
|
|
378
|
+
]);
|
|
379
|
+
|
|
380
|
+
console.log(data);
|
|
381
|
+
// [
|
|
382
|
+
// { id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' },
|
|
383
|
+
// { id: '5d3a4f2e-8f7b-4c1d-9a3e-2b6c1e8f9a0b' },
|
|
384
|
+
// { id: '7e9f1a3c-2d4b-5e6f-8a9c-3d4e5f6a7b8c' }
|
|
385
|
+
// ]
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Batch with Tags
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
const { data, error } = await resend.batch.send([
|
|
392
|
+
{
|
|
393
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
394
|
+
to: ['user1@example.com'],
|
|
395
|
+
subject: 'Hello',
|
|
396
|
+
html: '<p>Hello</p>',
|
|
397
|
+
tags: [{ name: 'category', value: 'welcome' }],
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
401
|
+
to: ['user2@example.com'],
|
|
402
|
+
subject: 'Hello',
|
|
403
|
+
html: '<p>Hello</p>',
|
|
404
|
+
tags: [{ name: 'category', value: 'welcome' }],
|
|
405
|
+
},
|
|
406
|
+
]);
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Permissive Validation Mode
|
|
410
|
+
|
|
411
|
+
By default, if any email in a batch is invalid, the entire batch fails. Use permissive mode to process valid emails and return errors for invalid ones:
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
const { data, error } = await resend.batch.send(
|
|
415
|
+
[
|
|
416
|
+
{
|
|
417
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
418
|
+
to: ['valid@example.com'],
|
|
419
|
+
subject: 'Valid Email',
|
|
420
|
+
html: '<p>This is valid</p>',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
from: 'invalid-email',
|
|
424
|
+
to: ['user@example.com'],
|
|
425
|
+
subject: 'Invalid Email',
|
|
426
|
+
html: '<p>This has invalid from address</p>',
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
{
|
|
430
|
+
headers: {
|
|
431
|
+
'X-Resend-Validation-Mode': 'permissive',
|
|
432
|
+
},
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
console.log(data);
|
|
437
|
+
// {
|
|
438
|
+
// data: [{ id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' }],
|
|
439
|
+
// errors: [{ message: 'Invalid from address', index: 1 }]
|
|
440
|
+
// }
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Managing Emails
|
|
444
|
+
|
|
445
|
+
### Retrieve Email by ID
|
|
446
|
+
|
|
447
|
+
Get details about a specific email:
|
|
448
|
+
|
|
449
|
+
```javascript
|
|
450
|
+
const { data, error } = await resend.emails.get(
|
|
451
|
+
'49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
console.log(data);
|
|
455
|
+
// {
|
|
456
|
+
// object: 'email',
|
|
457
|
+
// id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
|
|
458
|
+
// to: ['delivered@resend.dev'],
|
|
459
|
+
// from: 'Acme <onboarding@resend.dev>',
|
|
460
|
+
// created_at: '2023-04-03T22:13:42.674981+00:00',
|
|
461
|
+
// subject: 'Hello World',
|
|
462
|
+
// html: 'Congrats on sending your <strong>first email</strong>!',
|
|
463
|
+
// text: null,
|
|
464
|
+
// bcc: [],
|
|
465
|
+
// cc: [],
|
|
466
|
+
// reply_to: [],
|
|
467
|
+
// last_event: 'delivered',
|
|
468
|
+
// scheduled_at: null
|
|
469
|
+
// }
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Update Scheduled Email
|
|
473
|
+
|
|
474
|
+
Update the scheduled time for a scheduled email:
|
|
475
|
+
|
|
476
|
+
```javascript
|
|
477
|
+
const oneHourFromNow = new Date(Date.now() + 1000 * 60 * 60).toISOString();
|
|
478
|
+
|
|
479
|
+
const { data, error } = await resend.emails.update({
|
|
480
|
+
id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
|
|
481
|
+
scheduledAt: oneHourFromNow,
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
console.log(data);
|
|
485
|
+
// {
|
|
486
|
+
// object: 'email',
|
|
487
|
+
// id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
|
|
488
|
+
// }
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
With natural language:
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
const { data, error } = await resend.emails.update({
|
|
495
|
+
id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
|
|
496
|
+
scheduledAt: 'in 2 hours',
|
|
497
|
+
});
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Cancel Scheduled Email
|
|
501
|
+
|
|
502
|
+
Cancel a scheduled email that hasn't been sent yet:
|
|
503
|
+
|
|
504
|
+
```javascript
|
|
505
|
+
const { data, error } = await resend.emails.cancel(
|
|
506
|
+
'49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
console.log(data);
|
|
510
|
+
// {
|
|
511
|
+
// object: 'email',
|
|
512
|
+
// id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
|
|
513
|
+
// }
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Note: Once an email is canceled, it cannot be rescheduled.
|
|
517
|
+
|
|
518
|
+
## Audiences
|
|
519
|
+
|
|
520
|
+
Audiences allow you to group and manage contacts for broadcasting.
|
|
521
|
+
|
|
522
|
+
### Create Audience
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
const { data, error } = await resend.audiences.create({
|
|
526
|
+
name: 'Registered Users',
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
console.log(data);
|
|
530
|
+
// {
|
|
531
|
+
// object: 'audience',
|
|
532
|
+
// id: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
533
|
+
// name: 'Registered Users'
|
|
534
|
+
// }
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Retrieve Audience
|
|
538
|
+
|
|
539
|
+
```javascript
|
|
540
|
+
const { data, error } = await resend.audiences.get(
|
|
541
|
+
'78261eea-8f8b-4381-83c6-79fa7120f1cf'
|
|
542
|
+
);
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### List Audiences
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
const { data, error } = await resend.audiences.list();
|
|
549
|
+
|
|
550
|
+
console.log(data);
|
|
551
|
+
// {
|
|
552
|
+
// object: 'list',
|
|
553
|
+
// data: [
|
|
554
|
+
// {
|
|
555
|
+
// id: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
556
|
+
// name: 'Registered Users',
|
|
557
|
+
// created_at: '2023-10-06T23:47:56.678Z'
|
|
558
|
+
// }
|
|
559
|
+
// ]
|
|
560
|
+
// }
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Delete Audience
|
|
564
|
+
|
|
565
|
+
```javascript
|
|
566
|
+
const { data, error } = await resend.audiences.remove(
|
|
567
|
+
'78261eea-8f8b-4381-83c6-79fa7120f1cf'
|
|
568
|
+
);
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Contacts
|
|
572
|
+
|
|
573
|
+
Manage individual contacts within audiences.
|
|
574
|
+
|
|
575
|
+
### Create Contact
|
|
576
|
+
|
|
577
|
+
```javascript
|
|
578
|
+
const { data, error } = await resend.contacts.create({
|
|
579
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
580
|
+
email: 'user@example.com',
|
|
581
|
+
firstName: 'John',
|
|
582
|
+
lastName: 'Doe',
|
|
583
|
+
unsubscribed: false,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
console.log(data);
|
|
587
|
+
// {
|
|
588
|
+
// object: 'contact',
|
|
589
|
+
// id: '479e3145-dd38-476b-932c-529ceb705947'
|
|
590
|
+
// }
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Create Contact (Minimal)
|
|
594
|
+
|
|
595
|
+
```javascript
|
|
596
|
+
const { data, error } = await resend.contacts.create({
|
|
597
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
598
|
+
email: 'user@example.com',
|
|
599
|
+
});
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Retrieve Contact
|
|
603
|
+
|
|
604
|
+
```javascript
|
|
605
|
+
const { data, error } = await resend.contacts.get({
|
|
606
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
607
|
+
id: '479e3145-dd38-476b-932c-529ceb705947',
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### List Contacts
|
|
612
|
+
|
|
613
|
+
```javascript
|
|
614
|
+
const { data, error } = await resend.contacts.list({
|
|
615
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
console.log(data);
|
|
619
|
+
// {
|
|
620
|
+
// object: 'list',
|
|
621
|
+
// data: [
|
|
622
|
+
// {
|
|
623
|
+
// id: '479e3145-dd38-476b-932c-529ceb705947',
|
|
624
|
+
// email: 'user@example.com',
|
|
625
|
+
// first_name: 'John',
|
|
626
|
+
// last_name: 'Doe',
|
|
627
|
+
// created_at: '2023-10-06T23:47:56.678Z',
|
|
628
|
+
// unsubscribed: false
|
|
629
|
+
// }
|
|
630
|
+
// ]
|
|
631
|
+
// }
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Update Contact
|
|
635
|
+
|
|
636
|
+
```javascript
|
|
637
|
+
const { data, error } = await resend.contacts.update({
|
|
638
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
639
|
+
id: '479e3145-dd38-476b-932c-529ceb705947',
|
|
640
|
+
firstName: 'Jane',
|
|
641
|
+
unsubscribed: true,
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### Delete Contact
|
|
646
|
+
|
|
647
|
+
```javascript
|
|
648
|
+
const { data, error } = await resend.contacts.remove({
|
|
649
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
650
|
+
id: '479e3145-dd38-476b-932c-529ceb705947',
|
|
651
|
+
});
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
## Broadcasts
|
|
655
|
+
|
|
656
|
+
Broadcasts allow you to send emails to entire audiences.
|
|
657
|
+
|
|
658
|
+
### Create Broadcast
|
|
659
|
+
|
|
660
|
+
```javascript
|
|
661
|
+
const { data, error } = await resend.broadcasts.create({
|
|
662
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
663
|
+
from: 'Acme <newsletter@acme.com>',
|
|
664
|
+
subject: 'Monthly Newsletter',
|
|
665
|
+
html: 'Hi {{{FIRST_NAME|there}}}, you can unsubscribe here: {{{RESEND_UNSUBSCRIBE_URL}}}',
|
|
666
|
+
name: 'October Newsletter',
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
console.log(data);
|
|
670
|
+
// {
|
|
671
|
+
// id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
|
|
672
|
+
// }
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Create Broadcast with React
|
|
676
|
+
|
|
677
|
+
```javascript
|
|
678
|
+
import { NewsletterTemplate } from './newsletter-template';
|
|
679
|
+
|
|
680
|
+
const { data, error } = await resend.broadcasts.create({
|
|
681
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
682
|
+
from: 'Acme <newsletter@acme.com>',
|
|
683
|
+
subject: 'Monthly Newsletter',
|
|
684
|
+
react: NewsletterTemplate(),
|
|
685
|
+
});
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### Broadcast Template Variables
|
|
689
|
+
|
|
690
|
+
Use template variables in broadcasts:
|
|
691
|
+
|
|
692
|
+
- `{{{FIRST_NAME}}}` - Contact's first name
|
|
693
|
+
- `{{{LAST_NAME}}}` - Contact's last name
|
|
694
|
+
- `{{{EMAIL}}}` - Contact's email
|
|
695
|
+
- `{{{RESEND_UNSUBSCRIBE_URL}}}` - Unsubscribe URL
|
|
696
|
+
|
|
697
|
+
With fallback values:
|
|
698
|
+
|
|
699
|
+
```javascript
|
|
700
|
+
const { data, error } = await resend.broadcasts.create({
|
|
701
|
+
audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
702
|
+
from: 'Acme <newsletter@acme.com>',
|
|
703
|
+
subject: 'Hello {{{FIRST_NAME|Friend}}}',
|
|
704
|
+
html: '<p>Hi {{{FIRST_NAME|there}}},</p><p>Thanks for subscribing!</p>',
|
|
705
|
+
});
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
### Send Broadcast Immediately
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
const { data, error } = await resend.broadcasts.send(
|
|
712
|
+
'559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
console.log(data);
|
|
716
|
+
// {
|
|
717
|
+
// id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
|
|
718
|
+
// }
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### Send Broadcast with Scheduling
|
|
722
|
+
|
|
723
|
+
```javascript
|
|
724
|
+
const { data, error } = await resend.broadcasts.send(
|
|
725
|
+
'559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
|
|
726
|
+
{
|
|
727
|
+
scheduledAt: 'tomorrow at 9am',
|
|
728
|
+
}
|
|
729
|
+
);
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
```javascript
|
|
733
|
+
const { data, error } = await resend.broadcasts.send(
|
|
734
|
+
'559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
|
|
735
|
+
{
|
|
736
|
+
scheduledAt: '2024-08-05T11:52:01.858Z',
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### Retrieve Broadcast
|
|
742
|
+
|
|
743
|
+
```javascript
|
|
744
|
+
const { data, error } = await resend.broadcasts.get(
|
|
745
|
+
'559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
|
|
746
|
+
);
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### List Broadcasts
|
|
750
|
+
|
|
751
|
+
```javascript
|
|
752
|
+
const { data, error } = await resend.broadcasts.list();
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### Update Broadcast
|
|
756
|
+
|
|
757
|
+
```javascript
|
|
758
|
+
const { data, error } = await resend.broadcasts.update({
|
|
759
|
+
id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
|
|
760
|
+
subject: 'Updated Newsletter Subject',
|
|
761
|
+
html: '<p>Updated content</p>',
|
|
762
|
+
});
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### Delete Broadcast
|
|
766
|
+
|
|
767
|
+
```javascript
|
|
768
|
+
const { data, error } = await resend.broadcasts.remove(
|
|
769
|
+
'559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
|
|
770
|
+
);
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
## Domains
|
|
774
|
+
|
|
775
|
+
Manage domains for sending emails.
|
|
776
|
+
|
|
777
|
+
### Create Domain
|
|
778
|
+
|
|
779
|
+
```javascript
|
|
780
|
+
const { data, error } = await resend.domains.create({
|
|
781
|
+
name: 'example.com',
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
console.log(data);
|
|
785
|
+
// {
|
|
786
|
+
// id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
|
|
787
|
+
// name: 'example.com',
|
|
788
|
+
// status: 'not_started',
|
|
789
|
+
// records: [
|
|
790
|
+
// {
|
|
791
|
+
// record: 'SPF',
|
|
792
|
+
// name: 'example.com',
|
|
793
|
+
// type: 'TXT',
|
|
794
|
+
// value: 'v=spf1 include:_spf.resend.com ~all'
|
|
795
|
+
// },
|
|
796
|
+
// {
|
|
797
|
+
// record: 'DKIM',
|
|
798
|
+
// name: 'resend._domainkey.example.com',
|
|
799
|
+
// type: 'TXT',
|
|
800
|
+
// value: 'p=...'
|
|
801
|
+
// }
|
|
802
|
+
// ]
|
|
803
|
+
// }
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Retrieve Domain
|
|
807
|
+
|
|
808
|
+
```javascript
|
|
809
|
+
const { data, error } = await resend.domains.get(
|
|
810
|
+
'd91cd9bd-1176-453e-8fc1-35364d380206'
|
|
811
|
+
);
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
### List Domains
|
|
815
|
+
|
|
816
|
+
```javascript
|
|
817
|
+
const { data, error } = await resend.domains.list();
|
|
818
|
+
|
|
819
|
+
console.log(data);
|
|
820
|
+
// {
|
|
821
|
+
// object: 'list',
|
|
822
|
+
// data: [
|
|
823
|
+
// {
|
|
824
|
+
// id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
|
|
825
|
+
// name: 'example.com',
|
|
826
|
+
// status: 'verified',
|
|
827
|
+
// created_at: '2023-04-03T22:13:42.674981+00:00'
|
|
828
|
+
// }
|
|
829
|
+
// ]
|
|
830
|
+
// }
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Verify Domain
|
|
834
|
+
|
|
835
|
+
After adding DNS records, verify the domain:
|
|
836
|
+
|
|
837
|
+
```javascript
|
|
838
|
+
const { data, error } = await resend.domains.verify(
|
|
839
|
+
'd91cd9bd-1176-453e-8fc1-35364d380206'
|
|
840
|
+
);
|
|
841
|
+
|
|
842
|
+
console.log(data);
|
|
843
|
+
// {
|
|
844
|
+
// object: 'domain',
|
|
845
|
+
// id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
|
|
846
|
+
// status: 'verified'
|
|
847
|
+
// }
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
### Update Domain
|
|
851
|
+
|
|
852
|
+
```javascript
|
|
853
|
+
const { data, error } = await resend.domains.update({
|
|
854
|
+
id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
|
|
855
|
+
clickTracking: true,
|
|
856
|
+
openTracking: true,
|
|
857
|
+
});
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### Delete Domain
|
|
861
|
+
|
|
862
|
+
```javascript
|
|
863
|
+
const { data, error } = await resend.domains.remove(
|
|
864
|
+
'd91cd9bd-1176-453e-8fc1-35364d380206'
|
|
865
|
+
);
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
## API Keys
|
|
869
|
+
|
|
870
|
+
Manage API keys programmatically.
|
|
871
|
+
|
|
872
|
+
### Create API Key
|
|
873
|
+
|
|
874
|
+
```javascript
|
|
875
|
+
const { data, error } = await resend.apiKeys.create({
|
|
876
|
+
name: 'Production',
|
|
877
|
+
permission: 'full_access',
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
console.log(data);
|
|
881
|
+
// {
|
|
882
|
+
// id: 'b6d24b8e-af0b-4c3c-be0c-359bbd97381e',
|
|
883
|
+
// token: 're_xxxxxxxxx'
|
|
884
|
+
// }
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
Available permissions:
|
|
888
|
+
- `full_access` - Can create, delete, get, and update any resource
|
|
889
|
+
- `sending_access` - Can only send emails
|
|
890
|
+
|
|
891
|
+
Create sending-only API key:
|
|
892
|
+
|
|
893
|
+
```javascript
|
|
894
|
+
const { data, error } = await resend.apiKeys.create({
|
|
895
|
+
name: 'Sending Key',
|
|
896
|
+
permission: 'sending_access',
|
|
897
|
+
});
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
Restrict to specific domain:
|
|
901
|
+
|
|
902
|
+
```javascript
|
|
903
|
+
const { data, error } = await resend.apiKeys.create({
|
|
904
|
+
name: 'Domain-Specific Key',
|
|
905
|
+
permission: 'sending_access',
|
|
906
|
+
domainId: 'd91cd9bd-1176-453e-8fc1-35364d380206',
|
|
907
|
+
});
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
### List API Keys
|
|
911
|
+
|
|
912
|
+
```javascript
|
|
913
|
+
const { data, error } = await resend.apiKeys.list();
|
|
914
|
+
|
|
915
|
+
console.log(data);
|
|
916
|
+
// {
|
|
917
|
+
// object: 'list',
|
|
918
|
+
// has_more: false,
|
|
919
|
+
// data: [
|
|
920
|
+
// {
|
|
921
|
+
// id: '91f3200a-df72-4654-b0cd-f202395f5354',
|
|
922
|
+
// name: 'Production',
|
|
923
|
+
// created_at: '2023-04-08T00:11:13.110779+00:00'
|
|
924
|
+
// }
|
|
925
|
+
// ]
|
|
926
|
+
// }
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
### Delete API Key
|
|
930
|
+
|
|
931
|
+
```javascript
|
|
932
|
+
const { data, error } = await resend.apiKeys.remove(
|
|
933
|
+
'b6d24b8e-af0b-4c3c-be0c-359bbd97381e'
|
|
934
|
+
);
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
## Error Handling
|
|
938
|
+
|
|
939
|
+
All API methods return an object with `data` and `error` properties:
|
|
940
|
+
|
|
941
|
+
```javascript
|
|
942
|
+
const { data, error } = await resend.emails.send({
|
|
943
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
944
|
+
to: ['user@example.com'],
|
|
945
|
+
subject: 'Hello',
|
|
946
|
+
html: '<p>Hello</p>',
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
if (error) {
|
|
950
|
+
console.error('Failed to send email:', error);
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
console.log('Email sent successfully:', data.id);
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
Common error scenarios:
|
|
958
|
+
|
|
959
|
+
```javascript
|
|
960
|
+
// Missing required fields
|
|
961
|
+
const { data, error } = await resend.emails.send({
|
|
962
|
+
from: 'Acme <onboarding@resend.dev>',
|
|
963
|
+
to: ['user@example.com'],
|
|
964
|
+
// Missing subject
|
|
965
|
+
html: '<p>Hello</p>',
|
|
966
|
+
});
|
|
967
|
+
// error: { message: 'Missing required parameter: subject' }
|
|
968
|
+
|
|
969
|
+
// Invalid API key
|
|
970
|
+
const resend = new Resend('invalid_key');
|
|
971
|
+
const { data, error } = await resend.emails.send({...});
|
|
972
|
+
// error: { message: 'Invalid API key' }
|
|
973
|
+
|
|
974
|
+
// Unverified domain
|
|
975
|
+
const { data, error } = await resend.emails.send({
|
|
976
|
+
from: 'user@unverified-domain.com',
|
|
977
|
+
to: ['user@example.com'],
|
|
978
|
+
subject: 'Hello',
|
|
979
|
+
html: '<p>Hello</p>',
|
|
980
|
+
});
|
|
981
|
+
// error: { message: 'Domain not verified' }
|
|
982
|
+
|
|
983
|
+
// Rate limit exceeded
|
|
984
|
+
// error: { message: 'Rate limit exceeded' }
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
## Complete Examples
|
|
988
|
+
|
|
989
|
+
### Basic Email Sending
|
|
990
|
+
|
|
991
|
+
```javascript
|
|
992
|
+
import { Resend } from 'resend';
|
|
993
|
+
|
|
994
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
995
|
+
|
|
996
|
+
async function sendWelcomeEmail(userEmail, userName) {
|
|
997
|
+
const { data, error } = await resend.emails.send({
|
|
998
|
+
from: 'Acme <welcome@acme.com>',
|
|
999
|
+
to: [userEmail],
|
|
1000
|
+
subject: `Welcome to Acme, ${userName}!`,
|
|
1001
|
+
html: `
|
|
1002
|
+
<h1>Welcome, ${userName}!</h1>
|
|
1003
|
+
<p>Thanks for signing up. We're excited to have you on board.</p>
|
|
1004
|
+
<p>Get started by visiting your dashboard.</p>
|
|
1005
|
+
`,
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
if (error) {
|
|
1009
|
+
throw new Error(`Failed to send welcome email: ${error.message}`);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
return data.id;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Usage
|
|
1016
|
+
await sendWelcomeEmail('user@example.com', 'John Doe');
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
### Scheduled Email with Attachment
|
|
1020
|
+
|
|
1021
|
+
```javascript
|
|
1022
|
+
import { Resend } from 'resend';
|
|
1023
|
+
import fs from 'fs';
|
|
1024
|
+
|
|
1025
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
1026
|
+
|
|
1027
|
+
async function sendScheduledReport(recipient, reportPath, sendTime) {
|
|
1028
|
+
const { data, error } = await resend.emails.send({
|
|
1029
|
+
from: 'Reports <reports@acme.com>',
|
|
1030
|
+
to: [recipient],
|
|
1031
|
+
subject: 'Weekly Report',
|
|
1032
|
+
html: '<p>Your weekly report is attached.</p>',
|
|
1033
|
+
attachments: [
|
|
1034
|
+
{
|
|
1035
|
+
filename: 'weekly-report.pdf',
|
|
1036
|
+
content: fs.readFileSync(reportPath),
|
|
1037
|
+
contentType: 'application/pdf',
|
|
1038
|
+
},
|
|
1039
|
+
],
|
|
1040
|
+
scheduledAt: sendTime,
|
|
1041
|
+
tags: [
|
|
1042
|
+
{ name: 'type', value: 'report' },
|
|
1043
|
+
{ name: 'frequency', value: 'weekly' },
|
|
1044
|
+
],
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
if (error) {
|
|
1048
|
+
throw new Error(`Failed to schedule report: ${error.message}`);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
return data.id;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Usage
|
|
1055
|
+
await sendScheduledReport(
|
|
1056
|
+
'manager@example.com',
|
|
1057
|
+
'./reports/weekly.pdf',
|
|
1058
|
+
'Friday at 9am'
|
|
1059
|
+
);
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
### Newsletter Broadcast
|
|
1063
|
+
|
|
1064
|
+
```javascript
|
|
1065
|
+
import { Resend } from 'resend';
|
|
1066
|
+
|
|
1067
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
1068
|
+
|
|
1069
|
+
async function sendNewsletter(audienceId, content) {
|
|
1070
|
+
// Create broadcast
|
|
1071
|
+
const { data: broadcast, error: createError } = await resend.broadcasts.create({
|
|
1072
|
+
audienceId: audienceId,
|
|
1073
|
+
from: 'Newsletter <newsletter@acme.com>',
|
|
1074
|
+
subject: 'Monthly Update - October 2024',
|
|
1075
|
+
html: `
|
|
1076
|
+
<h1>Hi {{{FIRST_NAME|there}}}!</h1>
|
|
1077
|
+
${content}
|
|
1078
|
+
<p><a href="{{{RESEND_UNSUBSCRIBE_URL}}}">Unsubscribe</a></p>
|
|
1079
|
+
`,
|
|
1080
|
+
name: 'October 2024 Newsletter',
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
if (createError) {
|
|
1084
|
+
throw new Error(`Failed to create broadcast: ${createError.message}`);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Send immediately
|
|
1088
|
+
const { data: sent, error: sendError } = await resend.broadcasts.send(
|
|
1089
|
+
broadcast.id
|
|
1090
|
+
);
|
|
1091
|
+
|
|
1092
|
+
if (sendError) {
|
|
1093
|
+
throw new Error(`Failed to send broadcast: ${sendError.message}`);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
return sent.id;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// Usage
|
|
1100
|
+
await sendNewsletter(
|
|
1101
|
+
'78261eea-8f8b-4381-83c6-79fa7120f1cf',
|
|
1102
|
+
'<p>Here is what is new this month...</p>'
|
|
1103
|
+
);
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
### Batch Email with Error Handling
|
|
1107
|
+
|
|
1108
|
+
```javascript
|
|
1109
|
+
import { Resend } from 'resend';
|
|
1110
|
+
|
|
1111
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
1112
|
+
|
|
1113
|
+
async function sendBatchNotifications(users) {
|
|
1114
|
+
const emails = users.map(user => ({
|
|
1115
|
+
from: 'Notifications <notifications@acme.com>',
|
|
1116
|
+
to: [user.email],
|
|
1117
|
+
subject: 'Important Update',
|
|
1118
|
+
html: `<p>Hi ${user.name}, we have an important update for you.</p>`,
|
|
1119
|
+
tags: [{ name: 'user_id', value: user.id }],
|
|
1120
|
+
}));
|
|
1121
|
+
|
|
1122
|
+
const { data, error } = await resend.batch.send(emails, {
|
|
1123
|
+
headers: {
|
|
1124
|
+
'X-Resend-Validation-Mode': 'permissive',
|
|
1125
|
+
},
|
|
1126
|
+
});
|
|
1127
|
+
|
|
1128
|
+
if (error) {
|
|
1129
|
+
throw new Error(`Batch send failed: ${error.message}`);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// Handle partial failures
|
|
1133
|
+
if (data.errors && data.errors.length > 0) {
|
|
1134
|
+
console.warn('Some emails failed:', data.errors);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
return {
|
|
1138
|
+
successful: data.data.length,
|
|
1139
|
+
failed: data.errors?.length || 0,
|
|
1140
|
+
emailIds: data.data.map(d => d.id),
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// Usage
|
|
1145
|
+
const users = [
|
|
1146
|
+
{ id: '1', email: 'user1@example.com', name: 'User 1' },
|
|
1147
|
+
{ id: '2', email: 'user2@example.com', name: 'User 2' },
|
|
1148
|
+
{ id: '3', email: 'user3@example.com', name: 'User 3' },
|
|
1149
|
+
];
|
|
1150
|
+
|
|
1151
|
+
const result = await sendBatchNotifications(users);
|
|
1152
|
+
console.log(`Sent ${result.successful} emails, ${result.failed} failed`);
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
### Managing Audience and Contacts
|
|
1156
|
+
|
|
1157
|
+
```javascript
|
|
1158
|
+
import { Resend } from 'resend';
|
|
1159
|
+
|
|
1160
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
1161
|
+
|
|
1162
|
+
async function setupMarketingList(listName, contacts) {
|
|
1163
|
+
// Create audience
|
|
1164
|
+
const { data: audience, error: audienceError } = await resend.audiences.create({
|
|
1165
|
+
name: listName,
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
if (audienceError) {
|
|
1169
|
+
throw new Error(`Failed to create audience: ${audienceError.message}`);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
console.log(`Created audience: ${audience.id}`);
|
|
1173
|
+
|
|
1174
|
+
// Add contacts
|
|
1175
|
+
const results = [];
|
|
1176
|
+
for (const contact of contacts) {
|
|
1177
|
+
const { data, error } = await resend.contacts.create({
|
|
1178
|
+
audienceId: audience.id,
|
|
1179
|
+
email: contact.email,
|
|
1180
|
+
firstName: contact.firstName,
|
|
1181
|
+
lastName: contact.lastName,
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
if (error) {
|
|
1185
|
+
console.error(`Failed to add ${contact.email}:`, error.message);
|
|
1186
|
+
} else {
|
|
1187
|
+
results.push(data.id);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
return {
|
|
1192
|
+
audienceId: audience.id,
|
|
1193
|
+
contactsAdded: results.length,
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// Usage
|
|
1198
|
+
const contacts = [
|
|
1199
|
+
{ email: 'john@example.com', firstName: 'John', lastName: 'Doe' },
|
|
1200
|
+
{ email: 'jane@example.com', firstName: 'Jane', lastName: 'Smith' },
|
|
1201
|
+
];
|
|
1202
|
+
|
|
1203
|
+
const result = await setupMarketingList('Q4 Campaign', contacts);
|
|
1204
|
+
console.log(`Setup complete: ${result.contactsAdded} contacts added`);
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
### Cancel and Reschedule
|
|
1208
|
+
|
|
1209
|
+
```javascript
|
|
1210
|
+
import { Resend } from 'resend';
|
|
1211
|
+
|
|
1212
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
1213
|
+
|
|
1214
|
+
async function rescheduleEmail(emailId, newTime) {
|
|
1215
|
+
// Update scheduled time
|
|
1216
|
+
const { data, error } = await resend.emails.update({
|
|
1217
|
+
id: emailId,
|
|
1218
|
+
scheduledAt: newTime,
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
if (error) {
|
|
1222
|
+
throw new Error(`Failed to reschedule: ${error.message}`);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
return data.id;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
async function cancelScheduledEmail(emailId) {
|
|
1229
|
+
const { data, error } = await resend.emails.cancel(emailId);
|
|
1230
|
+
|
|
1231
|
+
if (error) {
|
|
1232
|
+
throw new Error(`Failed to cancel: ${error.message}`);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
return data.id;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// Usage
|
|
1239
|
+
const emailId = '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794';
|
|
1240
|
+
|
|
1241
|
+
// Reschedule for 2 hours later
|
|
1242
|
+
await rescheduleEmail(emailId, 'in 2 hours');
|
|
1243
|
+
|
|
1244
|
+
// Or cancel completely
|
|
1245
|
+
await cancelScheduledEmail(emailId);
|
|
1246
|
+
```
|
|
1247
|
+
|
|
1248
|
+
## TypeScript Support
|
|
1249
|
+
|
|
1250
|
+
The Resend SDK is written in TypeScript and includes full type definitions:
|
|
1251
|
+
|
|
1252
|
+
```typescript
|
|
1253
|
+
import { Resend } from 'resend';
|
|
1254
|
+
import type { CreateEmailOptions, CreateEmailResponse } from 'resend';
|
|
1255
|
+
|
|
1256
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
1257
|
+
|
|
1258
|
+
async function sendEmail(
|
|
1259
|
+
options: CreateEmailOptions
|
|
1260
|
+
): Promise<CreateEmailResponse> {
|
|
1261
|
+
const { data, error } = await resend.emails.send(options);
|
|
1262
|
+
|
|
1263
|
+
if (error) {
|
|
1264
|
+
throw error;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
return data;
|
|
1268
|
+
}
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
Type definitions for all API methods are included in the package.
|