mailtrap 2.17.0 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf895b774a80d6579230f2629793150d13be0648536b9c88524f6149ae39feb9
4
- data.tar.gz: 50169e072e02c1509a9da6b7b933ad8fe1b6b6d219f50771696d3f5f62cc4674
3
+ metadata.gz: 2749218455a3db4dce0286b7c6aacda197ac2fa7e97547def63703d5df982aa9
4
+ data.tar.gz: c324fcd9a6d8b788609ae48f5a4a1ca68aaf74887a036c6625631b1e643f79b6
5
5
  SHA512:
6
- metadata.gz: 7da15a7343f680b071be20f34f3223582351e66de800600d48c84afd46ee78d9dad96220fb9885f4498f0d62617cb35b16a0957169d3e79639d071509177c52d
7
- data.tar.gz: 4c4a95c0fdbf908287f60e6ae15ff0332a24ee35e217643f80664a6ef379d80216902335c4d7b8108c05301f3f7e46e39ef232f1293e1ee70a9edc41533a0334
6
+ metadata.gz: 2c739fdf5614960c3e36a239ab922d879a91fe6063652f8bf3ef7dfd2b22f145a969fd72cbd2c6b0dcdf977481e1fa5f35d37104fad2d6fc2d71f83eed136fa2
7
+ data.tar.gz: cfd90df52872218ddfbb80082a885ccb07898e7e1fc42fef8da12361d9e614e58bfe0e8672a75c5e4238974dd22615000a997001b9c78eac19709e09396aa45b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [2.19.0] - 2026-10-29
2
+
3
+ ## What's Changed
4
+ * Add MarketingStatsAPI for GET /api/marketing/stats by @Rabsztok in https://github.com/mailtrap/mailtrap-ruby/pull/136
5
+ * Fix CI on Ubuntu 26.04 by testing Ruby series, not exact patches by @Rabsztok in https://github.com/mailtrap/mailtrap-ruby/pull/137
6
+
7
+
8
+ **Full Changelog**: https://github.com/mailtrap/mailtrap-ruby/compare/v2.18.0...v2.19.0
9
+
10
+ ## [2.18.0] - 2026-10-07
11
+
12
+ ## What's Changed
13
+ * Add inbound forward rules, forward outcomes, thread delivery and search by @mklocek in https://github.com/mailtrap/mailtrap-ruby/pull/132
14
+
15
+
16
+ **Full Changelog**: https://github.com/mailtrap/mailtrap-ruby/compare/v2.17.0...v2.18.0
17
+
1
18
  ## [2.17.0] - 2026-10-07
2
19
 
3
20
  ## What's Changed
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mailtrap (2.17.0)
4
+ mailtrap (2.19.0)
5
5
  base64
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -195,6 +195,7 @@ Inbound Email:
195
195
  - Inbound Inboxes API – [`inbound_inboxes_api.rb`](examples/inbound_inboxes_api.rb)
196
196
  - Inbound Messages API (list, get, delete, reply, reply_all, forward) – [`inbound_messages_api.rb`](examples/inbound_messages_api.rb)
197
197
  - Inbound Threads API – [`inbound_threads_api.rb`](examples/inbound_threads_api.rb)
198
+ - Inbound Forward Rules API – [`inbound_forward_rules_api.rb`](examples/inbound_forward_rules_api.rb)
198
199
 
199
200
  Contact management:
200
201
 
@@ -203,6 +204,7 @@ Contact management:
203
204
  Email marketing:
204
205
 
205
206
  - Email Campaigns CRUD, Lifecycle Actions & Stats – [`email_campaigns_api.rb`](examples/email_campaigns_api.rb)
207
+ - Email Marketing Stats API – [`marketing_stats_api.rb`](examples/marketing_stats_api.rb)
206
208
 
207
209
  General:
