From be38e8f6c3d6c8d1f0eace937887de271148c8b3 Mon Sep 17 00:00:00 2001 From: Igor Dobryn Date: Tue, 28 Apr 2026 12:43:14 +0300 Subject: [PATCH 1/4] Add SendingDomainsAPI#update --- examples/sending_domains_api.rb | 9 +++ lib/mailtrap/sending_domains_api.rb | 17 ++++- ..._response_data_to_SendingDomain_object.yml | 76 +++++++++++++++++++ .../raises_not_found_error.yml | 71 +++++++++++++++++ spec/mailtrap/sending_domains_api_spec.rb | 44 +++++++++++ 5 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/maps_response_data_to_SendingDomain_object.yml create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml diff --git a/examples/sending_domains_api.rb b/examples/sending_domains_api.rb index 5534d47..6484958 100644 --- a/examples/sending_domains_api.rb +++ b/examples/sending_domains_api.rb @@ -16,6 +16,15 @@ sending_domain = sending_domains.get(sending_domain.id) # => # +# Update sending domain configuration +sending_domains.update( + sending_domain.id, + open_tracking_enabled: true, + click_tracking_enabled: true, + auto_unsubscribe_link_enabled: false +) +# => # + # Send setup email sending_domains.send_setup_instructions(sending_domain.id, email: 'jonathan@mail.com') # => nil diff --git a/lib/mailtrap/sending_domains_api.rb b/lib/mailtrap/sending_domains_api.rb index 50407c3..35f922e 100644 --- a/lib/mailtrap/sending_domains_api.rb +++ b/lib/mailtrap/sending_domains_api.rb @@ -7,7 +7,7 @@ module Mailtrap class SendingDomainsAPI include BaseAPI - self.supported_options = %i[domain_name] + self.supported_options = %i[open_tracking_enabled click_tracking_enabled auto_unsubscribe_link_enabled] self.response_class = SendingDomain @@ -34,7 +34,7 @@ def get(domain_id) # @!macro api_errors # @raise [ArgumentError] If invalid options are provided def create(options) - base_create(options) + base_create(options, %i[domain_name]) end # Deletes a sending domain @@ -45,6 +45,19 @@ def delete(domain_id) base_delete(domain_id) end + # Updates configuration settings for a sending domain + # @param domain_id [Integer] The sending domain ID + # @param [Hash] options The parameters to update + # @option options [Boolean] :open_tracking_enabled Enable open tracking for emails sent from this domain + # @option options [Boolean] :click_tracking_enabled Enable click tracking for links in emails sent from this domain + # @option options [Boolean] :auto_unsubscribe_link_enabled Automatically add an unsubscribe link to emails + # @return [SendingDomain] Updated sending domain + # @!macro api_errors + # @raise [ArgumentError] If invalid options are provided + def update(domain_id, options) + base_update(domain_id, options) + end + # Email DNS configuration instructions for the sending domain # @param domain_id [Integer] The sending domain ID # @param email [String] The email for instructions diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/maps_response_data_to_SendingDomain_object.yml b/spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/maps_response_data_to_SendingDomain_object.yml new file mode 100644 index 0000000..e5c682a --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/maps_response_data_to_SendingDomain_object.yml @@ -0,0 +1,76 @@ +--- +http_interactions: +- request: + method: patch + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/61802 + body: + encoding: UTF-8 + string: '{"sending_domain":{"open_tracking_enabled":true,"click_tracking_enabled":true,"auto_unsubscribe_link_enabled":false}}' + 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: + - Tue, 28 Apr 2026 09:34:49 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Accept + - Accept-Encoding + 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: + - '150' + X-Ratelimit-Remaining: + - '149' + Etag: + - W/"2c87bee9e81d45fa0182a2cba94cd628" + Cache-Control: + - max-age=0, private, must-revalidate + X-Runtime: + - '0.049764' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"domain_name":"experiments.mailtrap.link","open_tracking_enabled":true,"click_tracking_enabled":true,"auto_unsubscribe_link_enabled":false,"custom_domain_tracking_enabled":true,"health_alerts_enabled":true,"critical_alerts_enabled":true,"alert_recipient_email":null,"demo":false,"id":61802,"dns_records":[{"key":"verification","domain":"6vdgrjnn7lt7oys6.experiments.mailtrap.link","type":"CNAME","value":"smtp.mailtrap.live","status":"pass","name":"6vdgrjnn7lt7oys6"},{"key":"dkim1","domain":"rwmt1._domainkey.experiments.mailtrap.link","type":"CNAME","value":"rwmt1.dkim.smtp.mailtrap.live","status":"pass","name":"rwmt1._domainkey"},{"key":"dkim2","domain":"rwmt2._domainkey.experiments.mailtrap.link","type":"CNAME","value":"rwmt2.dkim.smtp.mailtrap.live","status":"pass","name":"rwmt2._domainkey"},{"key":"dmarc","domain":"_dmarc.experiments.mailtrap.link","type":"TXT","value":"v=DMARC1; + p=none; rua=mailto:dmarc@smtp-staging.mailtrap.net; ruf=mailto:dmarc@smtp-staging.mailtrap.net; + rf=afrf; pct=100","status":"pass","name":"_dmarc"},{"key":"link_verification","domain":"mt-link.experiments.mailtrap.link","type":"CNAME","value":"t.mailtrap.live","status":"pass","name":"mt-link"}],"dns_verified":true,"dns_verified_at":"2026-04-28T08:19:31.769Z","permissions":{"can_read":true,"can_update":true,"can_destroy":true},"compliance_status":"compliant"}' + recorded_at: Tue, 28 Apr 2026 09:34:49 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml new file mode 100644 index 0000000..fa08f08 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_SendingDomainsAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml @@ -0,0 +1,71 @@ +--- +http_interactions: +- request: + method: patch + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/-1 + body: + encoding: UTF-8 + string: '{"sending_domain":{"open_tracking_enabled":true,"click_tracking_enabled":true,"auto_unsubscribe_link_enabled":false}}' + 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, 28 Apr 2026 09:31:16 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: + - '150' + X-Ratelimit-Remaining: + - '148' + Cache-Control: + - no-cache + X-Runtime: + - '0.013840' + 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, 28 Apr 2026 09:31:16 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/mailtrap/sending_domains_api_spec.rb b/spec/mailtrap/sending_domains_api_spec.rb index fa732c6..a6b372b 100644 --- a/spec/mailtrap/sending_domains_api_spec.rb +++ b/spec/mailtrap/sending_domains_api_spec.rb @@ -184,4 +184,48 @@ end end end + + describe '#update' do + subject(:update) { sending_domains_api.update(sending_domain_id, **request) } + + let(:sending_domain_id) { 61_802 } + + let(:request) do + { + open_tracking_enabled: true, + click_tracking_enabled: true, + auto_unsubscribe_link_enabled: false + } + end + + it 'maps response data to SendingDomain object' do + expect(update).to be_a(Mailtrap::SendingDomain) + expect(update).to have_attributes( + id: sending_domain_id, + open_tracking_enabled: true, + click_tracking_enabled: true, + auto_unsubscribe_link_enabled: false + ) + end + + context 'when invalid options are provided' do + let(:request) { { unknown_option: true } } + + it 'raises ArgumentError' do + expect { update }.to raise_error(ArgumentError, /invalid options are given/) + end + end + + context 'when sending domain does not exist' do + let(:sending_domain_id) { -1 } + + it 'raises not found error' do + expect { update }.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 e0e919ecf21959314a76189fc2cbe396a4209a1d Mon Sep 17 00:00:00 2001 From: Igor Dobryn Date: Tue, 28 Apr 2026 13:34:37 +0300 Subject: [PATCH 2/4] Add CompanyInfoAPI#create --- examples/company_info_api.rb | 19 +++++ lib/mailtrap.rb | 1 + lib/mailtrap/company_info.rb | 29 +++++++ lib/mailtrap/company_info_api.rb | 57 ++++++++++++++ ...ps_response_data_to_CompanyInfo_object.yml | 74 ++++++++++++++++++ .../raises_a_Mailtrap_Error.yml | 72 ++++++++++++++++++ .../raises_not_found_error.yml | 72 ++++++++++++++++++ spec/mailtrap/company_info_api_spec.rb | 76 +++++++++++++++++++ spec/mailtrap/company_info_spec.rb | 26 +++++++ 9 files changed, 426 insertions(+) create mode 100644 examples/company_info_api.rb create mode 100644 lib/mailtrap/company_info.rb create mode 100644 lib/mailtrap/company_info_api.rb create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/maps_response_data_to_CompanyInfo_object.yml create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_required_field_is_missing/raises_a_Mailtrap_Error.yml create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_sending_domain_does_not_exist/raises_not_found_error.yml create mode 100644 spec/mailtrap/company_info_api_spec.rb create mode 100644 spec/mailtrap/company_info_spec.rb diff --git a/examples/company_info_api.rb b/examples/company_info_api.rb new file mode 100644 index 0000000..64914ef --- /dev/null +++ b/examples/company_info_api.rb @@ -0,0 +1,19 @@ +require 'mailtrap' + +account_id = 3229 +sending_domain_id = 1 +client = Mailtrap::Client.new(api_key: 'your-api-key') +company_info_api = Mailtrap::CompanyInfoAPI.new(account_id, client) + +# Create company info for a sending domain +company_info_api.create( + sending_domain_id, + name: 'Mailtrap', + address: '123 Main St', + city: 'San Francisco', + country: 'US', + zip_code: '94105', + website_url: 'https://mailtrap.io', + info_level: 'business' +) +# => # diff --git a/lib/mailtrap.rb b/lib/mailtrap.rb index dd07a7b..bb25971 100644 --- a/lib/mailtrap.rb +++ b/lib/mailtrap.rb @@ -14,6 +14,7 @@ require_relative 'mailtrap/contact_imports_api' require_relative 'mailtrap/suppressions_api' require_relative 'mailtrap/sending_domains_api' +require_relative 'mailtrap/company_info_api' require_relative 'mailtrap/email_logs_api' require_relative 'mailtrap/projects_api' require_relative 'mailtrap/inboxes_api' diff --git a/lib/mailtrap/company_info.rb b/lib/mailtrap/company_info.rb new file mode 100644 index 0000000..722f69c --- /dev/null +++ b/lib/mailtrap/company_info.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Mailtrap + # Data Transfer Object for Sending Domain Company Info + # @see https://docs.mailtrap.io/developers/management/sending-domains + # @attr_reader name [String, nil] Company or individual name + # @attr_reader address [String, nil] Street address + # @attr_reader city [String, nil] City + # @attr_reader country [String, nil] Country + # @attr_reader phone [String, nil] Phone number + # @attr_reader zip_code [String, nil] ZIP or postal code + # @attr_reader privacy_policy_url [String, nil] URL to the privacy policy page + # @attr_reader terms_of_service_url [String, nil] URL to the terms of service page + # @attr_reader website_url [String, nil] Company website URL or LinkedIn / personal website + # @attr_reader info_level [String, nil] Whether the sender is a "business" or "individual" + CompanyInfo = Struct.new( + :name, + :address, + :city, + :country, + :phone, + :zip_code, + :privacy_policy_url, + :terms_of_service_url, + :website_url, + :info_level, + keyword_init: true + ) +end diff --git a/lib/mailtrap/company_info_api.rb b/lib/mailtrap/company_info_api.rb new file mode 100644 index 0000000..4331b29 --- /dev/null +++ b/lib/mailtrap/company_info_api.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require_relative 'base_api' +require_relative 'company_info' + +module Mailtrap + class CompanyInfoAPI + include BaseAPI + + self.supported_options = %i[ + name + address + city + country + phone + zip_code + privacy_policy_url + terms_of_service_url + website_url + info_level + ].freeze + + self.response_class = CompanyInfo + + # Creates company information for a sending domain + # @param sending_domain_id [Integer] The sending domain ID + # @param [Hash] options The company info attributes + # @option options [String] :name Company or individual name + # @option options [String] :address Street address + # @option options [String] :city City + # @option options [String] :country Country + # @option options [String] :phone Phone number + # @option options [String] :zip_code ZIP or postal code + # @option options [String] :privacy_policy_url URL to the privacy policy page + # @option options [String] :terms_of_service_url URL to the terms of service page + # @option options [String] :website_url Company website URL + # @option options [String] :info_level Whether the sender is a "business" or "individual" + # @return [CompanyInfo] Created company information + # @!macro api_errors + # @raise [ArgumentError] If invalid options are provided + def create(sending_domain_id, options) + validate_options!(options, supported_options) + response = client.post(base_path(sending_domain_id), wrap_request(options)) + build_entity(response[:data], CompanyInfo) + end + + private + + def base_path(sending_domain_id) + "/api/accounts/#{account_id}/sending_domains/#{sending_domain_id}/company_info" + end + + def wrap_request(options) + { company_info: options } + end + end +end diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/maps_response_data_to_CompanyInfo_object.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/maps_response_data_to_CompanyInfo_object.yml new file mode 100644 index 0000000..698f86c --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/maps_response_data_to_CompanyInfo_object.yml @@ -0,0 +1,74 @@ +--- +http_interactions: +- request: + method: post + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/122392/company_info + body: + encoding: UTF-8 + string: '{"company_info":{"name":"Mailtrap","address":"123 Main St","city":"San + Francisco","country":"US","zip_code":"94105","website_url":"https://mailtrap.io","info_level":"business"}}' + 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: + - Tue, 28 Apr 2026 10:21:26 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + 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' + Etag: + - W/"1e2463fffad24d2d13db0ef550c6bd72" + Cache-Control: + - max-age=0, private, must-revalidate + X-Runtime: + - '0.028169' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"data":{"name":"Mailtrap","address":"123 Main St","city":"San Francisco","country":"US","phone":null,"zip_code":"94105","privacy_policy_url":null,"terms_of_service_url":null,"website_url":"https://mailtrap.io","info_level":"business"}}' + recorded_at: Tue, 28 Apr 2026 10:21:26 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_required_field_is_missing/raises_a_Mailtrap_Error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_required_field_is_missing/raises_a_Mailtrap_Error.yml new file mode 100644 index 0000000..9a23f46 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_required_field_is_missing/raises_a_Mailtrap_Error.yml @@ -0,0 +1,72 @@ +--- +http_interactions: +- request: + method: post + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/122392/company_info + body: + encoding: UTF-8 + string: '{"company_info":{"name":"Mailtrap","address":"123 Main St","city":"San + Francisco","country":"US","zip_code":"94105"}}' + 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: 422 + message: Unprocessable Entity + headers: + Date: + - Tue, 28 Apr 2026 10:30:32 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '58' + 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: + - no-cache + X-Runtime: + - '0.026470' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: UTF-8 + string: '{"errors":{"website_url":["can''t be blank","is invalid"]}}' + recorded_at: Tue, 28 Apr 2026 10:30:32 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_sending_domain_does_not_exist/raises_not_found_error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_sending_domain_does_not_exist/raises_not_found_error.yml new file mode 100644 index 0000000..51fc9ec --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_create/when_sending_domain_does_not_exist/raises_not_found_error.yml @@ -0,0 +1,72 @@ +--- +http_interactions: +- request: + method: post + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/-1/company_info + body: + encoding: UTF-8 + string: '{"company_info":{"name":"Mailtrap","address":"123 Main St","city":"San + Francisco","country":"US","zip_code":"94105","website_url":"https://mailtrap.io","info_level":"business"}}' + 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, 28 Apr 2026 10:21:27 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: + - '150' + X-Ratelimit-Remaining: + - '147' + Cache-Control: + - no-cache + X-Runtime: + - '0.012731' + 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, 28 Apr 2026 10:21:27 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/mailtrap/company_info_api_spec.rb b/spec/mailtrap/company_info_api_spec.rb new file mode 100644 index 0000000..358a38e --- /dev/null +++ b/spec/mailtrap/company_info_api_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +RSpec.describe Mailtrap::CompanyInfoAPI, :vcr do + subject(:company_info_api) { described_class.new(account_id, client) } + + let(:account_id) { ENV.fetch('MAILTRAP_ACCOUNT_ID', 1_111_111) } + let(:client) { Mailtrap::Client.new(api_key: ENV.fetch('MAILTRAP_API_KEY', 'local-api-key')) } + let(:sending_domain_id) { 122_392 } + + describe '#create' do + subject(:create) { company_info_api.create(sending_domain_id, request) } + + let(:request) do + { + name: 'Mailtrap', + address: '123 Main St', + city: 'San Francisco', + country: 'US', + zip_code: '94105', + website_url: 'https://mailtrap.io', + info_level: 'business' + } + end + + it 'maps response data to CompanyInfo object' do + expect(create).to be_a(Mailtrap::CompanyInfo) + expect(create).to have_attributes( + name: 'Mailtrap', + address: '123 Main St', + city: 'San Francisco', + country: 'US', + zip_code: '94105', + website_url: 'https://mailtrap.io', + info_level: 'business' + ) + end + + context 'when invalid options are provided' do + let(:request) { { unknown_option: true } } + + it 'raises ArgumentError' do + expect { create }.to raise_error(ArgumentError, /invalid options are given/) + end + end + + context 'when required field is missing' do + let(:request) do + { + name: 'Mailtrap', + address: '123 Main St', + city: 'San Francisco', + country: 'US', + zip_code: '94105' + } + end + + it 'raises a Mailtrap::Error' do + expect { create }.to raise_error(Mailtrap::Error) do |error| + expect(error.message).to include('client error') + end + end + end + + context 'when sending domain does not exist' do + let(:sending_domain_id) { -1 } + + it 'raises not found error' do + expect { create }.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 diff --git a/spec/mailtrap/company_info_spec.rb b/spec/mailtrap/company_info_spec.rb new file mode 100644 index 0000000..3be9ee5 --- /dev/null +++ b/spec/mailtrap/company_info_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +RSpec.describe Mailtrap::CompanyInfo do + describe '#initialize' do + subject(:company_info) { described_class.new(attributes) } + + let(:attributes) do + { + name: 'Mailtrap', + address: '123 Main St', + city: 'San Francisco', + country: 'US', + phone: '+1-555-0100', + zip_code: '94105', + privacy_policy_url: 'https://mailtrap.io/privacy', + terms_of_service_url: 'https://mailtrap.io/terms', + website_url: 'https://mailtrap.io', + info_level: 'business' + } + end + + it 'creates a company info with all attributes' do + expect(company_info).to have_attributes(attributes) + end + end +end From 27324c014ed6ee85d447756afebd8a1305bc4f5b Mon Sep 17 00:00:00 2001 From: Igor Dobryn Date: Tue, 28 Apr 2026 13:46:08 +0300 Subject: [PATCH 3/4] Add CompanyInfoAPI#update --- lib/mailtrap/company_info_api.rb | 12 +++ ...ps_response_data_to_CompanyInfo_object.yml | 73 +++++++++++++++++++ .../raises_not_found_error.yml | 71 ++++++++++++++++++ spec/mailtrap/company_info_api_spec.rb | 39 ++++++++++ 4 files changed, 195 insertions(+) create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/maps_response_data_to_CompanyInfo_object.yml create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml diff --git a/lib/mailtrap/company_info_api.rb b/lib/mailtrap/company_info_api.rb index 4331b29..fb0da5a 100644 --- a/lib/mailtrap/company_info_api.rb +++ b/lib/mailtrap/company_info_api.rb @@ -44,6 +44,18 @@ def create(sending_domain_id, options) build_entity(response[:data], CompanyInfo) end + # Updates company information for a sending domain + # @param sending_domain_id [Integer] The sending domain ID + # @param [Hash] options The company info attributes to update + # @return [CompanyInfo] Updated company information + # @!macro api_errors + # @raise [ArgumentError] If invalid options are provided + def update(sending_domain_id, options) + validate_options!(options, supported_options) + response = client.patch(base_path(sending_domain_id), wrap_request(options)) + build_entity(response[:data], CompanyInfo) + end + private def base_path(sending_domain_id) diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/maps_response_data_to_CompanyInfo_object.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/maps_response_data_to_CompanyInfo_object.yml new file mode 100644 index 0000000..b4c41b4 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/maps_response_data_to_CompanyInfo_object.yml @@ -0,0 +1,73 @@ +--- +http_interactions: +- request: + method: patch + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/122392/company_info + body: + encoding: UTF-8 + string: '{"company_info":{"city":"New York","zip_code":"10001"}}' + 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: + - Tue, 28 Apr 2026 10:44:00 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + 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' + Etag: + - W/"e9bc14ead042a4f69bcca68fcd7740a4" + Cache-Control: + - max-age=0, private, must-revalidate + X-Runtime: + - '0.025909' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"data":{"name":"Mailtrap","address":"123 Main St","city":"New York","country":"US","phone":null,"zip_code":"10001","privacy_policy_url":null,"terms_of_service_url":null,"website_url":"https://mailtrap.io","info_level":"business"}}' + recorded_at: Tue, 28 Apr 2026 10:44:00 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml new file mode 100644 index 0000000..4288537 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_update/when_sending_domain_does_not_exist/raises_not_found_error.yml @@ -0,0 +1,71 @@ +--- +http_interactions: +- request: + method: patch + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/-1/company_info + body: + encoding: UTF-8 + string: '{"company_info":{"city":"New York","zip_code":"10001"}}' + 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, 28 Apr 2026 10:40:50 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: + - '150' + X-Ratelimit-Remaining: + - '149' + Cache-Control: + - no-cache + X-Runtime: + - '0.015659' + 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, 28 Apr 2026 10:40:50 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/mailtrap/company_info_api_spec.rb b/spec/mailtrap/company_info_api_spec.rb index 358a38e..2489024 100644 --- a/spec/mailtrap/company_info_api_spec.rb +++ b/spec/mailtrap/company_info_api_spec.rb @@ -73,4 +73,43 @@ end end end + + describe '#update' do + subject(:update) { company_info_api.update(sending_domain_id, request) } + + let(:request) do + { + city: 'New York', + zip_code: '10001' + } + end + + it 'maps response data to CompanyInfo object' do + expect(update).to be_a(Mailtrap::CompanyInfo) + expect(update).to have_attributes( + city: 'New York', + zip_code: '10001' + ) + end + + context 'when invalid options are provided' do + let(:request) { { unknown_option: true } } + + it 'raises ArgumentError' do + expect { update }.to raise_error(ArgumentError, /invalid options are given/) + end + end + + context 'when sending domain does not exist' do + let(:sending_domain_id) { -1 } + + it 'raises not found error' do + expect { update }.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 7c6684b8bda44768b082a36feebea3ec07cbaca1 Mon Sep 17 00:00:00 2001 From: Igor Dobryn Date: Tue, 28 Apr 2026 14:04:51 +0300 Subject: [PATCH 4/4] Add CompanyInfoAPI#get --- lib/mailtrap/company_info_api.rb | 9 +++ ...ps_response_data_to_CompanyInfo_object.yml | 73 +++++++++++++++++++ .../raises_not_found_error.yml | 71 ++++++++++++++++++ spec/mailtrap/company_info_api_spec.rb | 29 ++++++++ 4 files changed, 182 insertions(+) create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/maps_response_data_to_CompanyInfo_object.yml create mode 100644 spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/when_sending_domain_does_not_exist/raises_not_found_error.yml diff --git a/lib/mailtrap/company_info_api.rb b/lib/mailtrap/company_info_api.rb index fb0da5a..1e3785b 100644 --- a/lib/mailtrap/company_info_api.rb +++ b/lib/mailtrap/company_info_api.rb @@ -22,6 +22,15 @@ class CompanyInfoAPI self.response_class = CompanyInfo + # Gets company information for a sending domain + # @param sending_domain_id [Integer] The sending domain ID + # @return [CompanyInfo] Company information + # @!macro api_errors + def get(sending_domain_id) + response = client.get(base_path(sending_domain_id)) + build_entity(response[:data], CompanyInfo) + end + # Creates company information for a sending domain # @param sending_domain_id [Integer] The sending domain ID # @param [Hash] options The company info attributes diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/maps_response_data_to_CompanyInfo_object.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/maps_response_data_to_CompanyInfo_object.yml new file mode 100644 index 0000000..8e05aee --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/maps_response_data_to_CompanyInfo_object.yml @@ -0,0 +1,73 @@ +--- +http_interactions: +- request: + method: get + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/122392/company_info + 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: 200 + message: OK + headers: + Date: + - Tue, 28 Apr 2026 11:01:44 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + 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' + Etag: + - W/"e9bc14ead042a4f69bcca68fcd7740a4" + Cache-Control: + - max-age=0, private, must-revalidate + X-Runtime: + - '0.024724' + Strict-Transport-Security: + - max-age=2592000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"data":{"name":"Mailtrap","address":"123 Main St","city":"San Francisco","country":"US","phone":null,"zip_code":"94105","privacy_policy_url":null,"terms_of_service_url":null,"website_url":"https://mailtrap.io","info_level":"business"}}' + recorded_at: Tue, 28 Apr 2026 11:01:44 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/when_sending_domain_does_not_exist/raises_not_found_error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/when_sending_domain_does_not_exist/raises_not_found_error.yml new file mode 100644 index 0000000..ca169db --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_CompanyInfoAPI/_get/when_sending_domain_does_not_exist/raises_not_found_error.yml @@ -0,0 +1,71 @@ +--- +http_interactions: +- request: + method: get + uri: https://mailtrap.io/api/accounts/1111111/sending_domains/-1/company_info + 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, 28 Apr 2026 11:01:44 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: + - '150' + X-Ratelimit-Remaining: + - '148' + Cache-Control: + - no-cache + X-Runtime: + - '0.016597' + 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, 28 Apr 2026 11:01:44 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/mailtrap/company_info_api_spec.rb b/spec/mailtrap/company_info_api_spec.rb index 2489024..fb50dc2 100644 --- a/spec/mailtrap/company_info_api_spec.rb +++ b/spec/mailtrap/company_info_api_spec.rb @@ -7,6 +7,35 @@ let(:client) { Mailtrap::Client.new(api_key: ENV.fetch('MAILTRAP_API_KEY', 'local-api-key')) } let(:sending_domain_id) { 122_392 } + describe '#get' do + subject(:get) { company_info_api.get(sending_domain_id) } + + it 'maps response data to CompanyInfo object' do + expect(get).to be_a(Mailtrap::CompanyInfo) + expect(get).to have_attributes( + name: 'Mailtrap', + address: '123 Main St', + city: 'San Francisco', + country: 'US', + zip_code: '94105', + website_url: 'https://mailtrap.io', + info_level: 'business' + ) + end + + context 'when sending domain does not exist' do + let(:sending_domain_id) { -1 } + + it 'raises not found error' do + expect { get }.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 + describe '#create' do subject(:create) { company_info_api.create(sending_domain_id, request) }