mailtrap 2.8.0 → 2.9.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: ad3283b7e6c8af70b1ac8bb3a965868e3b312c01682615c86f7da5104add3bcb
4
- data.tar.gz: 8bab417f54c310a6a92b93ed4a1c6ca6a4cd88dae2e0614e3d2f21cda05d8cf0
3
+ metadata.gz: c1d2ec6f013c1c734b375a56217c2ec6373904851fdc28f25147932bf7d44225
4
+ data.tar.gz: 3a7c2994b477de66e566ad9cc41c5ca39d70641fa096c92a47af4c0289de6808
5
5
  SHA512:
6
- metadata.gz: 317490e679342d1c9ac8ae12162268c4102ee410a3d4a9896237894c2a5cd39063595c613d248938a1770cd8f24c7cb4dc72f109c1dabec48f920f92f47cd89d
7
- data.tar.gz: 7da01e190af37689aff6aacdeb411f0858c7c75baf809b51266db920e2988021343e73f164728d9d9bf857139ee2f30cbf004b6c50782d7394685ef6513f05d8
6
+ metadata.gz: 1c2176601df89656a773772072952169caf35c0cff0d193cdab25c07956d09d9ab828b9e2995581512312f8e33f35605623b89052950752d8fc6a6c13cb3f0fc
7
+ data.tar.gz: 7661abf25236f9bec0a26f5463d92074a2e76b18bb9f5fc1067c3b2f810a7eed518e1a0d211ac61c11cde4eaaeb4542376ddd5ebd9785678adb225be3838092b
data/CHANGELOG.md CHANGED
@@ -1,25 +1,36 @@
1
+ ## [2.9.0] - 2026-03-13
2
+
3
+ - Add Sending Stats API
4
+ - Parse `reply_to` as a structured address field instead of passing it as a raw
5
+ header when sending with Action Mailer
6
+
1
7
  ## [2.8.0] - 2026-03-03
8
+
2
9
  - Add Account Accesses API
3
10
  - Add Billing API
4
11
 
5
- ## [2.7.0] - 2026-02-24
12
+ ## [2.7.0] - 2026-02-24
13
+
6
14
  - Add Sandbox Messages API
7
15
  - Add Sending Domains API
8
16
  - Add Sandbox Attachments API
9
17
  - Add Accounts API
10
18
 
11
19
  ## [2.6.0] - 2026-01-27
20
+
12
21
  - Add Inboxes API
13
22
  - Add Projects API
14
23
  - Models' `to_h` now returns all fields without compacting
15
24
 
16
25
  ## [2.5.0] - 2025-11-10
26
+
17
27
  - Add Contact Imports API
18
28
  - Add Suppressions API
19
29
  - Write the message IDs to the message when sending with Action Mailer
20
30
  - Fix versioning :)
21
31
 
22
32
  ## [2.4.1] - 2025-08-21
33
+
23
34
  - Set `template_uuid` and `template_variables` when building mail from `Mail::Message`
24
35
 
25
36
  ## [2.4.0] - 2025-08-04
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mailtrap (2.8.0)
4
+ mailtrap (2.9.0)
5
5
  base64
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -177,6 +177,7 @@ Email API:
177
177
  - Full Email Sending – [`full.rb`](examples/full.rb)
178
178
  - Batch Sending – [`batch.rb`](examples/batch.rb)
179
179
  - Sending Domains API – [`sending_domains_api.rb`](examples/sending_domains_api.rb)
180
+ - Sending Stats API – [`stats_api.rb`](examples/stats_api.rb)
180
181
 
181
182
  Email Sandbox (Testing):
182
183
 
data/lib/mailtrap/mail.rb CHANGED
@@ -17,6 +17,7 @@ module Mailtrap
17
17
  category
18
18
  customvariables
19
19
  contenttype
20
+ replyto
20
21
  ].freeze
21
22
  private_constant :SPECIAL_HEADERS
22
23
 
@@ -189,12 +190,13 @@ module Mailtrap
189
190
  # Builds a mail object from Mail::Message
190
191
  # @param message [Mail::Message]
191
192
  # @return [Mailtrap::Mail::Base]
