shipmail-cli 0.3.0 → 0.4.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 +26 -1
- package/dist/cli.js +98 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -51,6 +51,30 @@ shipmail messages send \
|
|
|
51
51
|
shipmail messages list --client-reference crm-123
|
|
52
52
|
shipmail messages reply msg_123 --to user@example.com --text "Thanks"
|
|
53
53
|
|
|
54
|
+
# Stage a raw file, then pass the returned sat_... ID when sending
|
|
55
|
+
shipmail mailboxes stage-attachment mbx_123 ./invoice.pdf --content-type application/pdf
|
|
56
|
+
|
|
57
|
+
# Prepare a five-minute, single-use upload URL for a browser-hosted component
|
|
58
|
+
shipmail mailboxes prepare-attachment-upload mbx_123 ./invoice.pdf --content-type application/pdf
|
|
59
|
+
|
|
60
|
+
shipmail messages send \
|
|
61
|
+
--mailbox-id mbx_123 \
|
|
62
|
+
--to customer@example.com \
|
|
63
|
+
--subject "Invoice" \
|
|
64
|
+
--text "Attached." \
|
|
65
|
+
--staged-attachment-id sat_123 \
|
|
66
|
+
--scheduled-at 2026-08-01T08:00:00.000Z
|
|
67
|
+
|
|
68
|
+
shipmail scheduled-messages list
|
|
69
|
+
shipmail scheduled-messages get msg_123
|
|
70
|
+
shipmail scheduled-messages update msg_123 \
|
|
71
|
+
--to customer@example.com \
|
|
72
|
+
--subject "Updated invoice" \
|
|
73
|
+
--text "Attached." \
|
|
74
|
+
--staged-attachment-id sat_123 \
|
|
75
|
+
--scheduled-at 2026-08-02T08:00:00.000Z
|
|
76
|
+
shipmail scheduled-messages cancel msg_123
|
|
77
|
+
|
|
54
78
|
# Use an sm_test_... key to simulate an outbound result and fake inbound reply
|
|
55
79
|
shipmail messages send --mailbox-id mbx_123 --to user@example.com --subject "Test" --text "Not delivered" --sandbox-outcome bounced
|
|
56
80
|
shipmail mailboxes sandbox-inbound mbx_123 --from customer@example.com --subject "Re: Test" --text "Fake inbound reply"
|
|
@@ -126,10 +150,11 @@ Use repeatable `--header "Name: value"` flags for request headers. Use `--output
|
|
|
126
150
|
- `status`
|
|
127
151
|
- `api <METHOD> <PATH>`
|
|
128
152
|
- `domains list|search|create|get|verify|delete`
|
|
129
|
-
- `mailboxes list|create|get|suspend|resume|forwarding|forwarding-add|forwarding-remove|app-passwords|folders|identities`
|
|
153
|
+
- `mailboxes list|create|get|suspend|resume|forwarding|forwarding-add|forwarding-remove|app-passwords|folders|identities|stage-attachment|prepare-attachment-upload`
|
|
130
154
|
- `inbox list|message|threads|thread|thread-state|draft|send-draft|reply-message|reply-thread|update|move`
|
|
131
155
|
- `reply-scans create|status|results`
|
|
132
156
|
- `messages send|list|get|reply` (test keys also support `--sandbox-outcome`)
|
|
157
|
+
- `scheduled-messages list|get|update|cancel`
|
|
133
158
|
- `mailboxes sandbox-inbound`
|
|
134
159
|
- `webhooks list|create|test|deliveries|replay-delivery`
|
|
135
160
|
- `suppressions list|remove`
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
+
import { createHash } from "crypto";
|
|
4
5
|
import { realpathSync } from "fs";
|
|
5
6
|
import { readFile, writeFile } from "fs/promises";
|
|
6
7
|
import { env as processEnv, exit, stderr, stdout } from "process";
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
} from "shipmail";
|
|
14
15
|
|
|
15
16
|
// src/version.ts
|
|
16
|
-
var VERSION = "0.
|
|
17
|
+
var VERSION = "0.4.0";
|
|
17
18
|
|
|
18
19
|
// src/cli.ts
|
|
19
20
|
var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
|
|
@@ -315,6 +316,7 @@ function usage() {
|
|
|
315
316
|
|
|
316
317
|
Usage:
|
|
317
318
|
shipmail status
|
|
319
|
+
shipmail capabilities
|
|
318
320
|
shipmail api <METHOD> <PATH> [--data JSON|@file] [--output file]
|
|
319
321
|
shipmail domains list [--limit 25] [--cursor cur]
|
|
320
322
|
shipmail domains search <keyword>
|
|
@@ -338,6 +340,8 @@ Usage:
|
|
|
338
340
|
shipmail mailboxes forwarding <id>
|
|
339
341
|
shipmail mailboxes forwarding-add <id> --destination owner@example.com
|
|
340
342
|
shipmail mailboxes forwarding-remove <id> <forwarding-id>
|
|
343
|
+
shipmail mailboxes prepare-attachment-upload <id> <file> [--filename name] [--content-type type]
|
|
344
|
+
shipmail mailboxes stage-attachment <id> <file> [--filename name] [--content-type type]
|
|
341
345
|
shipmail mailboxes sandbox-inbound <id> --from sender@example.com --subject "Test" (--text "Hello" | --html "<p>Hello</p>") [--to support@example.com]
|
|
342
346
|
shipmail inbox list <mailbox-id> [--folder-role inbox] [--after ISO] [--before ISO] [--limit 25] [--cursor cur]
|
|
343
347
|
shipmail inbox message <mailbox-id> <message-id>
|
|
@@ -354,6 +358,10 @@ Usage:
|
|
|
354
358
|
shipmail messages list (--mailbox-id mbx | --client-reference crm-123) [--limit 25] [--cursor cur]
|
|
355
359
|
shipmail messages get <message-id>
|
|
356
360
|
shipmail messages reply <message-id> --to user@example.com (--text "Hello" | --html "<p>Hello</p>") [--client-reference crm-reply-123]
|
|
361
|
+
shipmail scheduled-messages list [--include-held] [--search text] [--limit 100]
|
|
362
|
+
shipmail scheduled-messages get <message-id>
|
|
363
|
+
shipmail scheduled-messages update <message-id> --to user@example.com --subject "Hi" --scheduled-at ISO (--text "Hello" | --html "<p>Hello</p>") [--staged-attachment-id sat_...]
|
|
364
|
+
shipmail scheduled-messages cancel <message-id>
|
|
357
365
|
shipmail reply-scans create --mailbox-id mbx --after ISO [--before ISO]
|
|
358
366
|
shipmail reply-scans status <scan-id>
|
|
359
367
|
shipmail reply-scans results <scan-id> [--limit 25] [--cursor cur]
|
|
@@ -526,6 +534,7 @@ async function sendMessageParams(options) {
|
|
|
526
534
|
...metadata ? { metadata } : {},
|
|
527
535
|
...getString(options, "source-rfc-message-id") ? { source_rfc_message_id: getString(options, "source-rfc-message-id") } : {},
|
|
528
536
|
...headers.length > 0 ? { headers } : {},
|
|
537
|
+
...getStringList(options, "staged-attachment-id").length > 0 ? { staged_attachment_ids: getStringList(options, "staged-attachment-id") } : {},
|
|
529
538
|
...getString(options, "scheduled-at") ? { scheduled_at: getString(options, "scheduled-at") } : {},
|
|
530
539
|
...getString(options, "sandbox-outcome") ? {
|
|
531
540
|
sandbox_outcome: getEnum(options, "sandbox-outcome", [
|
|
@@ -759,6 +768,35 @@ async function runMailboxes(client, parsed, out) {
|
|
|
759
768
|
writeJson(out, { ok: true, id: forwardingId });
|
|
760
769
|
return;
|
|
761
770
|
}
|
|
771
|
+
if (subcommand === "stage-attachment") {
|
|
772
|
+
const mailboxId = requirePositional(parsed.positional, 2, "mailbox id");
|
|
773
|
+
const filePath = requirePositional(parsed.positional, 3, "file");
|
|
774
|
+
const data = await readFile(realpathSync(filePath));
|
|
775
|
+
writeJson(
|
|
776
|
+
out,
|
|
777
|
+
await client.mailboxes.stageAttachment(mailboxId, {
|
|
778
|
+
filename: getString(parsed.options, "filename") ?? filePath.split(/[\\/]/).at(-1) ?? "attachment",
|
|
779
|
+
data,
|
|
780
|
+
content_type: getString(parsed.options, "content-type")
|
|
781
|
+
})
|
|
782
|
+
);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
if (subcommand === "prepare-attachment-upload") {
|
|
786
|
+
const mailboxId = requirePositional(parsed.positional, 2, "mailbox id");
|
|
787
|
+
const filePath = requirePositional(parsed.positional, 3, "file");
|
|
788
|
+
const data = await readFile(realpathSync(filePath));
|
|
789
|
+
writeJson(
|
|
790
|
+
out,
|
|
791
|
+
await client.mailboxes.prepareStagedAttachmentUpload(mailboxId, {
|
|
792
|
+
filename: getString(parsed.options, "filename") ?? filePath.split(/[\\/]/).at(-1) ?? "attachment",
|
|
793
|
+
content_type: getString(parsed.options, "content-type") ?? "application/octet-stream",
|
|
794
|
+
size: data.byteLength,
|
|
795
|
+
sha256: createHash("sha256").update(data).digest("hex")
|
|
796
|
+
})
|
|
797
|
+
);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
762
800
|
if (subcommand === "sandbox-inbound") {
|
|
763
801
|
const text = getString(parsed.options, "text");
|
|
764
802
|
const html = getString(parsed.options, "html");
|
|
@@ -1037,6 +1075,52 @@ async function runMessages(client, parsed, out) {
|
|
|
1037
1075
|
}
|
|
1038
1076
|
throw new CliUsageError("Unknown messages command.");
|
|
1039
1077
|
}
|
|
1078
|
+
async function runScheduledMessages(client, parsed, out) {
|
|
1079
|
+
const subcommand = parsed.positional[1];
|
|
1080
|
+
if (subcommand === "list") {
|
|
1081
|
+
writeJson(
|
|
1082
|
+
out,
|
|
1083
|
+
await client.scheduledMessages.list({
|
|
1084
|
+
include_held: getBoolean(parsed.options, "include-held"),
|
|
1085
|
+
search: getString(parsed.options, "search"),
|
|
1086
|
+
limit: getNumber(parsed.options, "limit")
|
|
1087
|
+
})
|
|
1088
|
+
);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
const messageId = requirePositional(parsed.positional, 2, "message id");
|
|
1092
|
+
if (subcommand === "get") {
|
|
1093
|
+
writeJson(out, await client.scheduledMessages.get(messageId));
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
if (subcommand === "cancel") {
|
|
1097
|
+
await client.scheduledMessages.cancel(messageId);
|
|
1098
|
+
writeJson(out, { ok: true, id: messageId });
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
if (subcommand === "update") {
|
|
1102
|
+
const to = messageRecipients(parsed.options, "to");
|
|
1103
|
+
const cc = messageRecipients(parsed.options, "cc");
|
|
1104
|
+
const bcc = messageRecipients(parsed.options, "bcc");
|
|
1105
|
+
const text = getString(parsed.options, "text");
|
|
1106
|
+
const html = getString(parsed.options, "html");
|
|
1107
|
+
if (to.length === 0) throw new CliUsageError("Provide at least one --to recipient.");
|
|
1108
|
+
if (!text && !html) throw new CliUsageError("Provide --text or --html.");
|
|
1109
|
+
const update = {
|
|
1110
|
+
to,
|
|
1111
|
+
...cc.length > 0 ? { cc } : {},
|
|
1112
|
+
...bcc.length > 0 ? { bcc } : {},
|
|
1113
|
+
subject: getRequiredString(parsed.options, "subject"),
|
|
1114
|
+
...text ? { text } : {},
|
|
1115
|
+
...html ? { html } : {},
|
|
1116
|
+
...getStringList(parsed.options, "staged-attachment-id").length > 0 ? { staged_attachment_ids: getStringList(parsed.options, "staged-attachment-id") } : {},
|
|
1117
|
+
scheduled_at: getRequiredString(parsed.options, "scheduled-at")
|
|
1118
|
+
};
|
|
1119
|
+
writeJson(out, await client.scheduledMessages.update(messageId, update));
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
throw new CliUsageError("Unknown scheduled-messages command.");
|
|
1123
|
+
}
|
|
1040
1124
|
async function runWebhooks(client, parsed, out) {
|
|
1041
1125
|
const subcommand = parsed.positional[1];
|
|
1042
1126
|
if (subcommand === "list") {
|
|
@@ -1779,6 +1863,18 @@ async function runCli(argv, options = {}) {
|
|
|
1779
1863
|
await writeRawResponse(parsed, { stdout: out }, response);
|
|
1780
1864
|
return 0;
|
|
1781
1865
|
}
|
|
1866
|
+
if (command === "capabilities") {
|
|
1867
|
+
const response = await rawApiRequest(
|
|
1868
|
+
parsed,
|
|
1869
|
+
options,
|
|
1870
|
+
"GET",
|
|
1871
|
+
"/capabilities",
|
|
1872
|
+
void 0,
|
|
1873
|
+
true
|
|
1874
|
+
);
|
|
1875
|
+
await writeRawResponse(parsed, { stdout: out }, response);
|
|
1876
|
+
return 0;
|
|
1877
|
+
}
|
|
1782
1878
|
if (command === "api") {
|
|
1783
1879
|
const method = requirePositional(parsed.positional, 1, "method").toUpperCase();
|
|
1784
1880
|
const path = apiPath(requirePositional(parsed.positional, 2, "path"));
|
|
@@ -1792,6 +1888,7 @@ async function runCli(argv, options = {}) {
|
|
|
1792
1888
|
else if (command === "mailboxes") await runMailboxes(client, parsed, out);
|
|
1793
1889
|
else if (command === "inbox") await runInbox(client, parsed, out);
|
|
1794
1890
|
else if (command === "messages") await runMessages(client, parsed, out);
|
|
1891
|
+
else if (command === "scheduled-messages") await runScheduledMessages(client, parsed, out);
|
|
1795
1892
|
else if (command === "reply-scans") await runReplyScans(client, parsed, out);
|
|
1796
1893
|
else if (command === "webhooks") await runWebhooks(client, parsed, out);
|
|
1797
1894
|
else if (command === "suppressions") await runSuppressions(client, parsed, out);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shipmail-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Official CLI for the ShipMail API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"shipmail": "0.
|
|
44
|
+
"shipmail": "0.4.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"tsup": "^8.4.0",
|