resend-cli 2.5.0 → 2.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resend-cli",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "The official CLI for Resend",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -18,7 +18,7 @@
18
18
  "engines": {
19
19
  "node": ">=22"
20
20
  },
21
- "packageManager": "pnpm@11.2.2",
21
+ "packageManager": "pnpm@11.8.0",
22
22
  "files": [
23
23
  "dist/cli.cjs",
24
24
  "skills/"
@@ -43,7 +43,7 @@
43
43
  "@clack/prompts": "1.4.0",
44
44
  "@commander-js/extra-typings": "14.0.0",
45
45
  "commander": "14.0.3",
46
- "esbuild": "0.28.0",
46
+ "esbuild": "0.28.1",
47
47
  "esbuild-wasm": "0.28.0",
48
48
  "picocolors": "1.1.1",
49
49
  "resend": "6.14.0"
@@ -61,9 +61,9 @@
61
61
  "devDependencies": {
62
62
  "@biomejs/biome": "2.4.11",
63
63
  "@types/node": "24.12.4",
64
- "@yao-pkg/pkg": "6.19.0",
65
- "tsx": "4.22.3",
64
+ "@yao-pkg/pkg": "6.20.0",
65
+ "tsx": "4.22.4",
66
66
  "typescript": "5.9.3",
67
- "vitest": "4.1.7"
67
+ "vitest": "4.1.9"
68
68
  }
69
69
  }
@@ -11,6 +11,8 @@ description: >
11
11
  license: MIT
12
12
  metadata:
13
13
  author: resend
14
+ # Skill version is independent from the CLI/package.json version —
15
+ # bump it on skill content changes, not CLI releases.
14
16
  version: "2.3.0"
15
17
  homepage: https://resend.com/docs/cli-agents
16
18
  source: https://github.com/resend/resend-cli
