@sesender/cli 1.0.0 → 1.0.1
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/bin/ses-cli.mjs +177 -31
- package/package.json +5 -3
- package/src/commands/account.mjs +48 -0
- package/src/commands/campaigns.mjs +139 -23
- package/src/commands/contacts.mjs +96 -18
- package/src/commands/email.mjs +113 -39
- package/src/commands/providers.mjs +50 -0
- package/src/commands/schedule.mjs +52 -0
- package/src/commands/seedcheck.mjs +97 -0
- package/src/commands/sms.mjs +94 -32
- package/src/commands/templates.mjs +57 -0
- package/src/commands/tracking.mjs +61 -0
- package/src/commands/validate.mjs +112 -16
- package/src/commands/webhooks.mjs +103 -0
package/bin/ses-cli.mjs
CHANGED
|
@@ -3,11 +3,18 @@
|
|
|
3
3
|
import { configSet, configShow, configClear } from "../src/commands/config.mjs";
|
|
4
4
|
import { smsSend, smsBulk, smsHistory } from "../src/commands/sms.mjs";
|
|
5
5
|
import { emailSend, emailBulk, emailHistory } from "../src/commands/email.mjs";
|
|
6
|
-
import { contactsList, contactsImport, contactsGroups } from "../src/commands/contacts.mjs";
|
|
7
|
-
import { campaignsList, analyticsOverview } from "../src/commands/campaigns.mjs";
|
|
8
|
-
import { validatePhone, validateEmail } from "../src/commands/validate.mjs";
|
|
6
|
+
import { contactsList, contactsImport, contactsGroups, contactsExport, contactsDelete } from "../src/commands/contacts.mjs";
|
|
7
|
+
import { campaignsList, campaignsStats, campaignsPause, campaignsResume, campaignsCancel, analyticsOverview } from "../src/commands/campaigns.mjs";
|
|
8
|
+
import { validatePhone, validateEmail, validateBulk } from "../src/commands/validate.mjs";
|
|
9
|
+
import { providersList } from "../src/commands/providers.mjs";
|
|
10
|
+
import { webhooksList, webhooksCreate, webhooksDelete, webhooksTest } from "../src/commands/webhooks.mjs";
|
|
11
|
+
import { seedCheck, seedBalance } from "../src/commands/seedcheck.mjs";
|
|
12
|
+
import { templatesList, templatesGet } from "../src/commands/templates.mjs";
|
|
13
|
+
import { accountInfo, accountRateLimit } from "../src/commands/account.mjs";
|
|
14
|
+
import { trackingDomainsList, trackingStats } from "../src/commands/tracking.mjs";
|
|
15
|
+
import { scheduleList, scheduleCancel } from "../src/commands/schedule.mjs";
|
|
9
16
|
|
|
10
|
-
const VERSION = "1.0.
|
|
17
|
+
const VERSION = "1.0.1";
|
|
11
18
|
|
|
12
19
|
function parseArgs(argv) {
|
|
13
20
|
const args = { _positional: [] };
|
|
@@ -33,55 +40,114 @@ function parseArgs(argv) {
|
|
|
33
40
|
function showHelp() {
|
|
34
41
|
console.log(`
|
|
35
42
|
SESender CLI v${VERSION}
|
|
36
|
-
|
|
43
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
37
44
|
|
|
38
45
|
USAGE
|
|
39
46
|
ses-cli <command> <subcommand> [options]
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
config set
|
|
43
|
-
config show
|
|
44
|
-
config clear
|
|
48
|
+
CONFIGURATION
|
|
49
|
+
config set Configure API key and base URL
|
|
50
|
+
config show Show current configuration
|
|
51
|
+
config clear Remove saved configuration
|
|
52
|
+
|
|
53
|
+
MESSAGING
|
|
54
|
+
sms send Send a single SMS
|
|
55
|
+
sms bulk Send bulk SMS from CSV file
|
|
56
|
+
sms history View SMS message history
|
|
45
57
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
email send Send a single email
|
|
59
|
+
email bulk Send bulk emails from CSV file
|
|
60
|
+
email history View email message history
|
|
49
61
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
CAMPAIGNS
|
|
63
|
+
campaigns list List campaigns with stats
|
|
64
|
+
campaigns stats View detailed campaign statistics
|
|
65
|
+
campaigns pause Pause a running campaign
|
|
66
|
+
campaigns resume Resume a paused campaign
|
|
67
|
+
campaigns cancel Cancel a campaign permanently
|
|
53
68
|
|
|
54
|
-
|
|
69
|
+
CONTACTS
|
|
70
|
+
contacts list List contacts (with search/filter)
|
|
55
71
|
contacts import Import contacts from CSV
|
|
56
72
|
contacts groups List contact groups
|
|
73
|
+
contacts export Export contacts to CSV
|
|
74
|
+
contacts delete Delete a contact
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
PROVIDERS
|
|
77
|
+
providers list List available SMS/email providers
|
|
78
|
+
|
|
79
|
+
TEMPLATES
|
|
80
|
+
templates list List saved templates
|
|
81
|
+
templates get View a specific template
|
|
82
|
+
|
|
83
|
+
WEBHOOKS
|
|
84
|
+
webhooks list List configured webhooks
|
|
85
|
+
webhooks create Create a new webhook
|
|
86
|
+
webhooks delete Delete a webhook
|
|
87
|
+
webhooks test Send a test event to a webhook
|
|
60
88
|
|
|
89
|
+
TRACKING
|
|
90
|
+
tracking list List tracking domains
|
|
91
|
+
tracking stats View tracking/click statistics
|
|
92
|
+
|
|
93
|
+
SCHEDULING
|
|
94
|
+
schedule list List scheduled messages
|
|
95
|
+
schedule cancel Cancel a scheduled message
|
|
96
|
+
|
|
97
|
+
VALIDATION
|
|
61
98
|
validate phone Validate a phone number
|
|
62
99
|
validate email Validate an email address
|
|
100
|
+
validate bulk Bulk validate from file
|
|
101
|
+
|
|
102
|
+
SEED CHECK
|
|
103
|
+
seed-check Check emails against seed database
|
|
104
|
+
seed-balance Check seed check credit balance
|
|
105
|
+
|
|
106
|
+
ANALYTICS
|
|
107
|
+
analytics View analytics overview
|
|
108
|
+
|
|
109
|
+
ACCOUNT
|
|
110
|
+
account info View account information
|
|
111
|
+
account rate View API rate limit status
|
|
63
112
|
|
|
64
113
|
GLOBAL OPTIONS
|
|
65
|
-
--json
|
|
66
|
-
--help
|
|
67
|
-
--version
|
|
114
|
+
--json Output in JSON format (machine-readable)
|
|
115
|
+
--help Show this help message
|
|
116
|
+
--version Show version number
|
|
117
|
+
|
|
118
|
+
FLAGS (for sms/email send)
|
|
119
|
+
--provider Choose specific provider (e.g., ses, mailgun, twilio)
|
|
120
|
+
--route Routing mode (e.g., priority, round-robin)
|
|
121
|
+
--schedule Schedule send time (ISO 8601 format)
|
|
122
|
+
--timezone Timezone for scheduling (e.g., America/New_York)
|
|
123
|
+
--track-clicks Enable click tracking
|
|
124
|
+
--track-opens Enable open tracking
|
|
68
125
|
|
|
69
126
|
EXAMPLES
|
|
70
127
|
ses-cli config set --api-key sk_live_abc123 --base-url https://sesender.com
|
|
71
|
-
ses-cli sms send --to +1234567890 --body "Hello
|
|
72
|
-
ses-cli email send --to user@example.com --subject "Test" --
|
|
73
|
-
ses-cli sms bulk --file numbers.csv --body "Promo: 20% off!"
|
|
128
|
+
ses-cli sms send --to +1234567890 --body "Hello!" --provider twilio
|
|
129
|
+
ses-cli email send --to user@example.com --subject "Test" --html "<h1>Hi</h1>"
|
|
130
|
+
ses-cli sms bulk --file numbers.csv --body "Promo: 20% off!" --provider ses
|
|
131
|
+
ses-cli campaigns list --status sending --type email
|
|
132
|
+
ses-cli campaigns stats --id c-abc123
|
|
133
|
+
ses-cli campaigns pause --id c-abc123
|
|
74
134
|
ses-cli contacts import --file contacts.csv --group "Newsletter"
|
|
135
|
+
ses-cli contacts list --search "gmail" --limit 50
|
|
136
|
+
ses-cli webhooks create --url https://myapp.com/hook --events "email.delivered,sms.sent"
|
|
75
137
|
ses-cli validate phone +1234567890
|
|
76
|
-
ses-cli
|
|
138
|
+
ses-cli validate bulk --file emails.csv --type email
|
|
139
|
+
ses-cli seed-check --emails "user@test.com" --words "trap,seed"
|
|
140
|
+
ses-cli analytics --period 30d --json
|
|
141
|
+
ses-cli schedule list --status pending
|
|
77
142
|
|
|
78
143
|
ENVIRONMENT VARIABLES
|
|
79
|
-
SES_API_KEY
|
|
80
|
-
SES_BASE_URL
|
|
144
|
+
SES_API_KEY API key (overrides config file)
|
|
145
|
+
SES_BASE_URL Base URL (overrides config file)
|
|
81
146
|
|
|
82
147
|
CONFIGURATION
|
|
83
148
|
Config file: ~/.sesenderrc
|
|
84
149
|
Create API keys at: Settings > API Keys in your SESender dashboard
|
|
150
|
+
Docs: https://sesender.com/api-docs
|
|
85
151
|
`);
|
|
86
152
|
}
|
|
87
153
|
|
|
@@ -144,8 +210,10 @@ async function main() {
|
|
|
144
210
|
case "list": await contactsList(args, jsonMode); break;
|
|
145
211
|
case "import": await contactsImport(args, jsonMode); break;
|
|
146
212
|
case "groups": await contactsGroups(args, jsonMode); break;
|
|
213
|
+
case "export": await contactsExport(args, jsonMode); break;
|
|
214
|
+
case "delete": await contactsDelete(args, jsonMode); break;
|
|
147
215
|
default:
|
|
148
|
-
console.error("Usage: ses-cli contacts <list|import|groups>");
|
|
216
|
+
console.error("Usage: ses-cli contacts <list|import|groups|export|delete>");
|
|
149
217
|
process.exit(1);
|
|
150
218
|
}
|
|
151
219
|
break;
|
|
@@ -153,8 +221,12 @@ async function main() {
|
|
|
153
221
|
case "campaigns":
|
|
154
222
|
switch (subcommand) {
|
|
155
223
|
case "list": await campaignsList(args, jsonMode); break;
|
|
224
|
+
case "stats": await campaignsStats(args, jsonMode); break;
|
|
225
|
+
case "pause": await campaignsPause(args, jsonMode); break;
|
|
226
|
+
case "resume": await campaignsResume(args, jsonMode); break;
|
|
227
|
+
case "cancel": await campaignsCancel(args, jsonMode); break;
|
|
156
228
|
default:
|
|
157
|
-
console.error("Usage: ses-cli campaigns <list>");
|
|
229
|
+
console.error("Usage: ses-cli campaigns <list|stats|pause|resume|cancel>");
|
|
158
230
|
process.exit(1);
|
|
159
231
|
}
|
|
160
232
|
break;
|
|
@@ -163,12 +235,82 @@ async function main() {
|
|
|
163
235
|
await analyticsOverview(args, jsonMode);
|
|
164
236
|
break;
|
|
165
237
|
|
|
238
|
+
case "providers":
|
|
239
|
+
switch (subcommand) {
|
|
240
|
+
case "list": await providersList(args, jsonMode); break;
|
|
241
|
+
default:
|
|
242
|
+
console.error("Usage: ses-cli providers <list>");
|
|
243
|
+
process.exit(1);
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
|
|
247
|
+
case "templates":
|
|
248
|
+
switch (subcommand) {
|
|
249
|
+
case "list": await templatesList(args, jsonMode); break;
|
|
250
|
+
case "get": await templatesGet(args, jsonMode); break;
|
|
251
|
+
default:
|
|
252
|
+
console.error("Usage: ses-cli templates <list|get>");
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
|
|
257
|
+
case "webhooks":
|
|
258
|
+
switch (subcommand) {
|
|
259
|
+
case "list": await webhooksList(args, jsonMode); break;
|
|
260
|
+
case "create": await webhooksCreate(args, jsonMode); break;
|
|
261
|
+
case "delete": await webhooksDelete(args, jsonMode); break;
|
|
262
|
+
case "test": await webhooksTest(args, jsonMode); break;
|
|
263
|
+
default:
|
|
264
|
+
console.error("Usage: ses-cli webhooks <list|create|delete|test>");
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
|
|
269
|
+
case "tracking":
|
|
270
|
+
switch (subcommand) {
|
|
271
|
+
case "list": await trackingDomainsList(args, jsonMode); break;
|
|
272
|
+
case "stats": await trackingStats(args, jsonMode); break;
|
|
273
|
+
default:
|
|
274
|
+
console.error("Usage: ses-cli tracking <list|stats>");
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
break;
|
|
278
|
+
|
|
279
|
+
case "schedule":
|
|
280
|
+
switch (subcommand) {
|
|
281
|
+
case "list": await scheduleList(args, jsonMode); break;
|
|
282
|
+
case "cancel": await scheduleCancel(args, jsonMode); break;
|
|
283
|
+
default:
|
|
284
|
+
console.error("Usage: ses-cli schedule <list|cancel>");
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
|
|
166
289
|
case "validate":
|
|
167
290
|
switch (subcommand) {
|
|
168
291
|
case "phone": await validatePhone(args, jsonMode); break;
|
|
169
292
|
case "email": await validateEmail(args, jsonMode); break;
|
|
293
|
+
case "bulk": await validateBulk(args, jsonMode); break;
|
|
294
|
+
default:
|
|
295
|
+
console.error("Usage: ses-cli validate <phone|email|bulk>");
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
break;
|
|
299
|
+
|
|
300
|
+
case "seed-check":
|
|
301
|
+
await seedCheck(args, jsonMode);
|
|
302
|
+
break;
|
|
303
|
+
|
|
304
|
+
case "seed-balance":
|
|
305
|
+
await seedBalance(args, jsonMode);
|
|
306
|
+
break;
|
|
307
|
+
|
|
308
|
+
case "account":
|
|
309
|
+
switch (subcommand) {
|
|
310
|
+
case "info": await accountInfo(args, jsonMode); break;
|
|
311
|
+
case "rate": await accountRateLimit(args, jsonMode); break;
|
|
170
312
|
default:
|
|
171
|
-
console.error("Usage: ses-cli
|
|
313
|
+
console.error("Usage: ses-cli account <info|rate>");
|
|
172
314
|
process.exit(1);
|
|
173
315
|
}
|
|
174
316
|
break;
|
|
@@ -180,7 +322,11 @@ async function main() {
|
|
|
180
322
|
}
|
|
181
323
|
} catch (error) {
|
|
182
324
|
if (error.message !== "process.exit") {
|
|
183
|
-
|
|
325
|
+
if (jsonMode) {
|
|
326
|
+
console.log(JSON.stringify({ error: error.message }, null, 2));
|
|
327
|
+
} else {
|
|
328
|
+
console.error(`Error: ${error.message}`);
|
|
329
|
+
}
|
|
184
330
|
process.exit(1);
|
|
185
331
|
}
|
|
186
332
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sesender/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "SESender CLI - Send SMS/emails, manage contacts, and view analytics from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"ses-cli": "
|
|
7
|
+
"ses-cli": "bin/ses-cli.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/ilan7251/ses-messaging-platform.git",
|
|
20
|
+
"directory": "cli"
|
|
20
21
|
},
|
|
21
22
|
"engines": {
|
|
22
23
|
"node": ">=18.0.0"
|
|
23
24
|
},
|
|
25
|
+
"homepage": "https://sesender.com/api-docs",
|
|
24
26
|
"dependencies": {}
|
|
25
27
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { apiRequest } from "../api.mjs";
|
|
2
|
+
import { outputResult, success } from "../output.mjs";
|
|
3
|
+
|
|
4
|
+
export async function accountInfo(args, jsonMode) {
|
|
5
|
+
const result = await apiRequest("GET", "/account");
|
|
6
|
+
|
|
7
|
+
if (jsonMode) {
|
|
8
|
+
outputResult(result, true);
|
|
9
|
+
} else {
|
|
10
|
+
const data = result.data || result;
|
|
11
|
+
console.log(`\n Account Information`);
|
|
12
|
+
console.log(` ─────────────────────────`);
|
|
13
|
+
console.log(` Name: ${data.name || "N/A"}`);
|
|
14
|
+
console.log(` Email: ${data.email || "N/A"}`);
|
|
15
|
+
console.log(` User ID: ${data.id || "N/A"}`);
|
|
16
|
+
if (data.apiKey) {
|
|
17
|
+
console.log(`\n API Key Details`);
|
|
18
|
+
console.log(` ─────────────────────────`);
|
|
19
|
+
console.log(` Plan: ${data.apiKey.plan || "N/A"}`);
|
|
20
|
+
console.log(` Rate Limit: ${data.apiKey.rateLimit || "N/A"} req/hour`);
|
|
21
|
+
console.log(` Used: ${data.apiKey.requestsThisHour || 0} this hour`);
|
|
22
|
+
console.log(` Permissions: ${(data.apiKey.permissions || []).join(", ")}`);
|
|
23
|
+
}
|
|
24
|
+
console.log("");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function accountRateLimit(args, jsonMode) {
|
|
29
|
+
const result = await apiRequest("GET", "/rate-limit");
|
|
30
|
+
|
|
31
|
+
if (jsonMode) {
|
|
32
|
+
outputResult(result, true);
|
|
33
|
+
} else {
|
|
34
|
+
const data = result.data || result;
|
|
35
|
+
const pct = data.limit > 0 ? Math.round((data.used / data.limit) * 100) : 0;
|
|
36
|
+
const bar = "█".repeat(Math.round(pct / 5)) + "░".repeat(20 - Math.round(pct / 5));
|
|
37
|
+
|
|
38
|
+
console.log(`\n Rate Limit Status`);
|
|
39
|
+
console.log(` ─────────────────────────`);
|
|
40
|
+
console.log(` Plan: ${data.plan || "N/A"}`);
|
|
41
|
+
console.log(` Limit: ${data.limit} requests/hour`);
|
|
42
|
+
console.log(` Used: ${data.used}`);
|
|
43
|
+
console.log(` Remaining: ${data.remaining}`);
|
|
44
|
+
console.log(` Usage: [${bar}] ${pct}%`);
|
|
45
|
+
if (data.resetAt) console.log(` Resets at: ${new Date(data.resetAt).toLocaleString()}`);
|
|
46
|
+
console.log("");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,69 +1,185 @@
|
|
|
1
1
|
import { apiRequest } from "../api.mjs";
|
|
2
|
-
import { formatTable, outputResult, success } from "../output.mjs";
|
|
2
|
+
import { formatTable, outputResult, success, info } from "../output.mjs";
|
|
3
3
|
|
|
4
4
|
export async function campaignsList(args, jsonMode) {
|
|
5
5
|
const limit = args["--limit"] || "20";
|
|
6
|
-
const
|
|
6
|
+
const page = args["--page"] || "1";
|
|
7
|
+
const status = args["--status"];
|
|
8
|
+
const type = args["--type"];
|
|
9
|
+
|
|
10
|
+
const params = { limit, page };
|
|
11
|
+
if (status) params.status = status;
|
|
12
|
+
if (type) params.type = type;
|
|
13
|
+
|
|
14
|
+
const result = await apiRequest("GET", "/analytics/campaigns", null, params);
|
|
7
15
|
|
|
8
16
|
if (jsonMode) {
|
|
9
17
|
outputResult(result, true);
|
|
10
18
|
} else {
|
|
11
|
-
const campaigns = result.campaigns || result.data || [];
|
|
19
|
+
const campaigns = result.data?.campaigns || result.campaigns || result.data || [];
|
|
12
20
|
if (campaigns.length === 0) {
|
|
13
21
|
console.log("No campaigns found.");
|
|
14
22
|
return;
|
|
15
23
|
}
|
|
16
24
|
formatTable(
|
|
17
|
-
["ID", "Name", "Type", "Status", "Sent", "Opens", "Clicks"],
|
|
25
|
+
["ID", "Name", "Type", "Status", "Sent", "Opens", "Clicks", "Date"],
|
|
18
26
|
campaigns.map((c) => [
|
|
19
27
|
c.id || c.campaignId,
|
|
20
|
-
(c.name || c.campaignName || "").slice(0,
|
|
28
|
+
(c.name || c.campaignName || c.subject || "").slice(0, 20),
|
|
21
29
|
c.type || "email",
|
|
22
30
|
c.status || "-",
|
|
23
31
|
c.sent || c.totalSent || 0,
|
|
24
32
|
c.opens || c.totalOpens || 0,
|
|
25
33
|
c.clicks || c.totalClicks || 0,
|
|
34
|
+
c.createdAt ? new Date(c.createdAt).toLocaleDateString() : "-",
|
|
26
35
|
])
|
|
27
36
|
);
|
|
28
|
-
console.log(`\nShowing ${campaigns.length} campaigns`);
|
|
37
|
+
console.log(`\nShowing ${campaigns.length} campaigns (page ${page})`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function campaignsStats(args, jsonMode) {
|
|
42
|
+
const id = args["--id"];
|
|
43
|
+
|
|
44
|
+
if (!id) {
|
|
45
|
+
console.error(`
|
|
46
|
+
Usage: ses-cli campaigns stats --id CAMPAIGN_ID
|
|
47
|
+
|
|
48
|
+
Shows detailed statistics for a specific campaign including:
|
|
49
|
+
- Delivery rates, open rates, click rates
|
|
50
|
+
- Bounce and complaint rates
|
|
51
|
+
- Per-link click breakdown
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
ses-cli campaigns stats --id c-abc123
|
|
55
|
+
ses-cli campaigns stats --id mv-campaign-456 --json
|
|
56
|
+
`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const result = await apiRequest("GET", `/analytics/campaigns/${id}`);
|
|
61
|
+
|
|
62
|
+
if (jsonMode) {
|
|
63
|
+
outputResult(result, true);
|
|
64
|
+
} else {
|
|
65
|
+
const data = result.data || result;
|
|
66
|
+
console.log(`\n Campaign Statistics: ${data.name || id}`);
|
|
67
|
+
console.log(` ─────────────────────────────────`);
|
|
68
|
+
console.log(` Status: ${data.status || "N/A"}`);
|
|
69
|
+
console.log(` Total Sent: ${data.totalSent || data.sent || 0}`);
|
|
70
|
+
console.log(` Delivered: ${data.delivered || 0} (${data.deliveryRate || "N/A"}%)`);
|
|
71
|
+
console.log(` Opens: ${data.opens || data.totalOpens || 0} (${data.openRate || "N/A"}%)`);
|
|
72
|
+
console.log(` Clicks: ${data.clicks || data.totalClicks || 0} (${data.clickRate || "N/A"}%)`);
|
|
73
|
+
console.log(` Bounces: ${data.bounces || 0} (${data.bounceRate || "N/A"}%)`);
|
|
74
|
+
console.log(` Complaints: ${data.complaints || 0}`);
|
|
75
|
+
console.log(` Unsubs: ${data.unsubscribes || 0}`);
|
|
76
|
+
console.log("");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function campaignsPause(args, jsonMode) {
|
|
81
|
+
const id = args["--id"];
|
|
82
|
+
|
|
83
|
+
if (!id) {
|
|
84
|
+
console.error(`
|
|
85
|
+
Usage: ses-cli campaigns pause --id CAMPAIGN_ID
|
|
86
|
+
|
|
87
|
+
Pauses a running campaign. Messages already in queue will still be sent.
|
|
88
|
+
Resume with: ses-cli campaigns resume --id CAMPAIGN_ID
|
|
89
|
+
`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const result = await apiRequest("POST", `/campaigns/${id}/pause`);
|
|
94
|
+
|
|
95
|
+
if (jsonMode) {
|
|
96
|
+
outputResult(result, true);
|
|
97
|
+
} else {
|
|
98
|
+
success(`Campaign ${id} paused`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function campaignsResume(args, jsonMode) {
|
|
103
|
+
const id = args["--id"];
|
|
104
|
+
|
|
105
|
+
if (!id) {
|
|
106
|
+
console.error("Usage: ses-cli campaigns resume --id CAMPAIGN_ID");
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result = await apiRequest("POST", `/campaigns/${id}/resume`);
|
|
111
|
+
|
|
112
|
+
if (jsonMode) {
|
|
113
|
+
outputResult(result, true);
|
|
114
|
+
} else {
|
|
115
|
+
success(`Campaign ${id} resumed`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function campaignsCancel(args, jsonMode) {
|
|
120
|
+
const id = args["--id"];
|
|
121
|
+
|
|
122
|
+
if (!id) {
|
|
123
|
+
console.error(`
|
|
124
|
+
Usage: ses-cli campaigns cancel --id CAMPAIGN_ID
|
|
125
|
+
|
|
126
|
+
Permanently cancels a campaign. This cannot be undone.
|
|
127
|
+
Unsent messages will not be delivered.
|
|
128
|
+
`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const result = await apiRequest("POST", `/campaigns/${id}/cancel`);
|
|
133
|
+
|
|
134
|
+
if (jsonMode) {
|
|
135
|
+
outputResult(result, true);
|
|
136
|
+
} else {
|
|
137
|
+
success(`Campaign ${id} cancelled`);
|
|
29
138
|
}
|
|
30
139
|
}
|
|
31
140
|
|
|
32
141
|
export async function analyticsOverview(args, jsonMode) {
|
|
33
|
-
const
|
|
142
|
+
const period = args["--period"] || "7d";
|
|
143
|
+
|
|
144
|
+
const result = await apiRequest("GET", "/analytics/overview", null, { period });
|
|
34
145
|
|
|
35
146
|
if (jsonMode) {
|
|
36
147
|
outputResult(result, true);
|
|
37
148
|
} else {
|
|
38
|
-
|
|
39
|
-
console.log("
|
|
40
|
-
console.log(
|
|
149
|
+
const data = result.data || result;
|
|
150
|
+
console.log("");
|
|
151
|
+
console.log(` ═══════════════════════════════════════`);
|
|
152
|
+
console.log(` SESender Analytics Overview (${period})`);
|
|
153
|
+
console.log(` ═══════════════════════════════════════`);
|
|
41
154
|
console.log("");
|
|
42
155
|
|
|
43
|
-
if (
|
|
156
|
+
if (data.sms || data.smsSent !== undefined) {
|
|
44
157
|
console.log(" SMS:");
|
|
45
|
-
console.log(` Total Sent: ${
|
|
46
|
-
console.log(` Delivered: ${
|
|
47
|
-
console.log(` Failed: ${
|
|
158
|
+
console.log(` Total Sent: ${data.sms?.totalSent || data.smsSent || 0}`);
|
|
159
|
+
console.log(` Delivered: ${data.sms?.delivered || 0}`);
|
|
160
|
+
console.log(` Failed: ${data.sms?.failed || 0}`);
|
|
48
161
|
console.log("");
|
|
49
162
|
}
|
|
50
163
|
|
|
51
|
-
if (
|
|
164
|
+
if (data.email || data.emailsSent !== undefined) {
|
|
52
165
|
console.log(" Email:");
|
|
53
|
-
console.log(` Total Sent: ${
|
|
54
|
-
console.log(` Opens: ${
|
|
55
|
-
console.log(` Clicks: ${
|
|
56
|
-
console.log(` Bounces: ${
|
|
166
|
+
console.log(` Total Sent: ${data.email?.totalSent || data.emailsSent || 0}`);
|
|
167
|
+
console.log(` Opens: ${data.email?.totalOpens || data.opens || 0}`);
|
|
168
|
+
console.log(` Clicks: ${data.email?.totalClicks || data.clicks || 0}`);
|
|
169
|
+
console.log(` Bounces: ${data.email?.bounces || data.bounces || 0}`);
|
|
170
|
+
console.log(` Open Rate: ${data.email?.openRate || data.openRate || "N/A"}%`);
|
|
171
|
+
console.log(` Click Rate: ${data.email?.clickRate || data.clickRate || "N/A"}%`);
|
|
57
172
|
console.log("");
|
|
58
173
|
}
|
|
59
174
|
|
|
60
|
-
if (
|
|
175
|
+
if (data.contacts) {
|
|
61
176
|
console.log(" Contacts:");
|
|
62
|
-
console.log(` Total: ${
|
|
63
|
-
console.log(` Groups: ${
|
|
177
|
+
console.log(` Total: ${data.contacts.total || 0}`);
|
|
178
|
+
console.log(` Groups: ${data.contacts.groups || 0}`);
|
|
64
179
|
console.log("");
|
|
65
180
|
}
|
|
66
181
|
|
|
67
|
-
console.log(
|
|
182
|
+
console.log(` ═══════════════════════════════════════`);
|
|
183
|
+
console.log("");
|
|
68
184
|
}
|
|
69
185
|
}
|