208
210
 
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound forward outcome
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader rule_id [Integer] The forward rule ID
7
+ # @attr_reader rule_name [String, nil] The forward rule name
8
+ # @attr_reader destination [String] The destination address
9
+ # @attr_reader status [String] forwarded or rejected
10
+ # @attr_reader reason [String, nil] The rejection reason
11
+ # @attr_reader message_id [String, nil] The forwarded message ID
12
+ InboundForwardOutcome = Struct.new(
13
+ :rule_id,
14
+ :rule_name,
15
+ :destination,
16
+ :status,
17
+ :reason,
18
+ :message_id,
19
+ keyword_init: true
20
+ )
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound forward rule
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader id [Integer] The forward rule ID
7
+ # @attr_reader name [String] The rule name
8
+ # @attr_reader created_at [String] Creation timestamp
9
+ # @attr_reader updated_at [String] Last update timestamp
10
+ # @attr_reader conditions [Array<InboundForwardRuleCondition>] The rule conditions
11
+ # @attr_reader destinations [Array<InboundForwardRuleDestination>] The rule destinations
12
+ InboundForwardRule = Struct.new(
13
+ :id,
14
+ :name,
15
+ :created_at,
16
+ :updated_at,
17
+ :conditions,
18
+ :destinations,
19
+ keyword_init: true
20
+ )
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound forward rule condition
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader match_type [String] The match type
7
+ # @attr_reader operator [String] The comparison operator
8
+ # @attr_reader value [String, nil] The value to compare against
9
+ # @attr_reader header_key [String, nil] The header name
10
+ InboundForwardRuleCondition = Struct.new(
11
+ :match_type,
12
+ :operator,
13
+ :value,
14
+ :header_key,
15
+ keyword_init: true
16
+ )
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for an inbound forward rule destination
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader email [String] The destination email address
7
+ InboundForwardRuleDestination = Struct.new(
8
+ :email,
9
+ keyword_init: true
10
+ )
11
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_api'
4
+ require_relative 'inbound_forward_rule'
5
+ require_relative 'inbound_forward_rule_condition'
6
+ require_relative 'inbound_forward_rule_destination'
7
+
8
+ module Mailtrap
9
+ class InboundForwardRulesAPI
10
+ include BaseAPI
11
+
12
+ self.supported_options = %i[name conditions destinations]
13
+ self.response_class = InboundForwardRule
14
+
15
+ # @param client [Mailtrap::Client] The client instance
16
+ def initialize(client = Mailtrap::Client.new)
17
+ @client = client
18
+ end
19
+
20
+ # Lists forward rules in an inbox
21
+ # @param inbox_id [Integer] The inbox ID
22
+ # @return [Array<InboundForwardRule>] Array of forward rules
23
+ # @!macro api_errors
24
+ def list(inbox_id)
25
+ response = client.get(forward_rules_path(inbox_id))
26
+ Array(response[:data]).map { |item| build_rule(item) }
27
+ end
28
+
29
+ # Retrieves a specific forward rule
30
+ # @param inbox_id [Integer] The inbox ID
31
+ # @param forward_rule_id [Integer] The forward rule ID
32
+ # @return [InboundForwardRule] Forward rule object
33
+ # @!macro api_errors
34
+ def get(inbox_id, forward_rule_id)
35
+ handle_response(client.get("#{forward_rules_path(inbox_id)}/#{forward_rule_id}"))
36
+ end
37
+
38
+ # Creates a new forward rule
39
+ # @param inbox_id [Integer] The inbox ID
40
+ # @param [Hash] options The parameters to create
41
+ # @option options [String] :name The rule name
42
+ # @option options [Array<Hash>] :conditions The rule conditions
43
+ # @option options [Array<Hash>] :destinations The rule destinations
44
+ # @return [InboundForwardRule] Created forward rule
45
+ # @!macro api_errors
46
+ # @raise [ArgumentError] If invalid options are provided
47
+ def create(inbox_id, options)
48
+ validate_options!(options, supported_options)
49
+ handle_response(client.post(forward_rules_path(inbox_id), options))
50
+ end
51
+
52
+ # Updates a forward rule
53
+ # @param inbox_id [Integer] The inbox ID
54
+ # @param forward_rule_id [Integer] The forward rule ID
55
+ # @param [Hash] options The parameters to update
56
+ # @option options [String] :name The rule name
57
+ # @option options [Array<Hash>] :conditions The rule conditions
58
+ # @option options [Array<Hash>] :destinations The rule destinations
59
+ # @return [InboundForwardRule] Updated forward rule
60
+ # @!macro api_errors
61
+ # @raise [ArgumentError] If invalid options are provided
62
+ def update(inbox_id, forward_rule_id, options)
63
+ validate_options!(options, supported_options)
64
+ handle_response(client.patch("#{forward_rules_path(inbox_id)}/#{forward_rule_id}", options))
65
+ end
66
+
67
+ # Deletes a forward rule
68
+ # @param inbox_id [Integer] The inbox ID
69
+ # @param forward_rule_id [Integer] The forward rule ID
70
+ # @return nil
71
+ # @!macro api_errors
72
+ def delete(inbox_id, forward_rule_id)
73
+ client.delete("#{forward_rules_path(inbox_id)}/#{forward_rule_id}")
74
+ end
75
+
76
+ private
77
+
78
+ def forward_rules_path(inbox_id)
79
+ "/api/inbound/inboxes/#{inbox_id}/forward_rules"
80
+ end
81
+
82
+ def handle_response(response)
83
+ build_rule(response[:data])
84
+ end
85
+
86
+ def build_rule(hash)
87
+ attrs = hash.slice(*InboundForwardRule.members)
88
+ attrs[:conditions] = build_conditions(attrs[:conditions]) if attrs[:conditions]
89
+ attrs[:destinations] = build_destinations(attrs[:destinations]) if attrs[:destinations]
90
+
91
+ InboundForwardRule.new(**attrs)
92
+ end
93
+
94
+ def build_conditions(conditions)
95
+ Array(conditions).map do |condition|
96
+ InboundForwardRuleCondition.new(**condition.slice(*InboundForwardRuleCondition.members))
97
+ end
98
+ end
99
+
100
+ def build_destinations(destinations)
101
+ Array(destinations).map do |destination|
102
+ InboundForwardRuleDestination.new(**destination.slice(*InboundForwardRuleDestination.members))
103
+ end
104
+ end
105
+ end
106
+ end
@@ -25,6 +25,7 @@ module Mailtrap
25
25
  # @attr_reader raw_message_expires_at [String, nil] When the raw message URL expires (only when fetched by ID)