@@ -145,7 +147,7 @@ Auth resolves: `--api-key` flag > `RESEND_API_KEY` env > config file (`resend lo
145
147
  | `automations` | create, get, list, update, delete, stop, open, runs |
146
148
  | `events` | create, get, list, update, delete, send, open |
147
149
  | `broadcasts` | create, send, update, delete, list |
148
- | `contacts` | create, update, delete, segments, topics |
150
+ | `contacts` | create, update, delete, segments, topics, imports |
149
151
  | `contact-properties` | create, update, delete, list |
150
152
  | `segments` | create, get, list, delete, contacts |
151
153
  | `templates` | create, publish, duplicate, delete, list |
@@ -170,6 +172,7 @@ Read the matching reference file for detailed flags and output shapes.
170
172
  | 6 | **Sending a dashboard-created broadcast via CLI** | Only API-created broadcasts can be sent with `broadcasts send` — dashboard broadcasts must be sent from the dashboard |
171
173
  | 7 | **Passing `--events` to `webhooks update` expecting additive behavior** | `--events` replaces the entire subscription list — always pass the complete set |
172
174
  | 8 | **Expecting `logs list` to include request/response bodies** | List returns summary fields only — use `logs get <id>` for full `request_body` and `response_body` |
175
+ | 9 | **CSV import fails with `create_error` ("missing required email column")** | `contacts imports create` matches columns case-sensitively by lowercase names (`email`, `first_name`, `last_name`) — use `--column-map` for headers like `Email`/`First Name` |
173
176
 
174
177
  ## Common Patterns
175
178
 
@@ -98,3 +98,44 @@ List contact's topic subscriptions.
98
98
  | `--topics <json>` | string | Yes (non-interactive) | JSON array: `[{"id":"topic-uuid","subscription":"opt_in"}]` |
99
99
 
100
100
  Subscription values: `opt_in` | `opt_out`
101
+
102
+ ---
103
+
104
+ ## contacts imports create
105
+
106
+ Bulk-import contacts from a local CSV file. The file is uploaded as multipart form data (max 100MB). Imports run **asynchronously** — the command returns an import id immediately while the file is processed in the background (poll with `contacts imports get`).
107
+
108
+ | Flag | Type | Required | Description |
109
+ |------|------|----------|-------------|
110
+ | `--file <path>` | string | Yes (non-interactive) | Path to the CSV file to import |
111
+ | `--column-map <json>` | string | No | JSON object mapping contact fields to CSV column headers: `{"email":"Email","firstName":"First Name","properties":{"plan":{"column":"Plan","type":"string"}}}` |
112
+ | `--on-conflict <strategy>` | string | No | How to handle existing contacts: `upsert` (default, updates) or `skip` |
113
+ | `--segment-id <id...>` | string[] | No | Add imported contacts to segment(s) — repeatable |
114
+ | `--topics <json>` | string | No | JSON array: `[{"id":"topic-uuid","subscription":"opt_in"}]` |
115
+
116
+ Mappable contact fields: `email`, `firstName`, `lastName`, `unsubscribed`, `properties`.
117
+
118
+ Without `--column-map`, columns are matched by the lowercase names `email` (required), `first_name`, `last_name` — matching is **case-sensitive**, so a CSV with `Email`/`First Name` headers fails with `create_error` (422 "missing required email column"). Use `--column-map` to import such a file.
119
+
120
+ ---
121
+
122
+ ## contacts imports get
123
+
124
+ Retrieve a contact import's status and counts.
125
+
126
+ **Argument:** `[id]` — Contact import ID (interactive picker when omitted)
127
+
128
+ Status values: `queued` | `in_progress` | `completed` | `failed`
129
+
130
+ ---
131
+
132
+ ## contacts imports list
133
+
134
+ | Flag | Type | Default | Description |
135
+ |------|------|---------|-------------|
136
+ | `--limit <n>` | number | 10 | Max results (1-100) |
137
+ | `--after <cursor>` | string | — | Forward pagination |
138
+ | `--before <cursor>` | string | — | Backward pagination |
139
+ | `--status <status>` | string | — | Filter by status: `queued` \| `in_progress` \| `completed` \| `failed` |
140
+
141
+ **Alias:** `ls`
@@ -22,9 +22,18 @@ All errors exit with code `1` and output JSON to **stderr**:
22
22
  | `missing_body` | None of `--text`, `--html`, `--html-file`, or `--react-email` provided | Provide at least one body flag |
23
23
  | `react_email_build_error` | Failed to bundle a React Email `.tsx` template with esbuild | Check the template compiles; ensure `react` and one of `react-email` (6.0+), `@react-email/components` (5.x), or `@react-email/render` are installed in the project |
24
24
  | `react_email_render_error` | Bundled template failed during `render()` | Check the component exports a default function and renders valid React Email markup |
25
- | `file_read_error` | Could not read file from `--html-file` path | Check file path exists and is readable |
25
+ | `file_read_error` | Could not read file from a `--file`/`--html-file`/`--text-file` path | Check file path exists and is readable |
26
26
  | `send_error` | Resend API rejected the send request | Check from address is on a verified domain; check recipient is valid |
27
27
 
28
+ ## Contact Import Errors
29
+
30
+ | Code | Cause | Resolution |
31
+ |------|-------|------------|
32
+ | `missing_file` | `contacts imports create` called non-interactively without `--file` | Pass `--file <path>` to the CSV to import |
33
+ | `invalid_column_map` | `--column-map` is not valid JSON, or is not an object | Pass a JSON object mapping contact fields to CSV headers, e.g. `{"email":"Email"}` |
34
+ | `invalid_topics` | `--topics` is not valid JSON, or is not an array | Pass a JSON array of `{id, subscription}` objects |
35
+ | `create_error` | Resend API rejected the import (e.g. CSV missing the required `email` column, or file over 100MB) | Ensure the CSV has an `email` column (or map it with `--column-map`) and is under 100MB |
36
+
28
37
  ## Domain Errors
29
38
 
30
39
  | Code | Cause | Resolution |
@@ -414,3 +414,40 @@ resend emails receiving listen --interval 10
414
414
  # Stream as NDJSON (for scripting)
415
415
  resend emails receiving listen --json | head -3
416
416
  ```
417
+
418
+ ---
419
+
420
+ ## 13. Bulk Import Contacts from CSV
421
+
422
+ ```bash
423
+ # 1. Prepare a CSV. Without --column-map, columns are matched by the lowercase
424
+ # names email (required), first_name, last_name — matching is CASE-SENSITIVE,
425
+ # so headers like "Email" or "First Name" will NOT match (import fails with a
426
+ # 422 "missing required email column"). Map those with --column-map instead.
427
+ cat > contacts.csv << 'EOF'
428
+ email,first_name,last_name
429
+ ada@example.com,Ada,Lovelace
430
+ alan@example.com,Alan,Turing
431
+ EOF
432
+
433
+ # 2. Start the import (returns an import id immediately; runs async)
434
+ resend contacts imports create --file ./contacts.csv
435
+
436
+ # If your CSV uses different header names, map them with --column-map.
437
+ # You can also set a conflict strategy and add contacts to a segment:
438
+ cat > contacts-custom.csv << 'EOF'
439
+ Email,First Name,Last Name
440
+ ada@example.com,Ada,Lovelace
441
+ EOF
442
+ resend contacts imports create \
443
+ --file ./contacts-custom.csv \
444
+ --column-map '{"email":"Email","firstName":"First Name","lastName":"Last Name"}' \
445
+ --on-conflict upsert \
446
+ --segment-id <segment-id>
447
+
448
+ # 3. Poll status until "completed" (or "failed")
449
+ resend contacts imports get <import-id>
450
+
451
+ # 4. Review past imports (filter by status)
452
+ resend contacts imports list --status completed
453
+ ```