shipmail-cli 0.2.0 → 0.2.2
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 +18 -3
- package/dist/cli.js +162 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -56,8 +56,21 @@ shipmail messages send --mailbox-id mbx_123 --to user@example.com --subject "Tes
|
|
|
56
56
|
shipmail mailboxes sandbox-inbound mbx_123 --from customer@example.com --subject "Re: Test" --text "Fake inbound reply"
|
|
57
57
|
|
|
58
58
|
# Read inbound mail
|
|
59
|
-
shipmail inbox list
|
|
60
|
-
shipmail inbox
|
|
59
|
+
shipmail inbox list 550e8400-e29b-41d4-a716-446655440000 --folder-role inbox --after 2025-07-20T00:00:00Z --limit 25
|
|
60
|
+
shipmail inbox message 550e8400-e29b-41d4-a716-446655440000 eml_123
|
|
61
|
+
shipmail inbox threads 550e8400-e29b-41d4-a716-446655440000 --reply-state needs_reply --after 2025-07-20T00:00:00Z --limit 50
|
|
62
|
+
shipmail inbox thread 550e8400-e29b-41d4-a716-446655440000 thr_123
|
|
63
|
+
shipmail inbox draft 550e8400-e29b-41d4-a716-446655440000 thr_123 --expected-reply-version 7 --text "Thanks for the note"
|
|
64
|
+
# Apply your approval policy; stale drafts fail with 409 without delivery.
|
|
65
|
+
shipmail inbox send-draft 550e8400-e29b-41d4-a716-446655440000 thr_123 drf_123
|
|
66
|
+
shipmail inbox thread-state 550e8400-e29b-41d4-a716-446655440000 thr_123 --reply-state resolved --expected-reply-version 8
|
|
67
|
+
shipmail inbox reply-message 550e8400-e29b-41d4-a716-446655440000 eml_123 --to user@example.com --text "Thanks"
|
|
68
|
+
shipmail inbox reply-thread 550e8400-e29b-41d4-a716-446655440000 thr_123 --to user@example.com --text "Following up"
|
|
69
|
+
|
|
70
|
+
# Frozen historical scan, retained for 30 days (repeat --mailbox-id for more mailboxes)
|
|
71
|
+
shipmail reply-scans create --mailbox-id 550e8400-e29b-41d4-a716-446655440000 --after 2025-07-20T00:00:00Z
|
|
72
|
+
shipmail reply-scans status rsc_123
|
|
73
|
+
shipmail reply-scans results rsc_123 --limit 100
|
|
61
74
|
|
|
62
75
|
# Find newsletter sending domain IDs, then create a draft with blocks
|
|
63
76
|
shipmail newsletter-domains list
|
|
@@ -68,6 +81,7 @@ shipmail newsletters create \
|
|
|
68
81
|
--subject "What shipped in July" \
|
|
69
82
|
--blocks @blocks.json
|
|
70
83
|
shipmail newsletters update nws_123 --subject "Updated subject"
|
|
84
|
+
# A concurrent update exits with conflict (409); fetch the latest newsletter before retrying.
|
|
71
85
|
shipmail newsletters preview nws_123
|
|
72
86
|
shipmail newsletters test-send nws_123 --recipient-email owner@example.com
|
|
73
87
|
shipmail newsletters preflight nws_123
|
|
@@ -116,7 +130,8 @@ Use repeatable `--header "Name: value"` flags for request headers. Use `--output
|
|
|
116
130
|
- `api <METHOD> <PATH>`
|
|
117
131
|
- `domains list|search|create|get|verify|delete`
|
|
118
132
|
- `mailboxes list|create|get|suspend|resume|forwarding|forwarding-add|forwarding-remove|app-passwords|folders|identities|rules`
|
|
119
|
-
- `inbox list|thread|update|move`
|
|
133
|
+
- `inbox list|message|threads|thread|thread-state|draft|send-draft|reply-message|reply-thread|update|move`
|
|
134
|
+
- `reply-scans create|status|results`
|
|
120
135
|
- `messages send|list|get|reply` (test keys also support `--sandbox-outcome`)
|
|
121
136
|
- `mailboxes sandbox-inbound`
|
|
122
137
|
- `webhooks list|create|test|deliveries|replay-delivery`
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "shipmail";
|
|
14
14
|
|
|
15
15
|
// src/version.ts
|
|
16
|
-
var VERSION = "0.2.
|
|
16
|
+
var VERSION = "0.2.2";
|
|
17
17
|
|
|
18
18
|
// src/cli.ts
|
|
19
19
|
var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
|
|
@@ -340,14 +340,24 @@ Usage:
|
|
|
340
340
|
shipmail mailboxes forwarding-add <id> --destination owner@example.com
|
|
341
341
|
shipmail mailboxes forwarding-remove <id> <forwarding-id>
|
|
342
342
|
shipmail mailboxes sandbox-inbound <id> --from sender@example.com --subject "Test" (--text "Hello" | --html "<p>Hello</p>") [--to support@example.com]
|
|
343
|
-
shipmail inbox list <mailbox-id> [--folder-role inbox] [--limit 25]
|
|
343
|
+
shipmail inbox list <mailbox-id> [--folder-role inbox] [--after ISO] [--before ISO] [--limit 25] [--cursor cur]
|
|
344
|
+
shipmail inbox message <mailbox-id> <message-id>
|
|
345
|
+
shipmail inbox threads <mailbox-id> [--reply-state needs_reply] [--after ISO] [--before ISO] [--limit 25] [--cursor cur]
|
|
344
346
|
shipmail inbox thread <mailbox-id> <thread-id>
|
|
347
|
+
shipmail inbox thread-state <mailbox-id> <thread-id> --reply-state resolved --expected-reply-version 3
|
|
348
|
+
shipmail inbox draft <mailbox-id> <thread-id> --expected-reply-version 3 (--text "Hello" | --html "<p>Hello</p>") [--reply-mode reply_all]
|
|
349
|
+
shipmail inbox send-draft <mailbox-id> <thread-id> <draft-id>
|
|
350
|
+
shipmail inbox reply-message <mailbox-id> <message-id> --to user@example.com (--text "Hello" | --html "<p>Hello</p>")
|
|
351
|
+
shipmail inbox reply-thread <mailbox-id> <thread-id> --to user@example.com (--text "Hello" | --html "<p>Hello</p>")
|
|
345
352
|
shipmail inbox update <mailbox-id> <message-id> [--read true] [--starred false]
|
|
346
353
|
shipmail inbox move <mailbox-id> <message-id> (--target-role archive | --target-folder-id fld)
|
|
347
354
|
shipmail messages send --mailbox-id mbx --to user@example.com --subject "Hi" --text "Hello" [--sandbox-outcome delivered|bounced|complained] [--client-reference crm-123] [--metadata JSON|@file] [--source-rfc-message-id '<crm-123@example.com>'] [--header 'X-CRM-ID: 123']
|
|
348
355
|
shipmail messages list (--mailbox-id mbx | --client-reference crm-123) [--limit 25] [--cursor cur]
|
|
349
356
|
shipmail messages get <message-id>
|
|
350
357
|
shipmail messages reply <message-id> --to user@example.com (--text "Hello" | --html "<p>Hello</p>") [--client-reference crm-reply-123]
|
|
358
|
+
shipmail reply-scans create --mailbox-id mbx --after ISO [--before ISO]
|
|
359
|
+
shipmail reply-scans status <scan-id>
|
|
360
|
+
shipmail reply-scans results <scan-id> [--limit 25] [--cursor cur]
|
|
351
361
|
shipmail webhooks list
|
|
352
362
|
shipmail webhooks create --url https://example.com/hook --events message.received,message.bounced
|
|
353
363
|
shipmail webhooks replay-delivery <webhook-id> <delivery-id> [--idempotency-key key]
|
|
@@ -432,14 +442,18 @@ function inboxListParams(options) {
|
|
|
432
442
|
const folderId = getString(options, "folder-id");
|
|
433
443
|
const folderRole = getString(options, "folder-role");
|
|
434
444
|
const searchText = getString(options, "search");
|
|
435
|
-
const
|
|
445
|
+
const cursor = getString(options, "cursor");
|
|
446
|
+
const after = getString(options, "after");
|
|
447
|
+
const before = getString(options, "before");
|
|
436
448
|
const limit = getNumber(options, "limit");
|
|
437
449
|
const hasKeyword = getString(options, "has-keyword");
|
|
438
450
|
const notKeyword = getString(options, "not-keyword");
|
|
439
451
|
if (folderId) params.folder_id = folderId;
|
|
440
452
|
if (folderRole) params.folder_role = folderRole;
|
|
441
453
|
if (searchText) params.search_text = searchText;
|
|
442
|
-
if (
|
|
454
|
+
if (cursor) params.cursor = cursor;
|
|
455
|
+
if (after) params.after = after;
|
|
456
|
+
if (before) params.before = before;
|
|
443
457
|
if (limit !== void 0) params.limit = limit;
|
|
444
458
|
if (hasKeyword) params.has_keyword = hasKeyword;
|
|
445
459
|
if (notKeyword) params.not_keyword = notKeyword;
|
|
@@ -805,6 +819,114 @@ async function runInbox(client, parsed, out) {
|
|
|
805
819
|
);
|
|
806
820
|
return;
|
|
807
821
|
}
|
|
822
|
+
if (subcommand === "message") {
|
|
823
|
+
writeJson(
|
|
824
|
+
out,
|
|
825
|
+
await client.mailboxes.getInboxMessage(
|
|
826
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
827
|
+
requirePositional(parsed.positional, 3, "message id")
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (subcommand === "threads") {
|
|
833
|
+
const replyState = getString(parsed.options, "reply-state");
|
|
834
|
+
const sortBy = getString(parsed.options, "sort-by");
|
|
835
|
+
const order = getString(parsed.options, "order");
|
|
836
|
+
writeJson(
|
|
837
|
+
out,
|
|
838
|
+
await client.mailboxes.listInboxThreads(
|
|
839
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
840
|
+
{
|
|
841
|
+
...replyState ? {
|
|
842
|
+
reply_state: replyState
|
|
843
|
+
} : {},
|
|
844
|
+
...sortBy ? { sort_by: sortBy } : {},
|
|
845
|
+
...order ? { order } : {},
|
|
846
|
+
...getString(parsed.options, "after") ? { after: getString(parsed.options, "after") } : {},
|
|
847
|
+
...getString(parsed.options, "before") ? { before: getString(parsed.options, "before") } : {},
|
|
848
|
+
...getString(parsed.options, "cursor") ? { cursor: getString(parsed.options, "cursor") } : {},
|
|
849
|
+
...getNumber(parsed.options, "limit") !== void 0 ? { limit: getNumber(parsed.options, "limit") } : {}
|
|
850
|
+
}
|
|
851
|
+
)
|
|
852
|
+
);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (subcommand === "thread-state") {
|
|
856
|
+
const replyState = getString(parsed.options, "reply-state");
|
|
857
|
+
const expectedReplyVersion = getNumber(parsed.options, "expected-reply-version");
|
|
858
|
+
if (!replyState || expectedReplyVersion === void 0) {
|
|
859
|
+
throw new CliUsageError("Provide --reply-state and --expected-reply-version.");
|
|
860
|
+
}
|
|
861
|
+
writeJson(
|
|
862
|
+
out,
|
|
863
|
+
await client.mailboxes.updateInboxThreadReplyState(
|
|
864
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
865
|
+
requirePositional(parsed.positional, 3, "thread id"),
|
|
866
|
+
{
|
|
867
|
+
reply_state: replyState,
|
|
868
|
+
expected_reply_version: expectedReplyVersion
|
|
869
|
+
}
|
|
870
|
+
)
|
|
871
|
+
);
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
if (subcommand === "draft") {
|
|
875
|
+
const expectedReplyVersion = getNumber(parsed.options, "expected-reply-version");
|
|
876
|
+
if (expectedReplyVersion === void 0) {
|
|
877
|
+
throw new CliUsageError("Provide --expected-reply-version.");
|
|
878
|
+
}
|
|
879
|
+
const text = await readTextInput(getString(parsed.options, "text"));
|
|
880
|
+
const html = await readTextInput(getString(parsed.options, "html"));
|
|
881
|
+
if (!text && !html) throw new CliUsageError("Provide --text or --html.");
|
|
882
|
+
writeJson(
|
|
883
|
+
out,
|
|
884
|
+
await client.mailboxes.createInboxReplyDraft(
|
|
885
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
886
|
+
requirePositional(parsed.positional, 3, "thread id"),
|
|
887
|
+
{
|
|
888
|
+
expected_reply_version: expectedReplyVersion,
|
|
889
|
+
...text ? { text } : {},
|
|
890
|
+
...html ? { html } : {},
|
|
891
|
+
...getString(parsed.options, "reply-mode") ? { reply_mode: getString(parsed.options, "reply-mode") } : {}
|
|
892
|
+
}
|
|
893
|
+
)
|
|
894
|
+
);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
if (subcommand === "send-draft") {
|
|
898
|
+
writeJson(
|
|
899
|
+
out,
|
|
900
|
+
await client.mailboxes.sendInboxReplyDraft(
|
|
901
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
902
|
+
requirePositional(parsed.positional, 3, "thread id"),
|
|
903
|
+
requirePositional(parsed.positional, 4, "draft id")
|
|
904
|
+
)
|
|
905
|
+
);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
if (subcommand === "reply-message") {
|
|
909
|
+
writeJson(
|
|
910
|
+
out,
|
|
911
|
+
await client.mailboxes.replyToInboxMessage(
|
|
912
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
913
|
+
requirePositional(parsed.positional, 3, "message id"),
|
|
914
|
+
await replyToMessageParams(parsed.options)
|
|
915
|
+
)
|
|
916
|
+
);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
if (subcommand === "reply-thread") {
|
|
920
|
+
writeJson(
|
|
921
|
+
out,
|
|
922
|
+
await client.mailboxes.replyToInboxThread(
|
|
923
|
+
requirePositional(parsed.positional, 2, "mailbox id"),
|
|
924
|
+
requirePositional(parsed.positional, 3, "thread id"),
|
|
925
|
+
await replyToMessageParams(parsed.options)
|
|
926
|
+
)
|
|
927
|
+
);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
808
930
|
if (subcommand === "update") {
|
|
809
931
|
const read = getBoolean(parsed.options, "read");
|
|
810
932
|
const starred = getBoolean(parsed.options, "starred");
|
|
@@ -846,6 +968,41 @@ async function runInbox(client, parsed, out) {
|
|
|
846
968
|
}
|
|
847
969
|
throw new CliUsageError("Unknown inbox command.");
|
|
848
970
|
}
|
|
971
|
+
async function runReplyScans(client, parsed, out) {
|
|
972
|
+
const subcommand = parsed.positional[1];
|
|
973
|
+
if (subcommand === "create") {
|
|
974
|
+
const mailboxIds = getStringList(parsed.options, "mailbox-id");
|
|
975
|
+
const after = getString(parsed.options, "after");
|
|
976
|
+
if (mailboxIds.length === 0 || !after) {
|
|
977
|
+
throw new CliUsageError("Provide --mailbox-id and --after.");
|
|
978
|
+
}
|
|
979
|
+
writeJson(
|
|
980
|
+
out,
|
|
981
|
+
await client.replyScans.create({
|
|
982
|
+
mailbox_ids: [...mailboxIds],
|
|
983
|
+
after,
|
|
984
|
+
...getString(parsed.options, "before") ? { before: getString(parsed.options, "before") } : {}
|
|
985
|
+
})
|
|
986
|
+
);
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const scanId = requirePositional(parsed.positional, 2, "scan id");
|
|
990
|
+
if (subcommand === "status") {
|
|
991
|
+
writeJson(out, await client.replyScans.get(scanId));
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
if (subcommand === "results") {
|
|
995
|
+
writeJson(
|
|
996
|
+
out,
|
|
997
|
+
await client.replyScans.listResults(scanId, {
|
|
998
|
+
...getString(parsed.options, "cursor") ? { cursor: getString(parsed.options, "cursor") } : {},
|
|
999
|
+
...getNumber(parsed.options, "limit") !== void 0 ? { limit: getNumber(parsed.options, "limit") } : {}
|
|
1000
|
+
})
|
|
1001
|
+
);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
throw new CliUsageError("Unknown reply-scans command.");
|
|
1005
|
+
}
|
|
849
1006
|
async function runMessages(client, parsed, out) {
|
|
850
1007
|
const subcommand = parsed.positional[1];
|
|
851
1008
|
if (subcommand === "send") {
|
|
@@ -1643,6 +1800,7 @@ async function runCli(argv, options = {}) {
|
|
|
1643
1800
|
else if (command === "mailboxes") await runMailboxes(client, parsed, out);
|
|
1644
1801
|
else if (command === "inbox") await runInbox(client, parsed, out);
|
|
1645
1802
|
else if (command === "messages") await runMessages(client, parsed, out);
|
|
1803
|
+
else if (command === "reply-scans") await runReplyScans(client, parsed, out);
|
|
1646
1804
|
else if (command === "webhooks") await runWebhooks(client, parsed, out);
|
|
1647
1805
|
else if (command === "suppressions") await runSuppressions(client, parsed, out);
|
|
1648
1806
|
else if (command === "newsletters") await runNewsletters(client, parsed, out);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shipmail-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
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.2.
|
|
44
|
+
"shipmail": "0.2.3"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"tsup": "^8.4.0",
|