26
26
  # @attr_reader html_body [String, nil] Decoded HTML body (only when fetched by ID)
27
27
  # @attr_reader text_body [String, nil] Decoded text body (only when fetched by ID)
28
+ # @attr_reader forwards [Array<InboundForwardOutcome>] The forward outcomes
28
29
  # rubocop:disable Lint/StructNewOverride -- +size+ is an API field that shadows Struct#size
29
30
  InboundMessage = Struct.new(
30
31
  :id,
@@ -49,6 +50,7 @@ module Mailtrap
49
50
  :raw_message_expires_at,
50
51
  :html_body,
51
52
  :text_body,
53
+ :forwards,
52
54
  keyword_init: true
53
55
  )
54
56
  # rubocop:enable Lint/StructNewOverride
@@ -3,6 +3,7 @@
3
3
  require_relative 'base_api'
4
4
  require_relative 'inbound_message'
5
5
  require_relative 'inbound_attachment'
6
+ require_relative 'inbound_forward_outcome'
6
7
  require_relative 'inbound_messages_list_response'
7
8
  require_relative 'inbound_send_result'
8
9
 
@@ -100,6 +101,7 @@ module Mailtrap
100
101
  def build_message(hash)
101
102
  attrs = hash.slice(*InboundMessage.members)
102
103
  attrs[:attachments] = build_attachments(attrs[:attachments]) if attrs[:attachments]
104
+ attrs[:forwards] = build_forwards(attrs[:forwards]) if attrs[:forwards]
103
105
 
104
106
  InboundMessage.new(**attrs)
105
107
  end
