From de980d7f12ba4562945402cdc47bb01f50bbf538 Mon Sep 17 00:00:00 2001 From: Maciej Walusiak Date: Tue, 3 Nov 2026 09:04:29 +0100 Subject: [PATCH 1/3] Use the Sandbox and Domain names in help text and skill docs Decisions: - The commands, flags and config keys already use sandbox/domain; this aligns the remaining prose and internal identifiers with them - API paths, request body roots, JSON keys and token resource types keep inbox/sending_domain because they mirror the wire - Email Inbound keeps "inbox": inbound inboxes are a separate product - SKILL.md gains a naming note so agents still map "inbox" and "sending domain" requests to sandboxes and domains Co-Authored-By: Claude Opus 5.5 --- cmd/root.go | 2 +- docs/TEST_PLAN.md | 68 +++++++++---------- internal/commands/companyinfo/companyinfo.go | 2 +- internal/commands/companyinfo/create.go | 4 +- internal/commands/companyinfo/get.go | 4 +- internal/commands/companyinfo/update.go | 4 +- internal/commands/domains/create.go | 2 +- internal/commands/domains/delete.go | 2 +- internal/commands/domains/domains.go | 2 +- internal/commands/domains/get.go | 2 +- internal/commands/domains/list.go | 2 +- internal/commands/domains/update.go | 2 +- .../commands/emailcampaigns/attributes.go | 2 +- internal/commands/inbound/inboxes/create.go | 2 +- .../commands/sandbox_send/sandbox_send.go | 4 +- internal/commands/sandboxes/clean.go | 8 +-- internal/commands/sandboxes/create.go | 6 +- internal/commands/sandboxes/delete.go | 8 +-- internal/commands/sandboxes/get.go | 14 ++-- internal/commands/sandboxes/list.go | 10 +-- internal/commands/sandboxes/mark_read.go | 14 ++-- .../commands/sandboxes/reset_credentials.go | 14 ++-- internal/commands/sandboxes/reset_email.go | 14 ++-- internal/commands/sandboxes/toggle_email.go | 14 ++-- internal/commands/sandboxes/update.go | 14 ++-- internal/commands/stats/get.go | 28 ++++---- internal/commands/suppressions/create.go | 2 +- internal/commands/tokens/create.go | 2 +- internal/commands/trackingoptouts/create.go | 2 +- skills/mailtrap-cli/SKILL.md | 9 +-- skills/mailtrap-cli/references/domains.md | 24 +++---- skills/mailtrap-cli/references/email-logs.md | 2 +- skills/mailtrap-cli/references/error-codes.md | 2 +- skills/mailtrap-cli/references/inbound.md | 2 +- 34 files changed, 147 insertions(+), 146 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 38ad199..9b4f1d4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -39,7 +39,7 @@ func NewRootCmd(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "mailtrap", Short: "CLI for the Mailtrap email platform", - Long: "A command-line interface for managing Mailtrap email sending, sandbox testing, contacts, and account settings.", + Long: "A command-line interface for managing Mailtrap email sending, sandboxes, contacts, and account settings.", SilenceUsage: true, SilenceErrors: true, } diff --git a/docs/TEST_PLAN.md b/docs/TEST_PLAN.md index f8bae5d..6259c49 100644 --- a/docs/TEST_PLAN.md +++ b/docs/TEST_PLAN.md @@ -25,9 +25,9 @@ export MAILTRAP_API_TOKEN=your-token Before running integration tests, ensure you have: - A Mailtrap account with API access -- A verified **sending domain** for transactional/bulk send tests -- At least one **sandbox project** with an **inbox** for sandbox tests -- Note down your **inbox ID** for sandbox send tests +- A verified **domain** for transactional/bulk send tests +- At least one **sandbox project** with a **sandbox** for sandbox tests +- Note down your **sandbox ID** for sandbox send tests ### 3. Build the CLI @@ -91,7 +91,7 @@ Tests are organized by endpoint group. Each test specifies: ## 2. Email Sending (Transactional/Bulk) -**Note:** Requires a verified sending domain. +**Note:** Requires a verified domain. | # | Test | Command | Expected | |---|------|---------|----------| @@ -105,7 +105,7 @@ Tests are organized by endpoint group. Each test specifies: | 2.8 | Send from template | `mailtrap send transactional --from you@yourdomain.com --to recipient@example.com --template-uuid --template-variables '{"user_name":"John"}'` | Success; delivered email has the template's subject and `John` substituted. Repeat with `send bulk` | | 2.9 | Template with subject | `mailtrap send transactional --from you@yourdomain.com --to recipient@example.com --template-uuid --subject "X"` | Error: `--subject cannot be used with --template-uuid` | -## 3. Domains (Sending) +## 3. Domains **Note:** The API returns `{"data": [...]}` — the CLI may need a fix to unwrap this. @@ -226,16 +226,16 @@ Tests are organized by endpoint group. Each test specifies: | # | Test | Command | Expected | |---|------|---------|----------| -| 12.1 | List inboxes | `mailtrap sandboxes list` | Table with sandbox entries | -| 12.2 | Get inbox | `mailtrap sandboxes get --id ` | Single sandbox details | -| 12.3 | Create inbox | `mailtrap sandboxes create --project-id --name "test-sandbox"` | New inbox in output | -| 12.4 | Update inbox | `mailtrap sandboxes update --id --name "test-sandbox-updated"` | Updated name | -| 12.5 | Mark read | `mailtrap sandboxes mark-read --id ` | Success message | +| 12.1 | List sandboxes | `mailtrap sandboxes list` | Table with sandbox entries | +| 12.2 | Get sandbox | `mailtrap sandboxes get --id ` | Single sandbox details | +| 12.3 | Create sandbox | `mailtrap sandboxes create --project-id --name "test-sandbox"` | New sandbox in output | +| 12.4 | Update sandbox | `mailtrap sandboxes update --id --name "test-sandbox-updated"` | Updated name | +| 12.5 | Mark read | `mailtrap sandboxes mark-read --id ` | Success message | | 12.6 | Reset credentials | `mailtrap sandboxes reset-credentials --id ` | Success/new credentials | | 12.7 | Toggle email username | `mailtrap sandboxes toggle-email-username --id ` | Toggled response | | 12.8 | Reset email username | `mailtrap sandboxes reset-email-username --id ` | Reset response | -| 12.9 | Clean inbox | `mailtrap sandboxes clean --id ` | Success message | -| 12.10 | Delete inbox | `mailtrap sandboxes delete --id ` | Success message | +| 12.9 | Clean sandbox | `mailtrap sandboxes clean --id ` | Success message | +| 12.10 | Delete sandbox | `mailtrap sandboxes delete --id ` | Success message | | 12.11 | Get missing ID | `mailtrap sandboxes get` | Error: `--id is required` | **Cleanup:** Delete test sandbox. @@ -244,11 +244,11 @@ Tests are organized by endpoint group. Each test specifies: | # | Test | Command | Expected | |---|------|---------|----------| -| 13.1 | Send single | `mailtrap sandbox-send single --sandbox-id --from test@example.com --to recipient@example.com --subject "Integration Test" --text "Hello from CLI"` | Success response with message ID | -| 13.2 | Send batch | `mailtrap sandbox-send batch --sandbox-id --from test@example.com --to recipient@example.com --subject "Batch Test" --text "Batch hello"` | Success response | +| 13.1 | Send single | `mailtrap sandbox-send single --sandbox-id --from test@example.com --to recipient@example.com --subject "Integration Test" --text "Hello from CLI"` | Success response with message ID | +| 13.2 | Send batch | `mailtrap sandbox-send batch --sandbox-id --from test@example.com --to recipient@example.com --subject "Batch Test" --text "Batch hello"` | Success response | | 13.3 | Missing flags | `mailtrap sandbox-send single` | Error: required flags | -**Verification:** After 13.1, run `mailtrap messages list --sandbox-id ` to confirm the message appears. +**Verification:** After 13.1, run `mailtrap messages list --sandbox-id ` to confirm the message appears. ## 14. Messages (Sandbox) @@ -256,22 +256,22 @@ Prerequisite: Send a test email to the sandbox first (test 13.1). | # | Test | Command | Expected | |---|------|---------|----------| -| 14.1 | List messages | `mailtrap messages list --sandbox-id ` | Table with message entries | -| 14.2 | List messages (JSON) | `mailtrap messages list --sandbox-id --output json` | Valid JSON array | -| 14.3 | Get message | `mailtrap messages get --sandbox-id --id ` | Single message details | -| 14.4 | Update message | `mailtrap messages update --sandbox-id --id --is-read true` | Updated message | -| 14.5 | Spam score | `mailtrap messages spam-score --sandbox-id --id ` | Spam score data | -| 14.6 | HTML analysis | `mailtrap messages html-analysis --sandbox-id --id ` | Analysis data | -| 14.7 | Headers | `mailtrap messages headers --sandbox-id --id ` | Email headers | -| 14.8 | HTML body | `mailtrap messages html --sandbox-id --id ` | Raw HTML content | -| 14.9 | Text body | `mailtrap messages text --sandbox-id --id ` | Raw text content | -| 14.10 | Source | `mailtrap messages source --sandbox-id --id ` | Raw source | -| 14.11 | Raw | `mailtrap messages raw --sandbox-id --id ` | Raw message | -| 14.12 | EML | `mailtrap messages eml --sandbox-id --id ` | EML format | -| 14.13 | Forward | `mailtrap messages forward --sandbox-id --id --email forward@example.com` | Success | -| 14.14 | Delete message | `mailtrap messages delete --sandbox-id --id ` | Success message | +| 14.1 | List messages | `mailtrap messages list --sandbox-id ` | Table with message entries | +| 14.2 | List messages (JSON) | `mailtrap messages list --sandbox-id --output json` | Valid JSON array | +| 14.3 | Get message | `mailtrap messages get --sandbox-id --id ` | Single message details | +| 14.4 | Update message | `mailtrap messages update --sandbox-id --id --is-read true` | Updated message | +| 14.5 | Spam score | `mailtrap messages spam-score --sandbox-id --id ` | Spam score data | +| 14.6 | HTML analysis | `mailtrap messages html-analysis --sandbox-id --id ` | Analysis data | +| 14.7 | Headers | `mailtrap messages headers --sandbox-id --id ` | Email headers | +| 14.8 | HTML body | `mailtrap messages html --sandbox-id --id ` | Raw HTML content | +| 14.9 | Text body | `mailtrap messages text --sandbox-id --id ` | Raw text content | +| 14.10 | Source | `mailtrap messages source --sandbox-id --id ` | Raw source | +| 14.11 | Raw | `mailtrap messages raw --sandbox-id --id ` | Raw message | +| 14.12 | EML | `mailtrap messages eml --sandbox-id --id ` | EML format | +| 14.13 | Forward | `mailtrap messages forward --sandbox-id --id --email forward@example.com` | Success | +| 14.14 | Delete message | `mailtrap messages delete --sandbox-id --id ` | Success message | | 14.15 | Missing sandbox-id | `mailtrap messages list` | Error: `--sandbox-id is required` | -| 14.16 | Missing id | `mailtrap messages get --sandbox-id ` | Error: `--id is required` | +| 14.16 | Missing id | `mailtrap messages get --sandbox-id ` | Error: `--id is required` | ## 15. Attachments (Sandbox) @@ -279,8 +279,8 @@ Prerequisite: Send an email with an attachment to the sandbox. | # | Test | Command | Expected | |---|------|---------|----------| -| 15.1 | List attachments | `mailtrap attachments list --sandbox-id --message-id ` | Table with attachments | -| 15.2 | Get attachment | `mailtrap attachments get --sandbox-id --message-id --id ` | Attachment details | +| 15.1 | List attachments | `mailtrap attachments list --sandbox-id --message-id ` | Table with attachments | +| 15.2 | Get attachment | `mailtrap attachments get --sandbox-id --message-id --id ` | Attachment details | | 15.3 | Missing flags | `mailtrap attachments list` | Error: required flags | ## 16. Account Access @@ -399,7 +399,7 @@ Run tests in dependency order so earlier tests create resources needed by later 1. **Accounts** (read-only, validates API access) 2. **Sending** (transactional/bulk — requires verified domain) -3. **Domains** (CRUD for sending domains) +3. **Domains** (CRUD) 4. **Templates** (CRUD) 5. **Suppressions** (list/delete) 6. **Stats** (requires start-date) @@ -408,7 +408,7 @@ Run tests in dependency order so earlier tests create resources needed by later 9. **Contact Fields** (CRUD) 10. **Contacts** (CRUD) 11. **Projects** (CRUD — creates project for sandbox tests) -12. **Inboxes** (CRUD — creates sandbox for sandbox send/message tests) +12. **Sandboxes** (CRUD — creates a sandbox for sandbox send/message tests) 13. **Sandbox Send** (sends email to sandbox for message tests) 14. **Messages** (all subcommands on the sent message) 15. **Attachments** (requires message with attachment) diff --git a/internal/commands/companyinfo/companyinfo.go b/internal/commands/companyinfo/companyinfo.go index 8c662cf..3462d2e 100644 --- a/internal/commands/companyinfo/companyinfo.go +++ b/internal/commands/companyinfo/companyinfo.go @@ -43,7 +43,7 @@ func companyInfoPath(domainID string) string { func NewCmdCompanyInfo(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "company-info", - Short: "Manage sending domain company info", + Short: "Manage domain company info", } cmd.AddCommand(NewCmdGet(f)) diff --git a/internal/commands/companyinfo/create.go b/internal/commands/companyinfo/create.go index 2531b68..98c1462 100644 --- a/internal/commands/companyinfo/create.go +++ b/internal/commands/companyinfo/create.go @@ -26,7 +26,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "create", - Short: "Create company info for a sending domain", + Short: "Create company info for a domain", RunE: func(cmd *cobra.Command, args []string) error { required := []struct { flag string @@ -84,7 +84,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { }, } - cmd.Flags().StringVar(&domainID, "domain-id", "", "Sending domain ID (required)") + cmd.Flags().StringVar(&domainID, "domain-id", "", "Domain ID (required)") cmd.Flags().StringVar(&name, "name", "", "Company or individual name (required)") cmd.Flags().StringVar(&address, "address", "", "Street address (required)") cmd.Flags().StringVar(&city, "city", "", "City (required)") diff --git a/internal/commands/companyinfo/get.go b/internal/commands/companyinfo/get.go index d595ef8..2660915 100644 --- a/internal/commands/companyinfo/get.go +++ b/internal/commands/companyinfo/get.go @@ -14,7 +14,7 @@ func NewCmdGet(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "get", - Short: "Get company info for a sending domain", + Short: "Get company info for a domain", RunE: func(cmd *cobra.Command, args []string) error { if err := cmdutil.RequireFlag("domain-id", domainID); err != nil { return err @@ -35,7 +35,7 @@ func NewCmdGet(f *cmdutil.Factory) *cobra.Command { }, } - cmd.Flags().StringVar(&domainID, "domain-id", "", "Sending domain ID (required)") + cmd.Flags().StringVar(&domainID, "domain-id", "", "Domain ID (required)") return cmd } diff --git a/internal/commands/companyinfo/update.go b/internal/commands/companyinfo/update.go index 1722c2a..23ff1d2 100644 --- a/internal/commands/companyinfo/update.go +++ b/internal/commands/companyinfo/update.go @@ -27,7 +27,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "update", - Short: "Update company info for a sending domain", + Short: "Update company info for a domain", RunE: func(cmd *cobra.Command, args []string) error { if err := cmdutil.RequireFlag("domain-id", domainID); err != nil { return err @@ -76,7 +76,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { }, } - cmd.Flags().StringVar(&domainID, "domain-id", "", "Sending domain ID (required)") + cmd.Flags().StringVar(&domainID, "domain-id", "", "Domain ID (required)") cmd.Flags().StringVar(&name, "name", "", "Company or individual name") cmd.Flags().StringVar(&address, "address", "", "Street address") cmd.Flags().StringVar(&city, "city", "", "City") diff --git a/internal/commands/domains/create.go b/internal/commands/domains/create.go index c738aa6..974e37c 100644 --- a/internal/commands/domains/create.go +++ b/internal/commands/domains/create.go @@ -15,7 +15,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "create", - Short: "Create a sending domain", + Short: "Create a domain", RunE: func(cmd *cobra.Command, args []string) error { if err := cmdutil.RequireFlag("name", name); err != nil { return err diff --git a/internal/commands/domains/delete.go b/internal/commands/domains/delete.go index a975b18..bb52967 100644 --- a/internal/commands/domains/delete.go +++ b/internal/commands/domains/delete.go @@ -15,7 +15,7 @@ func NewCmdDelete(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "delete", - Short: "Delete a sending domain", + Short: "Delete a domain", RunE: func(cmd *cobra.Command, args []string) error { if err := cmdutil.RequireFlag("id", domainID); err != nil { return err diff --git a/internal/commands/domains/domains.go b/internal/commands/domains/domains.go index 120640d..d19d5da 100644 --- a/internal/commands/domains/domains.go +++ b/internal/commands/domains/domains.go @@ -8,7 +8,7 @@ import ( func NewCmdDomains(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "domains", - Short: "Manage sending domains", + Short: "Manage domains", } cmd.AddCommand(NewCmdList(f)) diff --git a/internal/commands/domains/get.go b/internal/commands/domains/get.go index 5853d49..bd9f048 100644 --- a/internal/commands/domains/get.go +++ b/internal/commands/domains/get.go @@ -16,7 +16,7 @@ func NewCmdGet(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "get", - Short: "Get a sending domain", + Short: "Get a domain", RunE: func(cmd *cobra.Command, args []string) error { if err := cmdutil.RequireFlag("id", domainID); err != nil { return err diff --git a/internal/commands/domains/list.go b/internal/commands/domains/list.go index 16cfd94..90fef4b 100644 --- a/internal/commands/domains/list.go +++ b/internal/commands/domains/list.go @@ -47,7 +47,7 @@ var domainSettingsColumns = append( func NewCmdList(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "list", - Short: "List all sending domains", + Short: "List all domains", RunE: func(cmd *cobra.Command, args []string) error { c, err := f.NewClient() if err != nil { diff --git a/internal/commands/domains/update.go b/internal/commands/domains/update.go index 0006a42..7b84a47 100644 --- a/internal/commands/domains/update.go +++ b/internal/commands/domains/update.go @@ -23,7 +23,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "update", - Short: "Update a sending domain", + Short: "Update a domain", RunE: func(cmd *cobra.Command, args []string) error { if err := cmdutil.RequireFlag("id", domainID); err != nil { return err diff --git a/internal/commands/emailcampaigns/attributes.go b/internal/commands/emailcampaigns/attributes.go index b137223..271be1c 100644 --- a/internal/commands/emailcampaigns/attributes.go +++ b/internal/commands/emailcampaigns/attributes.go @@ -25,7 +25,7 @@ type campaignAttrs struct { func addAttributeFlags(cmd *cobra.Command, attrs *campaignAttrs) { cmd.Flags().StringVar(&attrs.Name, "name", "", "Campaign name") - cmd.Flags().Int64Var(&attrs.DomainID, "domain-id", 0, "ID of the verified sending domain, as returned by the Sending Domains endpoints") + cmd.Flags().Int64Var(&attrs.DomainID, "domain-id", 0, "ID of the verified domain, as returned by the Domains endpoints") cmd.Flags().StringVar(&attrs.FromDisplayName, "from-display-name", "", "Display name shown in the From header") cmd.Flags().StringVar(&attrs.FromLocalPart, "from-local-part", "", "Local part (before the @) of the From address") cmd.Flags().StringVar(&attrs.ReplyToDisplayName, "reply-to-display-name", "", "Reply-To display name") diff --git a/internal/commands/inbound/inboxes/create.go b/internal/commands/inbound/inboxes/create.go index ea5fd29..f5a0707 100644 --- a/internal/commands/inbound/inboxes/create.go +++ b/internal/commands/inbound/inboxes/create.go @@ -52,7 +52,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { cmd.Flags().StringVar(&folderID, "folder-id", "", "Folder ID (required)") cmd.Flags().StringVar(&name, "name", "", "Inbox name (required)") - cmd.Flags().IntVar(&domainID, "domain-id", 0, "Sending domain ID for a custom-domain (catch-all) inbox") + cmd.Flags().IntVar(&domainID, "domain-id", 0, "Domain ID for a custom-domain (catch-all) inbox") return cmd } diff --git a/internal/commands/sandbox_send/sandbox_send.go b/internal/commands/sandbox_send/sandbox_send.go index b6155b7..f88478d 100644 --- a/internal/commands/sandbox_send/sandbox_send.go +++ b/internal/commands/sandbox_send/sandbox_send.go @@ -12,8 +12,8 @@ import ( func NewCmdSandboxSend(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "sandbox-send", - Short: "Send emails to a Mailtrap sandbox inbox", - Long: "Send single or batch emails to a Mailtrap sandbox inbox for testing.", + Short: "Send emails to a Mailtrap sandbox", + Long: "Send single or batch emails to a Mailtrap sandbox for testing.", } cmd.AddCommand(NewCmdSingle(f)) diff --git a/internal/commands/sandboxes/clean.go b/internal/commands/sandboxes/clean.go index 0d7adfb..0b7d044 100644 --- a/internal/commands/sandboxes/clean.go +++ b/internal/commands/sandboxes/clean.go @@ -11,13 +11,13 @@ import ( ) func NewCmdClean(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "clean", Short: "Clean a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -31,7 +31,7 @@ func NewCmdClean(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID), "clean") + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "clean") if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, nil); err != nil { return err @@ -42,7 +42,7 @@ func NewCmdClean(f *cmdutil.Factory) *cobra.Command { }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/create.go b/internal/commands/sandboxes/create.go index fbb297c..a5399e6 100644 --- a/internal/commands/sandboxes/create.go +++ b/internal/commands/sandboxes/create.go @@ -41,13 +41,13 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { "inbox": map[string]string{"name": name}, } - var inbox Inbox - if err := c.Post(context.Background(), client.BaseGeneral, path, body, &inbox); err != nil { + var sandbox Sandbox + if err := c.Post(context.Background(), client.BaseGeneral, path, body, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } diff --git a/internal/commands/sandboxes/delete.go b/internal/commands/sandboxes/delete.go index f17c146..22b7f51 100644 --- a/internal/commands/sandboxes/delete.go +++ b/internal/commands/sandboxes/delete.go @@ -11,13 +11,13 @@ import ( ) func NewCmdDelete(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "delete", Short: "Delete a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -31,7 +31,7 @@ func NewCmdDelete(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID)) + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID)) if err := c.Delete(context.Background(), client.BaseGeneral, path, nil); err != nil { return err @@ -42,7 +42,7 @@ func NewCmdDelete(f *cmdutil.Factory) *cobra.Command { }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/get.go b/internal/commands/sandboxes/get.go index 58c1515..fac3c00 100644 --- a/internal/commands/sandboxes/get.go +++ b/internal/commands/sandboxes/get.go @@ -12,13 +12,13 @@ import ( ) func NewCmdGet(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "get", Short: "Get a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -32,19 +32,19 @@ func NewCmdGet(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID)) + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID)) - var inbox Inbox - if err := c.Get(context.Background(), client.BaseGeneral, path, nil, &inbox); err != nil { + var sandbox Sandbox + if err := c.Get(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/list.go b/internal/commands/sandboxes/list.go index 95fd6c7..ae3b171 100644 --- a/internal/commands/sandboxes/list.go +++ b/internal/commands/sandboxes/list.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -type Inbox struct { +type Sandbox struct { ID int `json:"id"` Name string `json:"name"` EmailUsername string `json:"email_username"` @@ -18,7 +18,7 @@ type Inbox struct { MaxSize int `json:"max_size"` } -var inboxColumns = []output.Column{ +var sandboxColumns = []output.Column{ {Header: "ID", Field: "id"}, {Header: "NAME", Field: "name"}, {Header: "EMAIL_USERNAME", Field: "email_username"}, @@ -43,13 +43,13 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command { path := cmdutil.AccountPath("inboxes") - var inboxes []Inbox - if err := c.Get(context.Background(), client.BaseGeneral, path, nil, &inboxes); err != nil { + var sandboxes []Sandbox + if err := c.Get(context.Background(), client.BaseGeneral, path, nil, &sandboxes); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inboxes, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandboxes, sandboxColumns) }, } diff --git a/internal/commands/sandboxes/mark_read.go b/internal/commands/sandboxes/mark_read.go index 2fafdd1..cc3a7ab 100644 --- a/internal/commands/sandboxes/mark_read.go +++ b/internal/commands/sandboxes/mark_read.go @@ -12,13 +12,13 @@ import ( ) func NewCmdMarkRead(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "mark-read", Short: "Mark all messages in a sandbox as read", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -32,19 +32,19 @@ func NewCmdMarkRead(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID), "all_read") + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "all_read") - var inbox Inbox - if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &inbox); err != nil { + var sandbox Sandbox + if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/reset_credentials.go b/internal/commands/sandboxes/reset_credentials.go index 7e25434..ac37ab5 100644 --- a/internal/commands/sandboxes/reset_credentials.go +++ b/internal/commands/sandboxes/reset_credentials.go @@ -12,13 +12,13 @@ import ( ) func NewCmdResetCredentials(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "reset-credentials", Short: "Reset SMTP credentials of a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -32,19 +32,19 @@ func NewCmdResetCredentials(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID), "reset_credentials") + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "reset_credentials") - var inbox Inbox - if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &inbox); err != nil { + var sandbox Sandbox + if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/reset_email.go b/internal/commands/sandboxes/reset_email.go index 19159dc..7d1ee96 100644 --- a/internal/commands/sandboxes/reset_email.go +++ b/internal/commands/sandboxes/reset_email.go @@ -12,13 +12,13 @@ import ( ) func NewCmdResetEmail(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "reset-email", Short: "Reset email username of a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -32,19 +32,19 @@ func NewCmdResetEmail(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID), "reset_email_username") + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "reset_email_username") - var inbox Inbox - if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &inbox); err != nil { + var sandbox Sandbox + if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/toggle_email.go b/internal/commands/sandboxes/toggle_email.go index 4b1e92c..5b09645 100644 --- a/internal/commands/sandboxes/toggle_email.go +++ b/internal/commands/sandboxes/toggle_email.go @@ -12,13 +12,13 @@ import ( ) func NewCmdToggleEmail(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string cmd := &cobra.Command{ Use: "toggle-email", Short: "Toggle email username of a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } @@ -32,19 +32,19 @@ func NewCmdToggleEmail(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID), "toggle_email_username") + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "toggle_email_username") - var inbox Inbox - if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &inbox); err != nil { + var sandbox Sandbox + if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") return cmd } diff --git a/internal/commands/sandboxes/update.go b/internal/commands/sandboxes/update.go index 5535e66..5981118 100644 --- a/internal/commands/sandboxes/update.go +++ b/internal/commands/sandboxes/update.go @@ -12,14 +12,14 @@ import ( ) func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { - var inboxID string + var sandboxID string var name string cmd := &cobra.Command{ Use: "update", Short: "Update a sandbox", RunE: func(cmd *cobra.Command, args []string) error { - if err := cmdutil.RequireFlag("id", inboxID); err != nil { + if err := cmdutil.RequireFlag("id", sandboxID); err != nil { return err } if err := cmdutil.RequireFlag("name", name); err != nil { @@ -36,22 +36,22 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", inboxID)) + path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID)) body := map[string]interface{}{ "inbox": map[string]string{"name": name}, } - var inbox Inbox - if err := c.Patch(context.Background(), client.BaseGeneral, path, body, &inbox); err != nil { + var sandbox Sandbox + if err := c.Patch(context.Background(), client.BaseGeneral, path, body, &sandbox); err != nil { return err } format := cmdutil.GetOutputFormat() - return output.Print(f.IOStreams.Out, format, inbox, inboxColumns) + return output.Print(f.IOStreams.Out, format, sandbox, sandboxColumns) }, } - cmd.Flags().StringVar(&inboxID, "id", "", "Sandbox ID") + cmd.Flags().StringVar(&sandboxID, "id", "", "Sandbox ID") cmd.Flags().StringVar(&name, "name", "", "Sandbox name") return cmd diff --git a/internal/commands/stats/get.go b/internal/commands/stats/get.go index fbc926c..af294ee 100644 --- a/internal/commands/stats/get.go +++ b/internal/commands/stats/get.go @@ -43,25 +43,25 @@ var statsColumns = []output.Column{ // MarshalJSON on each type flattens the nested stats for table/text output. type DomainStats struct { - SendingDomainID int `json:"sending_domain_id"` - Stats Stats `json:"stats"` + DomainID int `json:"sending_domain_id"` + Stats Stats `json:"stats"` } func (d DomainStats) MarshalJSON() ([]byte, error) { type flat struct { - SendingDomainID int `json:"sending_domain_id"` - DeliveryCount int `json:"delivery_count"` - DeliveryRate float64 `json:"delivery_rate"` - BounceCount int `json:"bounce_count"` - BounceRate float64 `json:"bounce_rate"` - OpenCount int `json:"open_count"` - OpenRate float64 `json:"open_rate"` - ClickCount int `json:"click_count"` - ClickRate float64 `json:"click_rate"` - SpamCount int `json:"spam_count"` - SpamRate float64 `json:"spam_rate"` + DomainID int `json:"sending_domain_id"` + DeliveryCount int `json:"delivery_count"` + DeliveryRate float64 `json:"delivery_rate"` + BounceCount int `json:"bounce_count"` + BounceRate float64 `json:"bounce_rate"` + OpenCount int `json:"open_count"` + OpenRate float64 `json:"open_rate"` + ClickCount int `json:"click_count"` + ClickRate float64 `json:"click_rate"` + SpamCount int `json:"spam_count"` + SpamRate float64 `json:"spam_rate"` } - return json.Marshal(flat{d.SendingDomainID, d.Stats.DeliveryCount, d.Stats.DeliveryRate, d.Stats.BounceCount, d.Stats.BounceRate, d.Stats.OpenCount, d.Stats.OpenRate, d.Stats.ClickCount, d.Stats.ClickRate, d.Stats.SpamCount, d.Stats.SpamRate}) + return json.Marshal(flat{d.DomainID, d.Stats.DeliveryCount, d.Stats.DeliveryRate, d.Stats.BounceCount, d.Stats.BounceRate, d.Stats.OpenCount, d.Stats.OpenRate, d.Stats.ClickCount, d.Stats.ClickRate, d.Stats.SpamCount, d.Stats.SpamRate}) } var domainStatsColumns = []output.Column{ diff --git a/internal/commands/suppressions/create.go b/internal/commands/suppressions/create.go index 6d9b6e8..851ad79 100644 --- a/internal/commands/suppressions/create.go +++ b/internal/commands/suppressions/create.go @@ -70,7 +70,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { } cmd.Flags().StringVar(&email, "email", "", "Email address to suppress (required)") - cmd.Flags().Int64Var(&domainID, "domain-id", 0, "ID of the sending domain the suppression applies to (required)") + cmd.Flags().Int64Var(&domainID, "domain-id", 0, "ID of the domain the suppression applies to (required)") cmd.Flags().StringVar(&sendingStream, "sending-stream", "", "Sending stream to suppress for: transactional, bulk (required)") cmd.Flags().StringVar(&suppressType, "type", "", "Suppression reason: hard bounce, spam complaint, unsubscription, manual import") diff --git a/internal/commands/tokens/create.go b/internal/commands/tokens/create.go index 9634d38..8a1bcc8 100644 --- a/internal/commands/tokens/create.go +++ b/internal/commands/tokens/create.go @@ -23,7 +23,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { Long: `Create an API token with permissions. Permissions must be provided as a JSON array. Each entry requires: - - resource_type: "account", "project", "inbox", or "sending_domain" + - resource_type: "account", "project", "inbox" (a sandbox), or "sending_domain" (a domain) - resource_id: the resource ID (integer) - access_level: 10 (viewer) or 100 (admin) diff --git a/internal/commands/trackingoptouts/create.go b/internal/commands/trackingoptouts/create.go index 2a9c6ea..4d0672d 100644 --- a/internal/commands/trackingoptouts/create.go +++ b/internal/commands/trackingoptouts/create.go @@ -55,7 +55,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { } cmd.Flags().StringVar(&email, "email", "", "Email address to opt out of tracking (required)") - cmd.Flags().Int64Var(&domainID, "domain-id", 0, "ID of the sending domain the opt-out applies to (required)") + cmd.Flags().Int64Var(&domainID, "domain-id", 0, "ID of the domain the opt-out applies to (required)") return cmd } diff --git a/skills/mailtrap-cli/SKILL.md b/skills/mailtrap-cli/SKILL.md index dc6cb21..633170c 100644 --- a/skills/mailtrap-cli/SKILL.md +++ b/skills/mailtrap-cli/SKILL.md @@ -1,7 +1,7 @@ # Mailtrap CLI Skill The `mailtrap` CLI is the official command-line interface for the Mailtrap email platform. -It covers transactional/bulk email sending, sandbox testing, domain management, templates, +It covers transactional/bulk email sending, sandboxes, domain management, templates, contacts, statistics, and account administration. ## Authentication @@ -50,6 +50,7 @@ A `null` cursor means there are no more pages. `suppressions list` and `messages - **Batch operations**: use `--file path/to/payload.json` with a JSON array of email objects - **Config priority**: CLI flags > environment variables > config file - **Exit codes**: 0 on success, 1 on error (with descriptive message) +- **Naming**: sandboxes were formerly called inboxes, and domains were sending domains. A user asking about an "inbox" usually means a sandbox (`sandboxes`, `--sandbox-id`) unless they mean Email Inbound (`inbound`). API paths, JSON keys and token resource types keep the old names (`/inboxes`, `sending_domain_id`, `"inbox"`, `"sending_domain"`) - **API base**: most requests go to `https://mailtrap.io/api/accounts/{account-id}/...`. Several groups do not and take no `--account-id`: `inbound` (`/api/inbound/...`), `company-info` (`/api/domains/{domain-id}/company_info`), `tracking-opt-outs` (`/api/tracking_opt_outs`), `email-campaigns` (`/api/email_campaigns`) and `organizations` (`/api/organizations/...`). `send` and `sandbox-send` go to their own hosts entirely. ## Command Groups @@ -57,8 +58,8 @@ A `null` cursor means there are no more pages. `suppressions list` and `messages | Group | Purpose | Reference | |-------|---------|-----------| | `send` | Transactional & bulk email sending | [sending.md](references/sending.md) | -| `domains` | Sending domain management | [domains.md](references/domains.md) | -| `company-info` | Sending domain company info for compliance verification | [domains.md](references/domains.md) | +| `domains` | Domain management | [domains.md](references/domains.md) | +| `company-info` | Domain company info for compliance verification | [domains.md](references/domains.md) | | `templates` | Email template CRUD | [templates.md](references/templates.md) | | `stats` | Aggregated sending statistics | [email-logs.md](references/email-logs.md) | | `email-logs` | Individual email log lookup | [email-logs.md](references/email-logs.md) | @@ -66,7 +67,7 @@ A `null` cursor means there are no more pages. `suppressions list` and `messages | `contacts` | Contact management & import/export | [contacts.md](references/contacts.md) | | `contact-lists` | Contact list CRUD | [contacts.md](references/contacts.md) | | `contact-fields` | Custom contact fields | [contacts.md](references/contacts.md) | -| `sandbox-send` | Sandbox email testing | [sandbox.md](references/sandbox.md) | +| `sandbox-send` | Sending emails to a sandbox | [sandbox.md](references/sandbox.md) | | `projects` | Sandbox project management | [sandbox.md](references/sandbox.md) | | `sandboxes` | Sandbox management | [sandbox.md](references/sandbox.md) | | `messages` | Sandbox message inspection | [sandbox.md](references/sandbox.md) | diff --git a/skills/mailtrap-cli/references/domains.md b/skills/mailtrap-cli/references/domains.md index 2d1729f..42a06d5 100644 --- a/skills/mailtrap-cli/references/domains.md +++ b/skills/mailtrap-cli/references/domains.md @@ -6,7 +6,7 @@ Detailed flag specifications for `mailtrap domains`, `mailtrap company-info`, `m ## domains list -List all sending domains for the account. +List all domains for the account. No additional flags. Uses `--account-id` from global config. @@ -16,7 +16,7 @@ No additional flags. Uses `--account-id` from global config. ## domains get -Retrieve details of a specific sending domain. +Retrieve details of a specific domain. | Flag | Type | Required | Description | |------|------|----------|-------------| @@ -26,7 +26,7 @@ Retrieve details of a specific sending domain. ## domains create -Register a new sending domain. +Register a new domain. | Flag | Type | Required | Description | |------|------|----------|-------------| @@ -38,7 +38,7 @@ Register a new sending domain. ## domains update -Update the tracking and inbound settings of a sending domain. +Update the tracking and inbound settings of a domain. | Flag | Type | Required | Description | |------|------|----------|-------------| @@ -55,7 +55,7 @@ Only the flags actually passed are sent, so a partial update leaves the other se ## domains delete -Delete a sending domain. +Delete a domain. | Flag | Type | Required | Description | |------|------|----------|-------------| @@ -65,11 +65,11 @@ Delete a sending domain. ## company-info get -Retrieve the company info of a sending domain, used for domain compliance verification. +Retrieve the company info of a domain, used for domain compliance verification. | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--domain-id` | string | Yes | Sending domain ID | +| `--domain-id` | string | Yes | Domain ID | **Note:** Uses the API token's account; `--account-id` is not needed. @@ -77,11 +77,11 @@ Retrieve the company info of a sending domain, used for domain compliance verifi ## company-info create -Set the company info of a sending domain. +Set the company info of a domain. | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--domain-id` | string | Yes | Sending domain ID | +| `--domain-id` | string | Yes | Domain ID | | `--name` | string | Yes | Company or individual name | | `--address` | string | Yes | Street address | | `--city` | string | Yes | City | @@ -97,7 +97,7 @@ Set the company info of a sending domain. ## company-info update -Change the company info of a sending domain. +Change the company info of a domain. Takes the same flags as `company-info create`, all optional except `--domain-id`. Only the flags actually passed are sent, so a partial update leaves the other fields alone. An update with no attribute flags is rejected rather than sent as an empty payload. @@ -125,7 +125,7 @@ Add an address to the suppression list. | Flag | Type | Required | Description | |------|------|----------|-------------| | `--email` | string | Yes | Email address to suppress | -| `--domain-id` | int | Yes | Sending domain the suppression applies to | +| `--domain-id` | int | Yes | Domain the suppression applies to | | `--sending-stream` | string | Yes | `transactional` or `bulk` | | `--type` | string | No | Suppression reason: `hard bounce`, `spam complaint`, `unsubscription`, `manual import`. Defaults to `manual import` | @@ -165,7 +165,7 @@ Exclude an address from open and click tracking. | Flag | Type | Required | Description | |------|------|----------|-------------| | `--email` | string | Yes | Email address to opt out | -| `--domain-id` | int | Yes | Sending domain the opt-out applies to | +| `--domain-id` | int | Yes | Domain the opt-out applies to | --- diff --git a/skills/mailtrap-cli/references/email-logs.md b/skills/mailtrap-cli/references/email-logs.md index 8556d9a..feb8c49 100644 --- a/skills/mailtrap-cli/references/email-logs.md +++ b/skills/mailtrap-cli/references/email-logs.md @@ -69,7 +69,7 @@ mailtrap stats get \ ## stats by-domain -Get statistics grouped by sending domain. +Get statistics grouped by domain. Same flags as `stats get`. diff --git a/skills/mailtrap-cli/references/error-codes.md b/skills/mailtrap-cli/references/error-codes.md index ac1e9dd..d3fc27e 100644 --- a/skills/mailtrap-cli/references/error-codes.md +++ b/skills/mailtrap-cli/references/error-codes.md @@ -11,7 +11,7 @@ Common API errors and their meanings when using the Mailtrap CLI. | 400 | Bad Request | Invalid flag values, malformed JSON in `--file`, missing required fields | | 401 | Unauthorized | Invalid or expired API token | | 403 | Forbidden | Token lacks permissions for this action | -| 404 | Not Found | Invalid resource ID (domain, template, inbox, message, etc.) | +| 404 | Not Found | Invalid resource ID (domain, template, sandbox, message, etc.) | | 422 | Unprocessable Entity | Validation error (e.g. duplicate domain, invalid email format) | | 429 | Too Many Requests | Rate limit exceeded — wait and retry | | 500 | Internal Server Error | Mailtrap server issue — retry later | diff --git a/skills/mailtrap-cli/references/inbound.md b/skills/mailtrap-cli/references/inbound.md index e9285c5..b5f8595 100644 --- a/skills/mailtrap-cli/references/inbound.md +++ b/skills/mailtrap-cli/references/inbound.md @@ -72,7 +72,7 @@ Inboxes are managed within a folder. |------|------|----------|-------------| | `--folder-id` | string | Yes | Folder ID | | `--name` | string | Yes | Inbox name | -| `--domain-id` | int | No | Sending domain ID for a custom-domain (catch-all) inbox; omit for a Mailtrap-hosted inbox | +| `--domain-id` | int | No | Domain ID for a custom-domain (catch-all) inbox; omit for a Mailtrap-hosted inbox | --- From 60c35af2e4ec4f7d1c841961a056566ce935600d Mon Sep 17 00:00:00 2001 From: Maciej Walusiak Date: Tue, 3 Nov 2026 11:03:05 +0100 Subject: [PATCH 2/3] Clarify the inbound webhook inbox flag and drop no-op Sprintf calls Decisions: - --inbound-inbox-id help said only "Inbox ID", which the skill's new naming note maps to a sandbox; name the Email Inbound product instead - fmt.Sprintf("%s", id) did nothing on the sandbox ID lines this change already renames - the test plan prerequisite said "sandbox" three times in one line Co-Authored-By: Claude Opus 5.5 --- docs/TEST_PLAN.md | 2 +- internal/commands/sandboxes/clean.go | 2 +- internal/commands/sandboxes/create.go | 3 +-- internal/commands/sandboxes/delete.go | 2 +- internal/commands/sandboxes/get.go | 3 +-- internal/commands/sandboxes/mark_read.go | 3 +-- internal/commands/sandboxes/reset_credentials.go | 3 +-- internal/commands/sandboxes/reset_email.go | 3 +-- internal/commands/sandboxes/toggle_email.go | 3 +-- internal/commands/sandboxes/update.go | 3 +-- internal/commands/webhooks/create.go | 2 +- internal/commands/webhooks/update.go | 2 +- 12 files changed, 12 insertions(+), 19 deletions(-) diff --git a/docs/TEST_PLAN.md b/docs/TEST_PLAN.md index 6259c49..0357be4 100644 --- a/docs/TEST_PLAN.md +++ b/docs/TEST_PLAN.md @@ -26,7 +26,7 @@ export MAILTRAP_API_TOKEN=your-token Before running integration tests, ensure you have: - A Mailtrap account with API access - A verified **domain** for transactional/bulk send tests -- At least one **sandbox project** with a **sandbox** for sandbox tests +- At least one **project** with a **sandbox** for sandbox tests - Note down your **sandbox ID** for sandbox send tests ### 3. Build the CLI diff --git a/internal/commands/sandboxes/clean.go b/internal/commands/sandboxes/clean.go index 0b7d044..e1047d1 100644 --- a/internal/commands/sandboxes/clean.go +++ b/internal/commands/sandboxes/clean.go @@ -31,7 +31,7 @@ func NewCmdClean(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "clean") + path := cmdutil.AccountPath("inboxes", sandboxID, "clean") if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, nil); err != nil { return err diff --git a/internal/commands/sandboxes/create.go b/internal/commands/sandboxes/create.go index a5399e6..c6d43de 100644 --- a/internal/commands/sandboxes/create.go +++ b/internal/commands/sandboxes/create.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -36,7 +35,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("projects", fmt.Sprintf("%s", projectID), "inboxes") + path := cmdutil.AccountPath("projects", projectID, "inboxes") body := map[string]interface{}{ "inbox": map[string]string{"name": name}, } diff --git a/internal/commands/sandboxes/delete.go b/internal/commands/sandboxes/delete.go index 22b7f51..d38d04d 100644 --- a/internal/commands/sandboxes/delete.go +++ b/internal/commands/sandboxes/delete.go @@ -31,7 +31,7 @@ func NewCmdDelete(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID)) + path := cmdutil.AccountPath("inboxes", sandboxID) if err := c.Delete(context.Background(), client.BaseGeneral, path, nil); err != nil { return err diff --git a/internal/commands/sandboxes/get.go b/internal/commands/sandboxes/get.go index fac3c00..0ddb735 100644 --- a/internal/commands/sandboxes/get.go +++ b/internal/commands/sandboxes/get.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -32,7 +31,7 @@ func NewCmdGet(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID)) + path := cmdutil.AccountPath("inboxes", sandboxID) var sandbox Sandbox if err := c.Get(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { diff --git a/internal/commands/sandboxes/mark_read.go b/internal/commands/sandboxes/mark_read.go index cc3a7ab..d90017c 100644 --- a/internal/commands/sandboxes/mark_read.go +++ b/internal/commands/sandboxes/mark_read.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -32,7 +31,7 @@ func NewCmdMarkRead(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "all_read") + path := cmdutil.AccountPath("inboxes", sandboxID, "all_read") var sandbox Sandbox if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { diff --git a/internal/commands/sandboxes/reset_credentials.go b/internal/commands/sandboxes/reset_credentials.go index ac37ab5..50d153f 100644 --- a/internal/commands/sandboxes/reset_credentials.go +++ b/internal/commands/sandboxes/reset_credentials.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -32,7 +31,7 @@ func NewCmdResetCredentials(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "reset_credentials") + path := cmdutil.AccountPath("inboxes", sandboxID, "reset_credentials") var sandbox Sandbox if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { diff --git a/internal/commands/sandboxes/reset_email.go b/internal/commands/sandboxes/reset_email.go index 7d1ee96..7d40178 100644 --- a/internal/commands/sandboxes/reset_email.go +++ b/internal/commands/sandboxes/reset_email.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -32,7 +31,7 @@ func NewCmdResetEmail(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "reset_email_username") + path := cmdutil.AccountPath("inboxes", sandboxID, "reset_email_username") var sandbox Sandbox if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { diff --git a/internal/commands/sandboxes/toggle_email.go b/internal/commands/sandboxes/toggle_email.go index 5b09645..cff1b87 100644 --- a/internal/commands/sandboxes/toggle_email.go +++ b/internal/commands/sandboxes/toggle_email.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -32,7 +31,7 @@ func NewCmdToggleEmail(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID), "toggle_email_username") + path := cmdutil.AccountPath("inboxes", sandboxID, "toggle_email_username") var sandbox Sandbox if err := c.Patch(context.Background(), client.BaseGeneral, path, nil, &sandbox); err != nil { diff --git a/internal/commands/sandboxes/update.go b/internal/commands/sandboxes/update.go index 5981118..c977354 100644 --- a/internal/commands/sandboxes/update.go +++ b/internal/commands/sandboxes/update.go @@ -2,7 +2,6 @@ package sandboxes import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -36,7 +35,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("inboxes", fmt.Sprintf("%s", sandboxID)) + path := cmdutil.AccountPath("inboxes", sandboxID) body := map[string]interface{}{ "inbox": map[string]string{"name": name}, } diff --git a/internal/commands/webhooks/create.go b/internal/commands/webhooks/create.go index f54d9ad..8a5b197 100644 --- a/internal/commands/webhooks/create.go +++ b/internal/commands/webhooks/create.go @@ -97,7 +97,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command { cmd.Flags().StringVar(&sendingStream, "sending-stream", "", "Sending stream: transactional, bulk") cmd.Flags().StringSliceVar(&eventTypes, "event-types", nil, "Event types (comma-separated): delivery, soft_bounce, bounce, suspension, unsubscribe, open, spam_complaint, click, reject") cmd.Flags().IntVar(&domainID, "domain-id", 0, "Domain ID to scope the webhook to (email_sending and campaigns)") - cmd.Flags().IntVar(&inboundInboxID, "inbound-inbox-id", 0, "Inbox ID to scope the webhook to (inbound_receiving only; omit to apply to all inboxes)") + cmd.Flags().IntVar(&inboundInboxID, "inbound-inbox-id", 0, "Email Inbound inbox ID to scope the webhook to (inbound_receiving only; omit to apply to all inboxes)") return cmd } diff --git a/internal/commands/webhooks/update.go b/internal/commands/webhooks/update.go index 4be0afc..331d815 100644 --- a/internal/commands/webhooks/update.go +++ b/internal/commands/webhooks/update.go @@ -73,7 +73,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command { cmd.Flags().BoolVar(&active, "active", true, "Whether the webhook is active") cmd.Flags().StringVar(&payloadFormat, "payload-format", "", "Payload format: json, jsonlines") cmd.Flags().StringSliceVar(&eventTypes, "event-types", nil, "Event types (comma-separated): delivery, soft_bounce, bounce, suspension, unsubscribe, open, spam_complaint, click, reject") - cmd.Flags().IntVar(&inboundInboxID, "inbound-inbox-id", 0, "Inbox ID to scope the webhook to (inbound_receiving only)") + cmd.Flags().IntVar(&inboundInboxID, "inbound-inbox-id", 0, "Email Inbound inbox ID to scope the webhook to (inbound_receiving only)") return cmd } From f25d0315683b317a1b5a792c0585bef6658a2184 Mon Sep 17 00:00:00 2001 From: Maciej Walusiak Date: Tue, 3 Nov 2026 12:30:24 +0100 Subject: [PATCH 3/3] Fix sandbox command names in the test plan and drop no-op Sprintf in domains Test plan rows 12.7 and 12.8 named toggle-email-username and reset-email-username, which don't exist; the commands are toggle-email and reset-email. domains get and delete now pass the ID straight to AccountPath, as the sandboxes commands in this branch already do. Co-Authored-By: Claude Opus 5.5 --- docs/TEST_PLAN.md | 4 ++-- internal/commands/domains/delete.go | 2 +- internal/commands/domains/get.go | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/TEST_PLAN.md b/docs/TEST_PLAN.md index 0357be4..09fe73e 100644 --- a/docs/TEST_PLAN.md +++ b/docs/TEST_PLAN.md @@ -232,8 +232,8 @@ Tests are organized by endpoint group. Each test specifies: | 12.4 | Update sandbox | `mailtrap sandboxes update --id --name "test-sandbox-updated"` | Updated name | | 12.5 | Mark read | `mailtrap sandboxes mark-read --id ` | Success message | | 12.6 | Reset credentials | `mailtrap sandboxes reset-credentials --id ` | Success/new credentials | -| 12.7 | Toggle email username | `mailtrap sandboxes toggle-email-username --id ` | Toggled response | -| 12.8 | Reset email username | `mailtrap sandboxes reset-email-username --id ` | Reset response | +| 12.7 | Toggle email username | `mailtrap sandboxes toggle-email --id ` | Toggled response | +| 12.8 | Reset email username | `mailtrap sandboxes reset-email --id ` | Reset response | | 12.9 | Clean sandbox | `mailtrap sandboxes clean --id ` | Success message | | 12.10 | Delete sandbox | `mailtrap sandboxes delete --id ` | Success message | | 12.11 | Get missing ID | `mailtrap sandboxes get` | Error: `--id is required` | diff --git a/internal/commands/domains/delete.go b/internal/commands/domains/delete.go index bb52967..89cae46 100644 --- a/internal/commands/domains/delete.go +++ b/internal/commands/domains/delete.go @@ -31,7 +31,7 @@ func NewCmdDelete(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("sending_domains", fmt.Sprintf("%s", domainID)) + path := cmdutil.AccountPath("sending_domains", domainID) if err := c.Delete(context.Background(), client.BaseGeneral, path, nil); err != nil { return err diff --git a/internal/commands/domains/get.go b/internal/commands/domains/get.go index bd9f048..8a692c4 100644 --- a/internal/commands/domains/get.go +++ b/internal/commands/domains/get.go @@ -2,7 +2,6 @@ package domains import ( "context" - "fmt" "github.com/mailtrap/mailtrap-cli/internal/client" "github.com/mailtrap/mailtrap-cli/internal/cmdutil" @@ -32,7 +31,7 @@ func NewCmdGet(f *cmdutil.Factory) *cobra.Command { return err } - path := cmdutil.AccountPath("sending_domains", fmt.Sprintf("%s", domainID)) + path := cmdutil.AccountPath("sending_domains", domainID) var domain Domain if err := c.Get(context.Background(), client.BaseGeneral, path, nil, &domain); err != nil {