From 9edb340f37a412bf9211ff179904e1216522e29f Mon Sep 17 00:00:00 2001 From: Alex Shchyhol Date: Tue, 8 Sep 2026 11:01:23 +0200 Subject: [PATCH 1/5] add sub account deletion --- lib/mailtrap/sub_accounts_api.rb | 13 ++++ .../_delete/returns_nil_on_success.yml | 65 +++++++++++++++++ .../raises_not_found_error.yml | 71 +++++++++++++++++++ spec/mailtrap/sub_accounts_api_spec.rb | 22 ++++++ 4 files changed, 171 insertions(+) create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/when_sub_account_does_not_exist/raises_not_found_error.yml diff --git a/lib/mailtrap/sub_accounts_api.rb b/lib/mailtrap/sub_accounts_api.rb index e71ceec6..5bf2f465 100644 --- a/lib/mailtrap/sub_accounts_api.rb +++ b/lib/mailtrap/sub_accounts_api.rb @@ -40,6 +40,19 @@ def create(options) base_create(options) end + # Permanently deletes a sub account under the organization + # + # Requires sub account management permissions for the organization. The deletion is permanent + # and removes all data of the sub account. Deleting the last sub account also deletes the organization. + # A repeated call for the same sub account returns a 404 error. + # Rate limit: 10 requests per minute per organization. + # @param sub_account_id [Integer] The sub account ID + # @return nil + # @!macro api_errors + def delete(sub_account_id) + base_delete(sub_account_id) + end + private def base_path diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml b/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml new file mode 100644 index 00000000..1b4271f1 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml @@ -0,0 +1,65 @@ +--- +http_interactions: +- request: + method: delete + uri: https://mailtrap.io/api/organizations/2222222/sub_accounts/2704237 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - mailtrap-ruby (https://github.com/mailtrap/mailtrap-ruby) + Host: + - mailtrap.io + Authorization: + - Bearer + Content-Type: + - application/json + response: + status: + code: 204 + message: No Content + headers: + Date: + - Tue, 08 Sep 2026 10:00:00 GMT + Connection: + - keep-alive + Server: + - cloudflare + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Mailtrap-Version: + - v2 + X-Ratelimit-Limit: + - '10' + X-Ratelimit-Remaining: + - '9' + Cache-Control: + - no-cache + X-Runtime: + - '0.091243' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: UTF-8 + string: '' + recorded_at: Tue, 08 Sep 2026 10:00:00 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/when_sub_account_does_not_exist/raises_not_found_error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/when_sub_account_does_not_exist/raises_not_found_error.yml new file mode 100644 index 00000000..19aeba84 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/when_sub_account_does_not_exist/raises_not_found_error.yml @@ -0,0 +1,71 @@ +--- +http_interactions: +- request: + method: delete + uri: https://mailtrap.io/api/organizations/2222222/sub_accounts/-1 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - mailtrap-ruby (https://github.com/mailtrap/mailtrap-ruby) + Host: + - mailtrap.io + Authorization: + - Bearer + Content-Type: + - application/json + response: + status: + code: 404 + message: Not Found + headers: + Date: + - Tue, 08 Sep 2026 10:00:01 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '21' + Connection: + - keep-alive + Server: + - cloudflare + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Vary: + - Accept + X-Mailtrap-Version: + - v2 + X-Ratelimit-Limit: + - '10' + X-Ratelimit-Remaining: + - '8' + Cache-Control: + - no-cache + X-Runtime: + - '0.020318' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: UTF-8 + string: '{"error":"Not Found"}' + recorded_at: Tue, 08 Sep 2026 10:00:01 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/mailtrap/sub_accounts_api_spec.rb b/spec/mailtrap/sub_accounts_api_spec.rb index e364d506..1cd99d5a 100644 --- a/spec/mailtrap/sub_accounts_api_spec.rb +++ b/spec/mailtrap/sub_accounts_api_spec.rb @@ -54,4 +54,26 @@ end end end + + describe '#delete' do + subject(:delete) { sub_accounts_api.delete(sub_account_id) } + + let(:sub_account_id) { 2_704_237 } + + it 'returns nil on success' do + expect(delete).to be_nil + end + + context 'when sub account does not exist' do + let(:sub_account_id) { -1 } + + it 'raises not found error' do + expect { delete }.to raise_error do |error| + expect(error).to be_a(Mailtrap::Error) + expect(error.message).to include('Not Found') + expect(error.messages.any? { |msg| msg.include?('Not Found') }).to be true + end + end + end + end end From 2f30256936d18ab7d03040a391b1dfef3b4c23e4 Mon Sep 17 00:00:00 2001 From: Alex Shchyhol Date: Tue, 8 Sep 2026 11:01:24 +0200 Subject: [PATCH 2/5] document sub account deletion in the example and README --- README.md | 1 + examples/sub_accounts_api.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 562275ef..65d8c29c 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,7 @@ General: - API Tokens API – [`api_tokens_api.rb`](examples/api_tokens_api.rb) - Billing API – [`billing_api.rb`](examples/billing_api.rb) - Permissions API – [`permissions_api.rb`](examples/permissions_api.rb) +- Sub Accounts API (list, create, delete) – [`sub_accounts_api.rb`](examples/sub_accounts_api.rb) - Templates API (experimental) – [`templates_api.rb`](examples/templates_api.rb) - Email Templates API – [`email_templates_api.rb`](examples/email_templates_api.rb) - Action Mailer – [`action_mailer.rb`](examples/action_mailer.rb) diff --git a/examples/sub_accounts_api.rb b/examples/sub_accounts_api.rb index f24790f0..30df0573 100644 --- a/examples/sub_accounts_api.rb +++ b/examples/sub_accounts_api.rb @@ -11,3 +11,7 @@ # Create a new sub account sub_accounts.create(name: 'New Team Account') # => # + +# Delete a sub account +sub_accounts.delete(12_347) +# => nil From ef86f98b60d431f67769816c9b219f5eaeb16e06 Mon Sep 17 00:00:00 2001 From: Alex Shchyhol Date: Wed, 4 Nov 2026 11:46:16 +0100 Subject: [PATCH 3/5] update the permission note for deleting a sub-account --- lib/mailtrap/sub_accounts_api.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mailtrap/sub_accounts_api.rb b/lib/mailtrap/sub_accounts_api.rb index 5bf2f465..d5311701 100644 --- a/lib/mailtrap/sub_accounts_api.rb +++ b/lib/mailtrap/sub_accounts_api.rb @@ -42,7 +42,7 @@ def create(options) # Permanently deletes a sub account under the organization # - # Requires sub account management permissions for the organization. The deletion is permanent + # Requires organization admin permissions. The deletion is permanent # and removes all data of the sub account. Deleting the last sub account also deletes the organization. # A repeated call for the same sub account returns a 404 error. # Rate limit: 10 requests per minute per organization. From 623b4a8c1d3ed924df22a0268a66e94d32d17de1 Mon Sep 17 00:00:00 2001 From: Alex Shchyhol Date: Thu, 5 Nov 2026 18:07:22 +0100 Subject: [PATCH 4/5] delete a sub account the spec creates itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The success example deleted a fixed, existing sub account, so re-recording its cassette against the live API would delete a real account – possibly the last one in the organization. It now creates a throwaway sub account and deletes that. --- .../_delete/returns_nil_on_success.yml | 74 ++++++++++++++++++- spec/mailtrap/sub_accounts_api_spec.rb | 4 +- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml b/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml index 1b4271f1..92e72a71 100644 --- a/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml +++ b/spec/fixtures/vcr_cassettes/Mailtrap_SubAccountsAPI/_delete/returns_nil_on_success.yml @@ -1,8 +1,76 @@ --- http_interactions: +- request: + method: post + uri: https://mailtrap.io/api/organizations/2222222/sub_accounts + body: + encoding: UTF-8 + string: '{"account":{"name":"SDK Delete Test Sub Account"}}' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - mailtrap-ruby (https://github.com/mailtrap/mailtrap-ruby) + Host: + - mailtrap.io + Authorization: + - Bearer + Content-Type: + - application/json + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 05 Nov 2026 10:00:00 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '51' + Connection: + - keep-alive + Server: + - cloudflare + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Vary: + - Accept + X-Mailtrap-Version: + - v2 + X-Ratelimit-Limit: + - '150' + X-Ratelimit-Remaining: + - '149' + Cache-Control: + - max-age=0, private, must-revalidate + X-Runtime: + - '0.853483' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: UTF-8 + string: '{"id":3333333,"name":"SDK Delete Test Sub Account"}' + recorded_at: Thu, 05 Nov 2026 10:00:00 GMT - request: method: delete - uri: https://mailtrap.io/api/organizations/2222222/sub_accounts/2704237 + uri: https://mailtrap.io/api/organizations/2222222/sub_accounts/3333333 body: encoding: US-ASCII string: '' @@ -25,7 +93,7 @@ http_interactions: message: No Content headers: Date: - - Tue, 08 Sep 2026 10:00:00 GMT + - Thu, 05 Nov 2026 10:00:01 GMT Connection: - keep-alive Server: @@ -61,5 +129,5 @@ http_interactions: body: encoding: UTF-8 string: '' - recorded_at: Tue, 08 Sep 2026 10:00:00 GMT + recorded_at: Thu, 05 Nov 2026 10:00:01 GMT recorded_with: VCR 6.4.0 diff --git a/spec/mailtrap/sub_accounts_api_spec.rb b/spec/mailtrap/sub_accounts_api_spec.rb index 1cd99d5a..d4d2b2f3 100644 --- a/spec/mailtrap/sub_accounts_api_spec.rb +++ b/spec/mailtrap/sub_accounts_api_spec.rb @@ -58,7 +58,9 @@ describe '#delete' do subject(:delete) { sub_accounts_api.delete(sub_account_id) } - let(:sub_account_id) { 2_704_237 } + # Deletes a sub account the example creates itself. When the cassette is re-recorded against + # the live API, no existing sub account gets deleted, and the organization keeps its accounts. + let(:sub_account_id) { sub_accounts_api.create(name: 'SDK Delete Test Sub Account').id } it 'returns nil on success' do expect(delete).to be_nil From 7cf62a53a353e07d0e1604f4b3b3beede4fa9e73 Mon Sep 17 00:00:00 2001 From: Alex Shchyhol Date: Thu, 5 Nov 2026 18:07:22 +0100 Subject: [PATCH 5/5] delete the created sub account in the example --- examples/sub_accounts_api.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/sub_accounts_api.rb b/examples/sub_accounts_api.rb index 30df0573..d0f2261b 100644 --- a/examples/sub_accounts_api.rb +++ b/examples/sub_accounts_api.rb @@ -9,9 +9,9 @@ # => [#, ...] # Create a new sub account -sub_accounts.create(name: 'New Team Account') +sub_account = sub_accounts.create(name: 'New Team Account') # => # -# Delete a sub account -sub_accounts.delete(12_347) +# Delete the sub account +sub_accounts.delete(sub_account.id) # => nil