mailgun-ruby 1.2.14 → 1.2.16

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: 3905ad8ab1dae85ea3b87b10d2ac01700de085adab73d9e02373f4d54e70451d
4
- data.tar.gz: e5794e301066318205a9ffb6de455d73642d3162b1ad75900cefed7aa95db798
3
+ metadata.gz: 230e91483a287bc0ed69c568a1a76f87eca69685274a5027ab8ada2206930205
4
+ data.tar.gz: 78bc23c4966213a45577b279c3de82e01a04292205007d2d07f9b3ad173d0d9f
5
5
  SHA512:
6
- metadata.gz: af8ed54564c2f13b818aa7da6a550b9000b4148ee437b108d01219d80b610580fde3a1973dd831db3ffd8b0dbe934d9288b479a335a5521e3f275815a9f30c8e
7
- data.tar.gz: 5d11d20420e6333e9e71104fc529d80f19ed689cb300bc5b19ec4c2b855e9c92e24e59d7de83122d2bcdc910a0ec60f783ea277e011e8d375bb1e471be30802e
6
+ metadata.gz: 596a9fec66b1f46fb94d713906b37f472f80f8c2e0187c2df7d88e7609e2658a2c428c3bf68e7f2c41b5adc4a74c647e78f84b4ff94f4431b976d771bb4bf201
7
+ data.tar.gz: 94966b3b0325f188a6c9d28fea2e39c45f9a40a7e486f264fac53f111a6c7eada486cf7755698d29f8115b799b9ef39d98160f9ab50d964c48eb60051583f081
data/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.2.16] - 2024-11-29
8
+
9
+ ### Added
10
+
11
+ - Metrics API support (https://github.com/mailgun/mailgun-ruby/pull/326)
12
+
13
+ ## [1.2.15] - 2024-02-13
14
+
15
+ ### Fixed
16
+
17
+ - Remove Openstruct usage (- Remove OpenStruct usage, will warn in Ruby 3.4, raise in Ruby 3.5 (https://github.com/mailgun/mailgun-ruby/issues/321)).
18
+ - Error handling (- Work around error responses without message property (https://github.com/mailgun/mailgun-ruby/pull/324)).
19
+
7
20
  ## [1.2.14] - 2024-02-13
8
21
 
9
22
  ### Added
data/README.md CHANGED
@@ -19,7 +19,7 @@ gem install mailgun-ruby
19
19
  Gemfile:
20
20
 
21
21
  ```ruby
22
- gem 'mailgun-ruby', '~>1.2.14'
22
+ gem 'mailgun-ruby', '~>1.2.16'
23
23
  ```
24
24
 
25
25
  Usage
data/docs/Metrics.md ADDED
@@ -0,0 +1,108 @@
1
+ Mailgun - Metrics
2
+ ====================
3
+
4
+ This is the Mailgun Ruby *Metrics* utilities.
5
+
6
+ The below assumes you've already installed the Mailgun Ruby SDK in to your
7
+ project. If not, go back to the master README for instructions. It currently supports
8
+ all calls except credentials.
9
+
10
+ ---
11
+
12
+ Mailgun collects many different events and generates event metrics which are available
13
+ in your Control Panel. This data is also available via our analytics metrics API endpoint.
14
+
15
+ You can view additional samples in the [metrics_spec.rb](/spec/integration/metrics_spec.rb)
16
+ or the Metrics client API in [metrics.rb](/lib/metrics/metrics.rb).
17
+
18
+ Usage
19
+ -----
20
+
21
+ To get an instance of the Metrics client:
22
+
23
+ ```ruby
24
+ require 'mailgun'
25
+
26
+ mg_client = Mailgun::Client.new('your-api-key', 'mailgun-api-host', 'v1')
27
+ metrics = Mailgun::Metrics.new(mg_client)
28
+ ````
29
+ ---
30
+ Get filtered metrics for an account:
31
+ ```ruby
32
+ options = {
33
+ {
34
+ resolution: 'hour',
35
+ metrics: [
36
+ 'accepted_count',
37
+ 'delivered_count',
38
+ 'clicked_rate',
39
+ 'opened_rate'
40
+ ],
41
+ include_aggregates: true,
42
+ start: 'Tue, 26 Nov 2024 20:56:50 -0500',
43
+ duration: '1m',
44
+ filter: {
45
+ AND: [
46
+ {
47
+ attribute: 'domain',
48
+ comparator: '!=',
49
+ values: [
50
+ {
51
+ label: 'example.com',
52
+ value: 'example.com'
53
+ }
54
+ ]
55
+ }
56
+ ]
57
+ },
58
+ dimensions: ['time'],
59
+ end: 'Tue, 30 Nov 2024 20:56:50 -0500',
60
+ include_subaccounts: true
61
+ }
62
+ }
63
+
64
+ metrics.account_metrics(options)
65
+ ```
66
+ ---
67
+
68
+ Get filtered usage metrics for an account:
69
+ ```ruby
70
+ options = {
71
+ resolution: 'hour',
72
+ metrics: [
73
+ 'accepted_count',
74
+ 'delivered_count',
75
+ 'clicked_rate',
76
+ 'opened_rate'
77
+ ],
78
+ include_aggregates: true,
79
+ start: 'Tue, 26 Nov 2024 20:56:50 -0500',
80
+ duration: '1m',
81
+ filter: {
82
+ AND: [
83
+ {
84
+ attribute: 'domain',
85
+ comparator: '!=',
86
+ values: [
87
+ {
88
+ label: 'example.com',
89
+ value: 'example.com'
90
+ }
91
+ ]
92
+ }
93
+ ]
94
+ },
95
+ dimensions: ['time'],
96
+ end: 'Tue, 30 Nov 2024 20:56:50 -0500',
97
+ include_subaccounts: true
98
+ }
99
+
100
+ metrics.account_usage_metrics(options)
101
+ ```
102
+
103
+ ---
104
+
105
+ More Documentation
106
+ ------------------
107
+ See the official [Mailgun Domain Docs](https://documentation.mailgun.com/docs/mailgun/api-reference/openapi-final/tag/Metrics/)
108
+ for more information
@@ -50,7 +50,8 @@ module Mailgun
50
50
  end
51
51
 
52
52
  begin
53
- api_message = JSON.parse(response.body)['message']
53
+ json = JSON.parse(response.body)
54
+ api_message = json['message'] || json['Error'] || json['error']
54
55
  rescue JSON::ParserError
55
56
  api_message = response.body
56
57
  rescue NoMethodError
@@ -60,7 +61,7 @@ module Mailgun
60
61
  end
61
62
 
62
63
  message = message || ''
63
- message = message + ': ' + api_message
64
+ message = message + ': ' + (api_message || "")
64
65
 
65
66
  super(message, response)
66
67
  rescue NoMethodError, JSON::ParserError
@@ -0,0 +1,61 @@
1
+ require 'mailgun/exceptions/exceptions'
2
+
3
+ module Mailgun
4
+ # A Mailgun::Metrics object is a simple interface to Mailgun Metrics.
5
+ # Uses Mailgun
6
+ class Metrics
7
+ # Public: creates a new Mailgun::Metrics instance.
8
+ # Defaults to Mailgun::Client
9
+ def initialize(client = Mailgun::Client.new(Mailgun.api_key, Mailgun.api_host || 'api.mailgun.net', 'v1'))
10
+ @client = client
11
+ end
12
+
13
+ # Public: Post query to get account metrics
14
+ #
15
+ # options - [Hash] of
16
+ # start - [String] A start date (default: 7 days before current time). Must be in RFC 2822 format.
17
+ # end - [String] An end date (default: current time). Must be in RFC 2822 format.
18
+ # resolution - [String] A resolution in the format of 'day' 'hour' 'month'. Default is day.
19
+ # duration - [String] A duration in the format of '1d' '2h' '2m'. If duration is provided then it is calculated from the end date and overwrites the start date.
20
+ # dimensions - [Array] Attributes of the metric data such as 'subaccount'.
21
+ # metrics - [Array] Name of the metrics to receive the stats for such as 'processed_count'
22
+ # filter - [Object]
23
+ # AND: - [Array] of objects
24
+ # attribute - [String]
25
+ # comparator - [String]
26
+ # values - [Array] of objects
27
+ # label - [String]
28
+ # value - [String]
29
+ # include_subaccounts - [Boolean] Include stats from all subaccounts.
30
+ # include_aggregates - [Boolean] Include top-level aggregate metrics.
31
+ #
32
+ # Returns [Hash] Metrics
33
+ def account_metrics(options={})
34
+ @client.post('analytics/metrics', options.to_json, { "Content-Type" => "application/json" }).to_h!
35
+ end
36
+
37
+ # Public: Post query to get account usage metrics
38
+ #
39
+ # options - [Hash] of
40
+ # start - [String] A start date (default: 7 days before current time). Must be in RFC 2822 format.
41
+ # end - [String] An end date (default: current time). Must be in RFC 2822 format.
42
+ # resolution - [String] A resolution in the format of 'day' 'hour' 'month'. Default is day.
43
+ # duration - [String] A duration in the format of '1d' '2h' '2m'. If duration is provided then it is calculated from the end date and overwrites the start date.
44
+ # dimensions - [Array] Attributes of the metric data such as 'subaccount'.
45
+ # metrics - [Array] Name of the metrics to receive the stats for such as 'processed_count'
46
+ # filter - [Object]
47
+ # AND: - [Array] of objects
48
+ # attribute - [String]
49
+ # comparator - [String]
50
+ # values - [Array] of objects
51
+ # label - [String]
52
+ # value - [String]
53
+ # include_subaccounts - [Boolean] Include stats from all subaccounts.
54
+ # include_aggregates - [Boolean] Include top-level aggregate metrics.
55
+ #
56
+ # Returns [Hash] Metrics
57
+ def account_usage_metrics(options={})
58
+ @client.post('analytics/usage/metrics', options.to_json, { "Content-Type" => "application/json" }).to_h!
59
+ end
60
+ end
61
+ end
@@ -1,5 +1,3 @@
1
- require 'ostruct'
2
-
3
1
  module Mailgun
4
2
  # A Mailgun::Response object is instantiated for each response generated
5
3
  # by the Client request. The Response object supports deserialization of
@@ -12,9 +10,10 @@ module Mailgun
12
10
  # slightly different
13
11
  attr_accessor :body, :code
14
12
 
13
+ ResponseHash = Struct.new(:body, :code)
15
14
  def self.from_hash(h)
16
15
  # Create a "fake" response object with the data passed from h
17
- self.new OpenStruct.new(h)
16
+ self.new ResponseHash.new(h[:body], h[:code])
18
17
  end
19
18
 
20
19
  def initialize(response)
@@ -1,4 +1,4 @@
1
1
  # It's the version. Yeay!
2
2
  module Mailgun
3
- VERSION = '1.2.14'
3
+ VERSION = '1.2.16'
4
4
  end
data/lib/mailgun.rb CHANGED
@@ -18,6 +18,7 @@ require 'mailgun/webhooks/webhooks'
18
18
  require 'mailgun/templates/templates'
19
19
  require 'mailgun/subaccounts/subaccounts'
20
20
  require 'mailgun/tags/tags'
21
+ require 'mailgun/metrics/metrics'
21
22
 
22
23
  # Module for interacting with the sweet Mailgun API.
23
24
  #
@@ -0,0 +1,218 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { cassette_name: 'metrics' }
5
+
6
+ describe Mailgun::Metrics, vcr: vcr_opts do
7
+ let(:metrics) { Mailgun::Metrics.new(Mailgun::Client.new(APIKEY, APIHOST, 'v1')) }
8
+
9
+ describe '#account_metrics' do
10
+ let(:options) do
11
+ {
12
+ resolution: 'hour',
13
+ metrics: [
14
+ 'accepted_count',
15
+ 'delivered_count',
16
+ 'clicked_rate',
17
+ 'opened_rate'
18
+ ],
19
+ include_aggregates: true,
20
+ start: 'Tue, 26 Nov 2024 20:56:50 -0500',
21
+ duration: '1m',
22
+ filter: {
23
+ AND: [
24
+ {
25
+ attribute: 'domain',
26
+ comparator: '!=',
27
+ values: [
28
+ {
29
+ label: 'example.com',
30
+ value: 'example.com'
31
+ }
32
+ ]
33
+ }
34
+ ]
35
+ },
36
+ dimensions: ['time'],
37
+ end: 'Tue, 30 Nov 2024 20:56:50 -0500',
38
+ include_subaccounts: true
39
+ }
40
+ end
41
+
42
+ it 'responds with account metrics' do
43
+ expect(metrics.account_metrics(options)).to eq(
44
+ {
45
+ "start" => "Fri, 01 Nov 2024 01:00:00 +0000",
46
+ "end" => "Sun, 01 Dec 2024 01:00:00 +0000",
47
+ "resolution" => "hour",
48
+ "duration" => "1m",
49
+ "dimensions" => ["time"],
50
+ "pagination" => {
51
+ "sort" => "", "skip" => 0, "limit" => 1500, "total" => 3
52
+ },
53
+ "items" => [{
54
+ "dimensions" => [{
55
+ "dimension" => "time",
56
+ "value" => "Wed, 27 Nov 2024 12:00:00 +0000",
57
+ "display_value" => "Wed, 27 Nov 2024 12:00:00 +0000"
58
+ }],
59
+ "metrics" => {
60
+ "accepted_count" => 1, "delivered_count" => 1, "opened_rate" => "0.0000", "clicked_rate" => "0.0000"
61
+ }
62
+ },
63
+ {
64
+ "dimensions" => [{
65
+ "dimension" => "time",
66
+ "value" => "Wed, 27 Nov 2024 13:00:00 +0000",
67
+ "display_value" => "Wed, 27 Nov 2024 13:00:00 +0000"
68
+ }],
69
+ "metrics" => {
70
+ "accepted_count" => 1, "delivered_count" => 1, "opened_rate" => "0.0000", "clicked_rate" => "0.0000"
71
+ }
72
+ },
73
+ {
74
+ "dimensions" => [{
75
+ "dimension" => "time",
76
+ "value" => "Thu, 28 Nov 2024 15:00:00 +0000",
77
+ "display_value" => "Thu, 28 Nov 2024 15:00:00 +0000"
78
+ }],
79
+ "metrics" => {
80
+ "accepted_count" => 1, "delivered_count" => 1, "opened_rate" => "0.0000", "clicked_rate" => "0.0000"
81
+ }
82
+ }
83
+ ],
84
+ "aggregates" => {
85
+ "metrics" => {
86
+ "accepted_count" => 3, "delivered_count" => 3, "opened_rate" => "0.0000", "clicked_rate" => "0.0000"
87
+ }
88
+ }
89
+ }
90
+ )
91
+ end
92
+ end
93
+
94
+ describe '#account_usage_metrics' do
95
+ let(:options) do
96
+ {
97
+ resolution: 'hour',
98
+ metrics: [
99
+ 'email_preview_count',
100
+ 'email_preview_failed_count',
101
+ 'email_validation_bulk_count',
102
+ 'email_validation_count',
103
+ 'email_validation_list_count',
104
+ 'email_validation_mailgun_count',
105
+ 'email_validation_mailjet_count',
106
+ 'email_validation_public_count',
107
+ 'email_validation_single_count',
108
+ 'email_validation_valid_count',
109
+ 'link_validation_count',
110
+ 'link_validation_failed_count',
111
+ 'processed_count',
112
+ 'seed_test_count'
113
+ ],
114
+ include_aggregates: true,
115
+ start: 'Tue, 26 Nov 2024 20:56:50 -0500',
116
+ duration: '1m',
117
+ filter: {
118
+ AND: [
119
+ {
120
+ attribute: 'subaccount',
121
+ comparator: '!=',
122
+ values: [
123
+ {
124
+ label: '12345',
125
+ value: '12345'
126
+ }
127
+ ]
128
+ }
129
+ ]
130
+ },
131
+ dimensions: ['time'],
132
+ end: 'Tue, 28 Nov 2024 20:56:50 -0500',
133
+ include_subaccounts: true
134
+ }
135
+ end
136
+
137
+ it 'responds with account usage metrics' do
138
+ expect(metrics.account_usage_metrics(options)).to eq(
139
+ {
140
+ "start" => "Tue, 29 Oct 2024 01:00:00 +0000",
141
+ "end" => "Fri, 29 Nov 2024 01:00:00 +0000",
142
+ "resolution" => "hour",
143
+ "duration" => "1m",
144
+ "dimensions" => ["time"],
145
+ "pagination" => {
146
+ "sort" => "", "skip" => 0, "limit" => 1500, "total" => 2
147
+ },
148
+ "items" => [{
149
+ "dimensions" => [{
150
+ "dimension" => "time",
151
+ "value" => "Wed, 27 Nov 2024 00:00:00 +0000",
152
+ "display_value" => "Wed, 27 Nov 2024 00:00:00 +0000"
153
+ }],
154
+ "metrics" => {
155
+ "processed_count" => 2,
156
+ "email_validation_count" => 0,
157
+ "email_validation_public_count" => 0,
158
+ "email_validation_valid_count" => 0,
159
+ "email_validation_single_count" => 0,
160
+ "email_validation_bulk_count" => 0,
161
+ "email_validation_list_count" => 0,
162
+ "email_validation_mailgun_count" => 0,
163
+ "email_validation_mailjet_count" => 0,
164
+ "email_preview_count" => 0,
165
+ "email_preview_failed_count" => 0,
166
+ "link_validation_count" => 0,
167
+ "link_validation_failed_count" => 0,
168
+ "seed_test_count" => 0
169
+ }
170
+ },
171
+ {
172
+ "dimensions" => [{
173
+ "dimension" => "time",
174
+ "value" => "Thu, 28 Nov 2024 00:00:00 +0000",
175
+ "display_value" => "Thu, 28 Nov 2024 00:00:00 +0000"
176
+ }],
177
+ "metrics" => {
178
+ "processed_count" => 1,
179
+ "email_validation_count" => 0,
180
+ "email_validation_public_count" => 0,
181
+ "email_validation_valid_count" => 0,
182
+ "email_validation_single_count" => 0,
183
+ "email_validation_bulk_count" => 0,
184
+ "email_validation_list_count" => 0,
185
+ "email_validation_mailgun_count" => 0,
186
+ "email_validation_mailjet_count" => 0,
187
+ "email_preview_count" => 0,
188
+ "email_preview_failed_count" => 0,
189
+ "link_validation_count" => 0,
190
+ "link_validation_failed_count" => 0,
191
+ "seed_test_count" => 0
192
+ }
193
+ }
194
+ ],
195
+ "aggregates" => {
196
+ "metrics" => {
197
+ "permanent_failed_count" => 0,
198
+ "processed_count" => 3,
199
+ "email_validation_count" => 0,
200
+ "email_validation_public_count" => 0,
201
+ "email_validation_valid_count" => 0,
202
+ "email_validation_single_count" => 0,
203
+ "email_validation_bulk_count" => 0,
204
+ "email_validation_list_count" => 0,
205
+ "email_validation_mailgun_count" => 0,
206
+ "email_validation_mailjet_count" => 0,
207
+ "email_preview_count" => 0,
208
+ "email_preview_failed_count" => 0,
209
+ "link_validation_count" => 0,
210
+ "link_validation_failed_count" => 0,
211
+ "seed_test_count" => 0
212
+ }
213
+ }
214
+ }
215
+ )
216
+ end
217
+ end
218
+ end
@@ -96,19 +96,19 @@ module Mailgun
96
96
  if resource_endpoint == "messages"
97
97
  t = Time.now
98
98
  id = "<#{t.to_i}.#{rand(99999999)}.5817@example.com>"
99
- return OpenStruct.new({ "body" => JSON.generate({"message" => "Queued. Thank you.", "id" => id}) })
99
+ return Response.from_hash({ body: JSON.generate({"message" => "Queued. Thank you.", "id" => id}) })
100
100
  end
101
101
  if resource_endpoint == "bounces"
102
- return OpenStruct.new({ "body" => JSON.generate({"total_count" => 1, "items" => {"created_at" => "Fri, 21 Oct 2011 11:02:55 GMT", "code" => 550, "address" => "baz@example.com", "error" => "Message was not accepted -- invalid mailbox. Local mailbox baz@example.com is unavailable: user not found"}}) })
102
+ return Response.from_hash({ body: JSON.generate({"total_count" => 1, "items" => {"created_at" => "Fri, 21 Oct 2011 11:02:55 GMT", "code" => 550, "address" => "baz@example.com", "error" => "Message was not accepted -- invalid mailbox. Local mailbox baz@example.com is unavailable: user not found"}}) })
103
103
  end
104
104
  if resource_endpoint == "lists"
105
- return OpenStruct.new({ "body" => JSON.generate({"member" => {"vars" => {"age" => 26}, "name" => "Foo Bar", "subscribed" => false, "address" => "bar@example.com"}, "message" => "Mailing list member has been updated"}) })
105
+ return Response.from_hash({ body: JSON.generate({"member" => {"vars" => {"age" => 26}, "name" => "Foo Bar", "subscribed" => false, "address" => "bar@example.com"}, "message" => "Mailing list member has been updated"}) })
106
106
  end
107
107
  if resource_endpoint == "campaigns"
108
- return OpenStruct.new({ "body" => JSON.generate({"message" => "Campaign has been deleted", "id" => "ABC123"}) })
108
+ return Response.from_hash({ body: JSON.generate({"message" => "Campaign has been deleted", "id" => "ABC123"}) })
109
109
  end
110
110
  if resource_endpoint == "events"
111
- return OpenStruct.new({ "body" => JSON.generate({"items" => [], "paging" => {"next"=> "https://api.mailgun.net/v3/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIFsiZiJdLCBudWxsLCB7ImFjY291bnQuaWQiOiAiNGU4MjMwZjYxNDc2ZDg2NzEzMDBjNDc2IiwgImRvbWFpbi5uYW1lIjogInRoaXNpc2F0ZXN0ZG9tYWluZm9ybWFpbGd1bi5jb20iLCAic2V2ZXJpdHkiOiAiTk9UIGludGVybmFsIn0sIDEwMCwgbnVsbF0=", "previous"=> "https://api.mailgun.net/v2/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDdUMDA6NDU6NTEuNzQxODkyKzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIHsiYWNjb3VudC5pZCI6ICI0ZTgyMzBmNjE0NzZkODY3MTMwMGM0NzYiLCAiZG9tYWluLm5hbWUiOiAidGhpc2lzYXRlc3Rkb21haW5mb3JtYWlsZ3VuLmNvbSIsICJzZXZlcml0eSI6ICJOT1QgaW50ZXJuYWwifSwgMTAwLCBudWxsXQ=="}}) })
111
+ return Response.from_hash({ body: JSON.generate({"items" => [], "paging" => {"next"=> "https://api.mailgun.net/v3/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIFsiZiJdLCBudWxsLCB7ImFjY291bnQuaWQiOiAiNGU4MjMwZjYxNDc2ZDg2NzEzMDBjNDc2IiwgImRvbWFpbi5uYW1lIjogInRoaXNpc2F0ZXN0ZG9tYWluZm9ybWFpbGd1bi5jb20iLCAic2V2ZXJpdHkiOiAiTk9UIGludGVybmFsIn0sIDEwMCwgbnVsbF0=", "previous"=> "https://api.mailgun.net/v2/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDdUMDA6NDU6NTEuNzQxODkyKzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIHsiYWNjb3VudC5pZCI6ICI0ZTgyMzBmNjE0NzZkODY3MTMwMGM0NzYiLCAiZG9tYWluLm5hbWUiOiAidGhpc2lzYXRlc3Rkb21haW5mb3JtYWlsZ3VuLmNvbSIsICJzZXZlcml0eSI6ICJOT1QgaW50ZXJuYWwifSwgMTAwLCBudWxsXQ=="}}) })
112
112
  end
113
113
  end
114
114
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Mailgun::CommunicationError do
4
+ describe '.new' do
5
+ context "when the Response body doesn't have a `message` property" do
6
+ it "doesn't raise an error" do
7
+ expect do
8
+ described_class.new('Boom!', Mailgun::Response.from_hash({ code: 401, body: '{}' }))
9
+ end.not_to raise_error
10
+ end
11
+
12
+ context "when the Response body has an `Error` property" do
13
+ it "uses the `Error` property as the API message" do
14
+ subject = described_class.new('Boom!', Mailgun::Response.from_hash({ code: 401, body: '{"Error":"unauthorized"}' }))
15
+
16
+ expect(subject.message).to eq("Boom!: unauthorized")
17
+ end
18
+ end
19
+
20
+ context "when the Response body has an `error` property" do
21
+ it "uses the `Error` property as the API message" do
22
+ subject = described_class.new('Boom!', Mailgun::Response.from_hash({ code: 401, body: '{"error":"not found"}' }))
23
+
24
+ expect(subject.message).to eq("Boom!: not found")
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,116 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.mailgun.net/v1/analytics/metrics
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"resolution":"hour","metrics":["accepted_count","delivered_count","clicked_rate","opened_rate"],"include_aggregates":true,"start":"Tue,
9
+ 26 Nov 2024 20:56:50 -0500","duration":"1m","filter":{"AND":[{"attribute":"domain","comparator":"!=","values":[{"label":"example.com","value":"example.com"}]}]},"dimensions":["time"],"end":"Tue,
10
+ 30 Nov 2024 20:56:50 -0500","include_subaccounts":true}'
11
+ headers:
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - rest-client/2.1.0 (darwin23 x86_64) ruby/3.1.4p223
16
+ Content-Type:
17
+ - application/json
18
+ Content-Length:
19
+ - '387'
20
+ Accept-Encoding:
21
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
22
+ Host:
23
+ - api.mailgun.net
24
+ Authorization:
25
+ - Basic xxx
26
+ response:
27
+ status:
28
+ code: 200
29
+ message: OK
30
+ headers:
31
+ Access-Control-Allow-Credentials:
32
+ - 'true'
33
+ Access-Control-Allow-Origin:
34
+ - "*"
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Length:
38
+ - '1006'
39
+ Content-Type:
40
+ - application/json; charset=utf-8
41
+ Date:
42
+ - Thu, 28 Nov 2024 18:20:22 GMT
43
+ Strict-Transport-Security:
44
+ - max-age=63072000; includeSubDomains
45
+ X-Mailgun-Key-Id:
46
+ - c02fd0ba-d8dbad66
47
+ X-Xss-Protection:
48
+ - 1; mode=block
49
+ body:
50
+ encoding: UTF-8
51
+ string: '{"start":"Fri, 01 Nov 2024 01:00:00 +0000","end":"Sun, 01 Dec 2024
52
+ 01:00:00 +0000","resolution":"hour","duration":"1m","dimensions":["time"],"pagination":{"sort":"","skip":0,"limit":1500,"total":3},"items":[{"dimensions":[{"dimension":"time","value":"Wed,
53
+ 27 Nov 2024 12:00:00 +0000","display_value":"Wed, 27 Nov 2024 12:00:00 +0000"}],"metrics":{"accepted_count":1,"delivered_count":1,"opened_rate":"0.0000","clicked_rate":"0.0000"}},{"dimensions":[{"dimension":"time","value":"Wed,
54
+ 27 Nov 2024 13:00:00 +0000","display_value":"Wed, 27 Nov 2024 13:00:00 +0000"}],"metrics":{"accepted_count":1,"delivered_count":1,"opened_rate":"0.0000","clicked_rate":"0.0000"}},{"dimensions":[{"dimension":"time","value":"Thu,
55
+ 28 Nov 2024 15:00:00 +0000","display_value":"Thu, 28 Nov 2024 15:00:00 +0000"}],"metrics":{"accepted_count":1,"delivered_count":1,"opened_rate":"0.0000","clicked_rate":"0.0000"}}],"aggregates":{"metrics":{"accepted_count":3,"delivered_count":3,"opened_rate":"0.0000","clicked_rate":"0.0000"}}}
56
+
57
+ '
58
+ http_version:
59
+ recorded_at: Thu, 28 Nov 2024 18:20:22 GMT
60
+ - request:
61
+ method: post
62
+ uri: https://api.mailgun.net/v1/analytics/usage/metrics
63
+ body:
64
+ encoding: UTF-8
65
+ string: '{"resolution":"hour","metrics":["email_preview_count","email_preview_failed_count","email_validation_bulk_count","email_validation_count","email_validation_list_count","email_validation_mailgun_count","email_validation_mailjet_count","email_validation_public_count","email_validation_single_count","email_validation_valid_count","link_validation_count","link_validation_failed_count","processed_count","seed_test_count"],"include_aggregates":true,"start":"Tue,
66
+ 26 Nov 2024 20:56:50 -0500","duration":"1m","filter":{"AND":[{"attribute":"subaccount","comparator":"!=","values":[{"label":"12345","value":"12345"}]}]},"dimensions":["time"],"end":"Tue,
67
+ 28 Nov 2024 20:56:50 -0500","include_subaccounts":true}'
68
+ headers:
69
+ Accept:
70
+ - "*/*"
71
+ User-Agent:
72
+ - rest-client/2.1.0 (darwin23 x86_64) ruby/3.1.4p223
73
+ Content-Type:
74
+ - application/json
75
+ Content-Length:
76
+ - '703'
77
+ Accept-Encoding:
78
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
79
+ Host:
80
+ - api.mailgun.net
81
+ Authorization:
82
+ - Basic xxx
83
+ response:
84
+ status:
85
+ code: 200
86
+ message: OK
87
+ headers:
88
+ Access-Control-Allow-Credentials:
89
+ - 'true'
90
+ Access-Control-Allow-Origin:
91
+ - "*"
92
+ Cache-Control:
93
+ - no-store
94
+ Content-Length:
95
+ - '1795'
96
+ Content-Type:
97
+ - application/json; charset=utf-8
98
+ Date:
99
+ - Thu, 28 Nov 2024 18:20:23 GMT
100
+ Strict-Transport-Security:
101
+ - max-age=63072000; includeSubDomains
102
+ X-Mailgun-Key-Id:
103
+ - c02fd0ba-d8dbad66
104
+ X-Xss-Protection:
105
+ - 1; mode=block
106
+ body:
107
+ encoding: UTF-8
108
+ string: '{"start":"Tue, 29 Oct 2024 01:00:00 +0000","end":"Fri, 29 Nov 2024
109
+ 01:00:00 +0000","resolution":"hour","duration":"1m","dimensions":["time"],"pagination":{"sort":"","skip":0,"limit":1500,"total":2},"items":[{"dimensions":[{"dimension":"time","value":"Wed,
110
+ 27 Nov 2024 00:00:00 +0000","display_value":"Wed, 27 Nov 2024 00:00:00 +0000"}],"metrics":{"processed_count":2,"email_validation_count":0,"email_validation_public_count":0,"email_validation_valid_count":0,"email_validation_single_count":0,"email_validation_bulk_count":0,"email_validation_list_count":0,"email_validation_mailgun_count":0,"email_validation_mailjet_count":0,"email_preview_count":0,"email_preview_failed_count":0,"link_validation_count":0,"link_validation_failed_count":0,"seed_test_count":0}},{"dimensions":[{"dimension":"time","value":"Thu,
111
+ 28 Nov 2024 00:00:00 +0000","display_value":"Thu, 28 Nov 2024 00:00:00 +0000"}],"metrics":{"processed_count":1,"email_validation_count":0,"email_validation_public_count":0,"email_validation_valid_count":0,"email_validation_single_count":0,"email_validation_bulk_count":0,"email_validation_list_count":0,"email_validation_mailgun_count":0,"email_validation_mailjet_count":0,"email_preview_count":0,"email_preview_failed_count":0,"link_validation_count":0,"link_validation_failed_count":0,"seed_test_count":0}}],"aggregates":{"metrics":{"permanent_failed_count":0,"processed_count":3,"email_validation_count":0,"email_validation_public_count":0,"email_validation_valid_count":0,"email_validation_single_count":0,"email_validation_bulk_count":0,"email_validation_list_count":0,"email_validation_mailgun_count":0,"email_validation_mailjet_count":0,"email_preview_count":0,"email_preview_failed_count":0,"link_validation_count":0,"link_validation_failed_count":0,"seed_test_count":0}}}
112
+
113
+ '
114
+ http_version:
115
+ recorded_at: Thu, 28 Nov 2024 18:20:23 GMT
116
+ recorded_with: VCR 3.0.3
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailgun-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.14
4
+ version: 1.2.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mailgun
8
8
  - Travis Swientek
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-02-13 00:00:00.000000000 Z
12
+ date: 2024-11-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -158,6 +158,7 @@ files:
158
158
  - docs/Events.md
159
159
  - docs/MessageBuilder.md
160
160
  - docs/Messages.md
161
+ - docs/Metrics.md
161
162
  - docs/OptInHandler.md
162
163
  - docs/Snippets.md
163
164
  - docs/Subaccounts.md
@@ -178,6 +179,7 @@ files:
178
179
  - lib/mailgun/lists/opt_in_handler.rb
179
180
  - lib/mailgun/messages/batch_message.rb
180
181
  - lib/mailgun/messages/message_builder.rb
182
+ - lib/mailgun/metrics/metrics.rb
181
183
  - lib/mailgun/response.rb
182
184
  - lib/mailgun/subaccounts/subaccounts.rb
183
185
  - lib/mailgun/suppressions.rb
@@ -203,6 +205,7 @@ files:
203
205
  - spec/integration/mailer_spec.rb
204
206
  - spec/integration/mailgun_spec.rb
205
207
  - spec/integration/messages/sample_data/mime.txt
208
+ - spec/integration/metrics_spec.rb
206
209
  - spec/integration/routes_spec.rb
207
210
  - spec/integration/stats_spec.rb
208
211
  - spec/integration/subaccounts_spec.rb
@@ -214,6 +217,7 @@ files:
214
217
  - spec/spec_helper.rb
215
218
  - spec/unit/connection/test_client.rb
216
219
  - spec/unit/events/events_spec.rb
220
+ - spec/unit/exceptions/exceptions_spec.rb
217
221
  - spec/unit/lists/opt_in_handler_spec.rb
218
222
  - spec/unit/mailgun_spec.rb
219
223
  - spec/unit/messages/batch_message_spec.rb
@@ -239,6 +243,7 @@ files:
239
243
  - vcr_cassettes/mailing_list.todo.yml
240
244
  - vcr_cassettes/mailing_list.yml
241
245
  - vcr_cassettes/message_deliver.yml
246
+ - vcr_cassettes/metrics.yml
242
247
  - vcr_cassettes/routes.yml
243
248
  - vcr_cassettes/send_message.yml
244
249
  - vcr_cassettes/stats.yml
@@ -254,7 +259,7 @@ licenses:
254
259
  metadata:
255
260
  documentation_uri: https://documentation.mailgun.com/
256
261
  source_code_uri: https://github.com/mailgun/mailgun-ruby
257
- post_install_message:
262
+ post_install_message:
258
263
  rdoc_options: []
259
264
  require_paths:
260
265
  - lib
@@ -269,9 +274,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
274
  - !ruby/object:Gem::Version
270
275
  version: '0'
271
276
  requirements: []
272
- rubyforge_project:
273
- rubygems_version: 2.7.6
274
- signing_key:
277
+ rubygems_version: 3.3.26
278
+ signing_key:
275
279
  specification_version: 4
276
280
  summary: Mailgun's Official Ruby SDK
277
281
  test_files:
@@ -286,6 +290,7 @@ test_files:
286
290
  - spec/integration/mailer_spec.rb
287
291
  - spec/integration/mailgun_spec.rb
288
292
  - spec/integration/messages/sample_data/mime.txt
293
+ - spec/integration/metrics_spec.rb
289
294
  - spec/integration/routes_spec.rb
290
295
  - spec/integration/stats_spec.rb
291
296
  - spec/integration/subaccounts_spec.rb
@@ -297,6 +302,7 @@ test_files:
297
302
  - spec/spec_helper.rb
298
303
  - spec/unit/connection/test_client.rb
299
304
  - spec/unit/events/events_spec.rb
305
+ - spec/unit/exceptions/exceptions_spec.rb
300
306
  - spec/unit/lists/opt_in_handler_spec.rb
301
307
  - spec/unit/mailgun_spec.rb
302
308
  - spec/unit/messages/batch_message_spec.rb