192
- def from_message(message)
193
+ def from_message(message) # rubocop:disable Metrics/AbcSize
193
194
  Mailtrap::Mail::Base.new(
194
195
  from: prepare_addresses(message['from']).first,
195
196
  to: prepare_addresses(message['to']),
196
197
  cc: prepare_addresses(message['cc']),
197
198
  bcc: prepare_addresses(message['bcc']),
199
+ reply_to: prepare_addresses(message['reply-to']).first,
198
200
  subject: message.subject,
199
201
  text: prepare_text_part(message),
200
202
  html: prepare_html_part(message),
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for grouped Sending Stats data
5
+ # @attr_reader name [Symbol] Group type (:category, :date, :sending_domain_id, :email_service_provider)
6
+ # @attr_reader value [String, Integer] Group value (e.g., "Transactional", "2026-01-01", 1, "Gmail")
7
+ # @attr_reader stats [SendingStats] Sending stats for this group
8
+ #
9
+ SendingStatGroup = Struct.new(
10
+ :name,
11
+ :value,
12
+ :stats,
13
+ keyword_init: true
14
+ )
15
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mailtrap
4
+ # Data Transfer Object for Sending Stats data
5
+ # @see https://docs.mailtrap.io/developers/email-sending-stats
6
+ # @attr_reader delivery_count [Integer] Number of delivered emails
7
+ # @attr_reader delivery_rate [Float] Delivery rate
8
+ # @attr_reader bounce_count [Integer] Number of bounced emails
9
+ # @attr_reader bounce_rate [Float] Bounce rate
10
+ # @attr_reader open_count [Integer] Number of opened emails
11
+ # @attr_reader open_rate [Float] Open rate
12
+ # @attr_reader click_count [Integer] Number of clicked emails
13
+ # @attr_reader click_rate [Float] Click rate
14
+ # @attr_reader spam_count [Integer] Number of spam reports
15
+ # @attr_reader spam_rate [Float] Spam rate
16
+ #
17
+ SendingStats = Struct.new(
18
+ :delivery_count,
19
+ :delivery_rate,
20
+ :bounce_count,
21
+ :bounce_rate,
22
+ :open_count,
23
+ :open_rate,
24
+ :click_count,
25
+ :click_rate,
26
+ :spam_count,
27
+ :spam_rate,
28
+ keyword_init: true
29
+ )
30
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require_relative 'base_api'
5
+ require_relative 'sending_stats'
6
+ require_relative 'sending_stat_group'
7
+
8
+ module Mailtrap
9
+ class StatsAPI
10
+ include BaseAPI
11
+
12
+ ARRAY_FILTERS = %i[sending_domain_ids sending_streams categories email_service_providers].freeze
13
+ GROUP_KEYS = {
14
+ 'domains' => :sending_domain_id,
15
+ 'categories' => :category,
16
+ 'email_service_providers' => :email_service_provider,
17
+ 'date' => :date
18
+ }.freeze
19
+
20
+ # Get aggregated sending stats
21
+ # @param start_date [String, Date, Time] Start date for the stats period (required)
22
+ # @param end_date [String, Date, Time] End date for the stats period (required)
23
+ # @param sending_domain_ids [Array<Integer>] Filter by sending domain IDs
24
+ # @param sending_streams [Array<String>] Filter by sending streams
25
+ # @param categories [Array<String>] Filter by categories
26
+ # @param email_service_providers [Array<String>] Filter by email service providers
27
+ # @return [SendingStats] Aggregated sending stats
28
+ # @!macro api_errors
29
+ def get(start_date:, end_date:, sending_domain_ids: nil, sending_streams: nil, categories: nil, # rubocop:disable Metrics/ParameterLists
30
+ email_service_providers: nil)
31
+ query_params = build_query_params(
32
+ start_date, end_date,
33
+ { sending_domain_ids:, sending_streams:, categories:, email_service_providers: }
34
+ )
35
+ response = client.get(base_path, query_params)
36
+ build_entity(response, SendingStats)
37
+ end
38
+
39
+ # Get sending stats grouped by domain
40
+ # @param start_date [String, Date, Time] Start date for the stats period (required)
41
+ # @param end_date [String, Date, Time] End date for the stats period (required)
42
+ # @param sending_domain_ids [Array<Integer>] Filter by sending domain IDs
43
+ # @param sending_streams [Array<String>] Filter by sending streams
44
+ # @param categories [Array<String>] Filter by categories
45
+ # @param email_service_providers [Array<String>] Filter by email service providers
46
+ # @return [Array<SendingStatGroup>] Array of SendingStatGroup structs with sending_domain_id and stats
47
+ # @!macro api_errors
48
+ def by_domain(start_date:, end_date:, sending_domain_ids: nil, sending_streams: nil, categories: nil, # rubocop:disable Metrics/ParameterLists
49
+ email_service_providers: nil)
50
+ grouped_stats('domains', start_date, end_date,
51
+ { sending_domain_ids:, sending_streams:, categories:, email_service_providers: })
52
+ end
53
+
54
+ # Get sending stats grouped by category
55
+ # @param start_date [String, Date, Time] Start date for the stats period (required)
56
+ # @param end_date [String, Date, Time] End date for the stats period (required)
57
+ # @param sending_domain_ids [Array<Integer>] Filter by sending domain IDs
58
+ # @param sending_streams [Array<String>] Filter by sending streams
59
+ # @param categories [Array<String>] Filter by categories
60
+ # @param email_service_providers [Array<String>] Filter by email service providers
61
+ # @return [Array<SendingStatGroup>] Array of SendingStatGroup structs with category and stats
62
+ # @!macro api_errors
63
+ def by_category(start_date:, end_date:, sending_domain_ids: nil, sending_streams: nil, categories: nil, # rubocop:disable Metrics/ParameterLists
64
+ email_service_providers: nil)
65
+ grouped_stats('categories', start_date, end_date,
66
+ { sending_domain_ids:, sending_streams:, categories:, email_service_providers: })
67
+ end
68
+
69
+ # Get sending stats grouped by email service provider
70
+ # @param start_date [String, Date, Time] Start date for the stats period (required)
71
+ # @param end_date [String, Date, Time] End date for the stats period (required)
72
+ # @param sending_domain_ids [Array<Integer>] Filter by sending domain IDs
73
+ # @param sending_streams [Array<String>] Filter by sending streams
74
+ # @param categories [Array<String>] Filter by categories
75
+ # @param email_service_providers [Array<String>] Filter by email service providers
76
+ # @return [Array<SendingStatGroup>] Array of SendingStatGroup structs with email_service_provider and stats
77
+ # @!macro api_errors
78
+ def by_email_service_provider(start_date:, end_date:, sending_domain_ids: nil, sending_streams: nil, # rubocop:disable Metrics/ParameterLists
79
+ categories: nil, email_service_providers: nil)
80
+ grouped_stats('email_service_providers', start_date, end_date,
81
+ { sending_domain_ids:, sending_streams:, categories:, email_service_providers: })
82
+ end
83
+
84
+ # Get sending stats grouped by date
85
+ # @param start_date [String, Date, Time] Start date for the stats period (required)
86
+ # @param end_date [String, Date, Time] End date for the stats period (required)
87
+ # @param sending_domain_ids [Array<Integer>] Filter by sending domain IDs
88
+ # @param sending_streams [Array<String>] Filter by sending streams
89
+ # @param categories [Array<String>] Filter by categories
90
+ # @param email_service_providers [Array<String>] Filter by email service providers
91
+ # @return [Array<SendingStatGroup>] Array of SendingStatGroup structs with date and stats
92
+ # @!macro api_errors
93
+ def by_date(start_date:, end_date:, sending_domain_ids: nil, sending_streams: nil, categories: nil, # rubocop:disable Metrics/ParameterLists
94
+ email_service_providers: nil)
95
+ grouped_stats('date', start_date, end_date,
96
+ { sending_domain_ids:, sending_streams:, categories:, email_service_providers: })
97
+ end
98
+
99
+ private
100
+
101
+ def grouped_stats(group, start_date, end_date, filters)
102
+ query_params = build_query_params(start_date, end_date, filters)
103
+ response = client.get("#{base_path}/#{group}", query_params)
104
+ group_key = GROUP_KEYS.fetch(group)
105
+
106
+ response.map do |item|
107
+ SendingStatGroup.new(
108
+ name: group_key,
109
+ value: item[group_key],
110
+ stats: build_entity(item[:stats], SendingStats)
111
+ )
112
+ end
113
+ end
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
+ def base_path
148
+ "/api/accounts/#{account_id}/stats"
149
+ end
150
+ end
151
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailtrap
4
- VERSION = '2.8.0'
4
+ VERSION = '2.9.0'
5
5
  end
data/lib/mailtrap.rb CHANGED
@@ -18,6 +18,7 @@ require_relative 'mailtrap/projects_api'
18
18
  require_relative 'mailtrap/inboxes_api'
19
19
  require_relative 'mailtrap/sandbox_messages_api'
20
20
  require_relative 'mailtrap/sandbox_attachments_api'
21
+ require_relative 'mailtrap/stats_api'
21
22
 
22
23
  module Mailtrap
23
24
  # @!macro api_errors
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailtrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Railsware Products Studio LLC
@@ -79,6 +79,9 @@ files:
79
79
  - lib/mailtrap/sandbox_messages_api.rb
80
80
  - lib/mailtrap/sending_domain.rb
81
81
  - lib/mailtrap/sending_domains_api.rb
82
+ - lib/mailtrap/sending_stat_group.rb
83
+ - lib/mailtrap/sending_stats.rb
84
+ - lib/mailtrap/stats_api.rb
82
85
  - lib/mailtrap/suppression.rb
83
86
  - lib/mailtrap/suppressions_api.rb
84
87
  - lib/mailtrap/version.rb