@@ -109,5 +111,11 @@ module Mailtrap
109
111
  InboundAttachment.new(**attachment.slice(*InboundAttachment.members))
110
112
  end
111
113
  end
114
+
115
+ def build_forwards(forwards)
116
+ Array(forwards).map do |forward|
117
+ InboundForwardOutcome.new(**forward.slice(*InboundForwardOutcome.members))
118
+ end
119
+ end
112
120
  end
113
121
  end
@@ -2,8 +2,7 @@
2
2
 
3
3
  module Mailtrap
4
4
  # Data Transfer Object for a message inside an inbound thread.
5
- # Only +visibility_status+ and +direction+ are always present; +placeholder+ entries omit the rest,
6
- # and the delivery lifecycle fields are only set on available outbound messages.
5
+ # Only +visibility_status+ and +direction+ are always present; +placeholder+ entries omit the rest.
7
6
  # @see https://docs.mailtrap.io/developers/inbound
8
7
  # @attr_reader visibility_status [String] available or placeholder
9
8
  # @attr_reader direction [String] inbound or outbound
@@ -23,9 +22,8 @@ module Mailtrap
23
22
  # @attr_reader text_body [String, nil] Decoded text body
24
23
  # @attr_reader html_body [String, nil] Decoded HTML body
25
24
  # @attr_reader attachments [Array<InboundAttachment>, nil] The message attachments
26
- # @attr_reader delivery_status [String, nil] Delivery status (outbound messages only)
27
- # @attr_reader delivered_at [String, nil] Delivery timestamp (outbound messages only)
28
- # @attr_reader bounced_at [String, nil] Bounce timestamp (outbound messages only)
25
+ # @attr_reader delivery [InboundThreadMessageDelivery, nil] Delivery outcome (outbound messages only)
26
+ # @attr_reader forwards [Array<InboundForwardOutcome>, nil] Forward outcomes (inbound messages only)
29
27
  InboundThreadMessage = Struct.new(
30
28
  :visibility_status,
31
29
  :direction,
@@ -45,9 +43,8 @@ module Mailtrap
45
43
  :text_body,
46
44
  :html_body,
47
45
  :attachments,
48
- :delivery_status,
49
- :delivered_at,
50
- :bounced_at,
46
+ :delivery,
47
+ :forwards,
51
48
  keyword_init: true
52
49
  )
53
50
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for the delivery of an outbound message inside an inbound thread
5
+ # @see https://docs.mailtrap.io/developers/inbound
6
+ # @attr_reader to [String] The recipient address
7
+ # @attr_reader status [String] The delivery status
8
+ # @attr_reader delivered_at [String, nil] Delivery timestamp
9
+ # @attr_reader bounced_at [String, nil] Bounce timestamp
10
+ InboundThreadMessageDelivery = Struct.new(
11
+ :to,
12
+ :status,
13
+ :delivered_at,
14
+ :bounced_at,
15
+ keyword_init: true
16
+ )
17
+ end
@@ -4,6 +4,8 @@ require_relative 'base_api'
4
4
  require_relative 'inbound_thread'
5
5
  require_relative 'inbound_thread_message'
6
6
  require_relative 'inbound_attachment'
7
+ require_relative 'inbound_forward_outcome'
8
+ require_relative 'inbound_thread_message_delivery'
7
9
  require_relative 'inbound_threads_list_response'
8
10
 
9
11
  module Mailtrap
@@ -20,10 +22,11 @@ module Mailtrap
20
22
  # Lists threads in an inbox (cursor-paginated)
21
23
  # @param inbox_id [Integer] The inbox ID
22
24
  # @param last_id [String, nil] Cursor from the previous response's +last_id+ for the next page
25
+ # @param search [String, nil] Search query
23
26
  # @return [InboundThreadsListResponse] data, total_count, and last_id
24
27
  # @!macro api_errors
25
- def list(inbox_id, last_id: nil)
26
- query_params = last_id ? { last_id: } : {}
28
+ def list(inbox_id, last_id: nil, search: nil)
29
+ query_params = { last_id:, search: }.compact
27
30
  response = client.get(threads_path(inbox_id), query_params)
