Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- Add Sandbox Messages API
- Add Sending Domains API
- Add Sandbox Attachments API
- Add Accounts API

## [2.6.0] - 2026-01-27
- Add Inboxes API
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,11 @@ Contact management:

- Contacts CRUD & Listing – [`contacts_api.rb`](examples/contacts_api.rb)

General API:
General:

- Templates CRUD – [`email_templates_api.rb`](examples/email_templates_api.rb)
- Action Mailer – [`action_mailer.rb`](examples/action_mailer.rb)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you wanted to fix "Action Mailer", didnt you?

- Accounts API – [`accounts_api.rb`](examples/accounts_api.rb)

## Migration guide v1 → v2

Expand Down
13 changes: 13 additions & 0 deletions examples/accounts_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require 'mailtrap'

client = Mailtrap::Client.new(api_key: 'your-api-key')
accounts = Mailtrap::AccountsAPI.new(client)

# Set your API credentials as environment variables
# export MAILTRAP_API_KEY='your-api-key'

# accounts = Mailtrap::AccountsAPI.new

# Get all accounts
accounts.list
# => [#<struct Mailtrap::Account id=123456, name="My Account", access_levels=[1000]>]
1 change: 1 addition & 0 deletions lib/mailtrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative 'mailtrap/mail'
require_relative 'mailtrap/errors'
require_relative 'mailtrap/version'
require_relative 'mailtrap/accounts_api'
require_relative 'mailtrap/email_templates_api'
require_relative 'mailtrap/contacts_api'
require_relative 'mailtrap/contact_lists_api'
Expand Down
16 changes: 16 additions & 0 deletions lib/mailtrap/account.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Mailtrap
# Data Transfer Object for Account
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/d26921ca2a48f-get-all-accounts
# @attr_reader id [Integer] The account ID
# @attr_reader name [String] The account name
# @attr_reader access_levels [Array] The account access levels
#
Account = Struct.new(
:id,
:name,
:access_levels,
keyword_init: true
)
end
33 changes: 33 additions & 0 deletions lib/mailtrap/accounts_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

require_relative 'base_api'
require_relative 'account'

module Mailtrap
class AccountsAPI
include BaseAPI

self.response_class = Account

attr_reader :client

# @param client [Mailtrap::Client] The client instance
# @raise [ArgumentError] If account_id is nil
def initialize(client = Mailtrap::Client.new)
@client = client
end

# Lists all accounts
# @return [Array<Account>] Array of accounts
# @!macro api_errors
def list
base_list
end

private

def base_path
'/api/accounts'
end
end
end

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions spec/mailtrap/account_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

RSpec.describe Mailtrap::Account do
describe '#initialize' do
subject(:account) { described_class.new(attributes) }

let(:attributes) do
{
id: '123456',
name: 'Account 1',
access_levels: [
1000
]
}
end

it 'creates an account with all attributes' do
expect(account).to match_struct(
id: '123456',
name: 'Account 1',
access_levels: [1000]
)
end
end
end
28 changes: 28 additions & 0 deletions spec/mailtrap/accounts_api_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

RSpec.describe Mailtrap::AccountsAPI, :vcr do
subject(:accounts_api) { described_class.new(client) }

let(:client) { Mailtrap::Client.new(api_key: ENV.fetch('MAILTRAP_API_KEY', 'local-api-key')) }

describe '#list' do
subject(:list) { accounts_api.list }

it 'maps response data to Account objects' do
expect(list).to all(be_a(Mailtrap::Account))
expect(list.size).to eq(1)
end

context 'when api key is incorrect' do
let(:client) { Mailtrap::Client.new(api_key: 'incorrect-api-key') }

it 'raises authorization error' do
expect { list }.to raise_error do |error|
expect(error).to be_a(Mailtrap::AuthorizationError)
expect(error.message).to include('Incorrect API token')
expect(error.messages.any? { |msg| msg.include?('Incorrect API token') }).to be true
end
end
Comment on lines +20 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the AuthorizationError class definition
find . -name "*.rb" -type f | xargs rg -l "class AuthorizationError"

Repository: mailtrap/mailtrap-ruby

Length of output: 90


🏁 Script executed:

#!/bin/bash
# Look for error class definitions in the mailtrap directory structure
fd -e rb "error" --path "*mailtrap*" -type f

Repository: mailtrap/mailtrap-ruby

Length of output: 299


🏁 Script executed:

#!/bin/bash
# Search for AuthorizationError class and its attributes
rg -n "class AuthorizationError" -A 30 --type ruby

Repository: mailtrap/mailtrap-ruby

Length of output: 965


🏁 Script executed:

#!/bin/bash
# Also search for any definition of 'messages' or 'details' attributes in error classes
rg -n "(attr_reader|attr_accessor|def messages|def details)" --type ruby -B 3 -A 1 | head -100

Repository: mailtrap/mailtrap-ruby

Length of output: 7635


🏁 Script executed:

#!/bin/bash
# View the entire errors.rb file to see the Error base class definition
cat -n lib/mailtrap/errors.rb

Repository: mailtrap/mailtrap-ruby

Length of output: 1174


🏁 Script executed:

#!/bin/bash
# Search for Error class definition and attributes
rg -n "class Error" -A 25 --type ruby lib/mailtrap/errors.rb

Repository: mailtrap/mailtrap-ruby

Length of output: 845


Specify error type in raise_error to avoid false positives.

The raise_error matcher without a specific error type argument can match unintended exceptions raised inside the block (e.g., NoMethodError), causing tests to pass silently when they shouldn't. While error.messages is a valid attribute on Mailtrap::AuthorizationError, the bare matcher remains a code smell.

Pass the expected error type and message pattern directly to raise_error, and move only the custom assertion inside the block:

♻️ Proposed fix
-      expect { list }.to raise_error do |error|
-        expect(error).to be_a(Mailtrap::AuthorizationError)
-        expect(error.message).to include('Incorrect API token')
-        expect(error.messages.any? { |msg| msg.include?('Incorrect API token') }).to be true
-      end
+      expect { list }.to raise_error(Mailtrap::AuthorizationError, /Incorrect API token/) do |error|
+        expect(error.messages).to include(a_string_including('Incorrect API token'))
+      end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/mailtrap/accounts_api_spec.rb` around lines 20 - 25, The test's
raise_error matcher is too permissive; change the expectation to assert the
specific error type and message by calling raise_error with
Mailtrap::AuthorizationError and a message pattern (e.g., /Incorrect API token/)
for the main matcher, and keep only the custom assertion about error.messages
inside the block; update the spec around the call to list so it uses
raise_error(Mailtrap::AuthorizationError, /Incorrect API token/) and then yields
the error to verify error.messages contains the expected string.

end
end
end