28
31
 
29
32
  InboundThreadsListResponse.new(
@@ -69,6 +72,8 @@ module Mailtrap
69
72
  Array(messages).map do |message|
70
73
  attrs = message.slice(*InboundThreadMessage.members)
71
74
  attrs[:attachments] = build_attachments(attrs[:attachments]) if attrs[:attachments]
75
+ attrs[:delivery] = build_delivery(attrs[:delivery]) if attrs[:delivery]
76
+ attrs[:forwards] = build_forwards(attrs[:forwards]) if attrs[:forwards]
72
77
 
73
78
  InboundThreadMessage.new(**attrs)
74
79
  end
@@ -79,5 +84,15 @@ module Mailtrap
79
84
  InboundAttachment.new(**attachment.slice(*InboundAttachment.members))
80
85
  end
81
86
  end
87
+
88
+ def build_delivery(delivery)
89
+ InboundThreadMessageDelivery.new(**delivery.slice(*InboundThreadMessageDelivery.members))
90
+ end
91
+
92
+ def build_forwards(forwards)
93
+ Array(forwards).map do |forward|
94
+ InboundForwardOutcome.new(**forward.slice(*InboundForwardOutcome.members))
95
+ end
96
+ end
82
97
  end
83
98
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for Email Marketing Stats
5
+ #
6
+ # Aggregated metrics of the account's Email Marketing traffic (campaigns and automations) for
7
+ # the requested period and filters. Rates are fractions from 0 to 1. Every count and rate is +0+
8
+ # when nothing matched.
9
+ # @see https://docs.mailtrap.io/developers/email-marketing/marketing-stats
10
+ # @attr_reader delivery_count [Integer] Number of delivered messages
11
+ # @attr_reader delivery_rate [Float, Integer] Share of sent messages that were delivered (0–1)
12
+ # @attr_reader bounce_count [Integer] Number of bounced messages
13
+ # @attr_reader bounce_rate [Float, Integer] Share of sent messages that bounced (0–1)
14
+ # @attr_reader open_count [Integer] Number of opened messages
15
+ # @attr_reader open_rate [Float, Integer] Share of delivered messages that were opened (0–1)
16
+ # @attr_reader click_count [Integer] Number of clicked messages
17
+ # @attr_reader click_rate [Float, Integer] Share of delivered messages that were clicked (0–1)
18
+ # @attr_reader spam_count [Integer] Number of spam complaints
19
+ # @attr_reader spam_rate [Float, Integer] Share of delivered messages marked as spam (0–1)
20
+ # @attr_reader unsubscription_count [Integer] Number of unsubscriptions
21
+ # @attr_reader unsubscription_rate [Float, Integer] Share of delivered messages that unsubscribed (0–1)
22
+ # @attr_reader sent_count [Integer] Number of sent messages (delivered plus bounced)
23
+ MarketingStats = Struct.new(
24
+ :delivery_count,
25
+ :delivery_rate,
26
+ :bounce_count,
27
+ :bounce_rate,
28
+ :open_count,
29
+ :open_rate,
30
+ :click_count,
31
+ :click_rate,
32
+ :spam_count,
33
+ :spam_rate,
34
+ :unsubscription_count,
35
+ :unsubscription_rate,
36
+ :sent_count,
37
+ keyword_init: true
38
+ )
39
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_api'
4
+ require_relative 'stats_query_params'
5
+ require_relative 'marketing_stats'
6
+
7
+ module Mailtrap
8
+ class MarketingStatsAPI
9
+ include BaseAPI
10
+ include StatsQueryParams
11
+
12
+ # @param client [Mailtrap::Client] The client instance
13
+ def initialize(client = Mailtrap::Client.new)
14
+ @client = client
15
+ end
16
+
17
+ # Get aggregated Email Marketing stats: campaigns and automations together, the same numbers
18
+ # as Email Marketing > Stats Overview in the app. Email API/SMTP traffic is reported by {StatsAPI}.
19
+ # @param start_date [String, Date, Time] Start of the period, inclusive (required)
20
+ # @param end_date [String, Date, Time] End of the period, inclusive (required)
21
+ # @param sending_domain_ids [Array<Integer>] Filter by sending domain IDs
22
+ # @param sources [Array<String>] Filter by source: +campaigns+ or +automations+;
23
+ # omit it, or pass both, to include campaigns and automations together
24
+ # @param email_service_providers [Array<String>] Filter by recipient email service providers
25
+ # @return [MarketingStats] Aggregated Email Marketing stats
26
+ # @!macro api_errors
27
+ # @raise [ArgumentError] If a date is not a Date, Time, or String in +YYYY-MM-DD+ format
28
+ def get(start_date:, end_date:, sending_domain_ids: nil, sources: nil, email_service_providers: nil)
29
+ query_params = build_query_params(
30
+ start_date, end_date,
31
+ { sending_domain_ids:, sources:, email_service_providers: }
32
+ )
33
+ response = client.get(base_path, query_params)
34
+ build_entity(response[:data], MarketingStats)
35
+ end
36
+
37
+ private
38
+
39
+ def base_path
40
+ '/api/marketing/stats'
41
+ end
42
+ end
43
+ end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
4
3
  require_relative 'base_api'
4
+ require_relative 'stats_query_params'
5
5
  require_relative 'sending_stats'
6
6
  require_relative 'sending_stat_group'
7
7
 
8
8
  module Mailtrap
9
9
  class StatsAPI
10
10
  include BaseAPI
11
+ include StatsQueryParams
11
12
 
12
- ARRAY_FILTERS = %i[sending_domain_ids sending_streams categories email_service_providers].freeze
13
13
  GROUP_KEYS = {
14
14
  'domains' => :sending_domain_id,
15
15
  'categories' => :category,
@@ -112,38 +112,6 @@ module Mailtrap
112
112
  end
113
113
  end
114
114
 
115
- def build_query_params(start_date, end_date, filters)
116
- params = { start_date: normalize_date(start_date), end_date: normalize_date(end_date) }
117
-
118
- ARRAY_FILTERS.each do |filter_key|
119
- values = filters[filter_key]
120
- params["#{filter_key}[]"] = values if values
121
- end
122
-
123
- params
124
- end
125
-
126
- def normalize_date(value)
127
- case value
128
- when Date
129
- value.iso8601
130
- when Time
131
- value.strftime('%F')
132
- when String
133
- unless /\A\d{4}-\d{2}-\d{2}\z/.match?(value)
134
- raise ArgumentError,
135
- "Invalid date: #{value.inspect}. Expected a Date, Time, or String in YYYY-MM-DD format."
136
- end
137
-
138
- Date.iso8601(value).iso8601
139
- else
140
- raise ArgumentError,
141
- "Invalid date: #{value.inspect}. Expected a Date, Time, or String in YYYY-MM-DD format."
142
- end
143
- rescue Date::Error
144
- raise ArgumentError, "Invalid date: #{value.inspect}. Expected a Date, Time, or String in YYYY-MM-DD format."
145
- end
146
-
147
115
  def base_path
148
116
  "/api/accounts/#{account_id}/stats"
149
117
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Mailtrap
6
+ # Query parameters of the sending stats and Email Marketing stats endpoints: the period as
7
+ # +YYYY-MM-DD+ dates and every array filter as a repeated +key[]+ parameter. A +nil+ or empty
8
+ # filter is left out.
9
+ module StatsQueryParams
10
+ private
11
+
12
+ def build_query_params(start_date, end_date, filters)
13
+ params = { start_date: normalize_date(start_date), end_date: normalize_date(end_date) }
14
+ filters.each { |filter_key, values| params["#{filter_key}[]"] = values unless Array(values).empty? }
15
+ params
16
+ end
17
+
18
+ def normalize_date(value)
19
+ case value
20
+ when Date, Time # DateTime is a Date, but its #iso8601 includes the time of day
21
+ return value.strftime('%F')
22
+ when String
23
+ return value if /\A\d{4}-\d{2}-\d{2}\z/.match?(value) && Date.valid_date?(*value.split('-').map(&:to_i))
24
+ end
25
+
26
+ raise ArgumentError, "Invalid date: #{value.inspect}. Expected a Date, Time, or String in YYYY-MM-DD format."
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailtrap
4
- VERSION = '2.17.0'
4
+ VERSION = '2.19.0'
5
5
  end
data/lib/mailtrap.rb CHANGED
@@ -21,6 +21,7 @@ require_relative 'mailtrap/contact_events_api'
21
21
  require_relative 'mailtrap/suppressions_api'
22
22
  require_relative 'mailtrap/tracking_opt_outs_api'
23
23
  require_relative 'mailtrap/email_campaigns_api'
24
+ require_relative 'mailtrap/marketing_stats_api'
24
25
  require_relative 'mailtrap/sending_domains_api'
25
26
  require_relative 'mailtrap/company_info_api'
26
27
  require_relative 'mailtrap/email_logs_api'
@@ -35,6 +36,7 @@ require_relative 'mailtrap/inbound_folders_api'
35
36
  require_relative 'mailtrap/inbound_inboxes_api'
36
37
  require_relative 'mailtrap/inbound_messages_api'
37
38
  require_relative 'mailtrap/inbound_threads_api'
39
+ require_relative 'mailtrap/inbound_forward_rules_api'
38
40
 
39
41
  module Mailtrap
40
42
  # @!macro api_errors
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailtrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.17.0
4
+ version: 2.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Railsware Products Studio LLC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-07 00:00:00.000000000 Z
11
+ date: 2026-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -85,6 +85,11 @@ files:
85
85
  - lib/mailtrap/inbound_attachment.rb
86
86
  - lib/mailtrap/inbound_folder.rb
87
87
  - lib/mailtrap/inbound_folders_api.rb
88
+ - lib/mailtrap/inbound_forward_outcome.rb
89
+ - lib/mailtrap/inbound_forward_rule.rb
90
+ - lib/mailtrap/inbound_forward_rule_condition.rb
91
+ - lib/mailtrap/inbound_forward_rule_destination.rb
92
+ - lib/mailtrap/inbound_forward_rules_api.rb
88
93
  - lib/mailtrap/inbound_inbox.rb
89
94
  - lib/mailtrap/inbound_inboxes_api.rb
90
95
  - lib/mailtrap/inbound_message.rb
@@ -93,6 +98,7 @@ files:
93
98
  - lib/mailtrap/inbound_send_result.rb
94
99
  - lib/mailtrap/inbound_thread.rb
95
100
  - lib/mailtrap/inbound_thread_message.rb
101
+ - lib/mailtrap/inbound_thread_message_delivery.rb
96
102
  - lib/mailtrap/inbound_threads_api.rb
97
103
  - lib/mailtrap/inbound_threads_list_response.rb
98
104
  - lib/mailtrap/inbox.rb
@@ -100,6 +106,8 @@ files:
100
106
  - lib/mailtrap/mail.rb
101
107
  - lib/mailtrap/mail/base.rb
102
108
  - lib/mailtrap/mail/from_template.rb
109
+ - lib/mailtrap/marketing_stats.rb
110
+ - lib/mailtrap/marketing_stats_api.rb
103
111
  - lib/mailtrap/permission_resource.rb
104
112
  - lib/mailtrap/permissions_api.rb
105
113
  - lib/mailtrap/project.rb
@@ -113,6 +121,7 @@ files:
113
121
  - lib/mailtrap/sending_stat_group.rb
114
122
  - lib/mailtrap/sending_stats.rb
115
123
  - lib/mailtrap/stats_api.rb
124
+ - lib/mailtrap/stats_query_params.rb
116
125
  - lib/mailtrap/sub_account.rb
117
126
  - lib/mailtrap/sub_accounts_api.rb
118
127
  - lib/mailtrap/suppression.rb