mailgun-ruby 1.4.1 → 1.4.2

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/README.md +1 -1
  4. data/Rakefile +5 -3
  5. data/docs/AnalyticsTags.md +63 -0
  6. data/lib/mailgun/address.rb +5 -5
  7. data/lib/mailgun/chains.rb +2 -3
  8. data/lib/mailgun/client.rb +47 -51
  9. data/lib/mailgun/domains/domains.rb +7 -8
  10. data/lib/mailgun/events/events.rb +4 -3
  11. data/lib/mailgun/exceptions/exceptions.rb +12 -15
  12. data/lib/mailgun/helpers/api_version_checker.rb +6 -1
  13. data/lib/mailgun/lists/opt_in_handler.rb +4 -6
  14. data/lib/mailgun/logs/logs.rb +4 -2
  15. data/lib/mailgun/messages/batch_message.rb +8 -9
  16. data/lib/mailgun/messages/message_builder.rb +36 -24
  17. data/lib/mailgun/metrics/metrics.rb +6 -4
  18. data/lib/mailgun/response.rb +11 -9
  19. data/lib/mailgun/subaccounts/subaccounts.rb +13 -8
  20. data/lib/mailgun/suppressions.rb +36 -43
  21. data/lib/mailgun/tags/analytics_tags.rb +33 -2
  22. data/lib/mailgun/tags/tags.rb +25 -17
  23. data/lib/mailgun/templates/templates.rb +40 -29
  24. data/lib/mailgun/version.rb +3 -1
  25. data/lib/mailgun/webhooks/webhooks.rb +22 -19
  26. data/lib/mailgun-ruby.rb +2 -0
  27. data/lib/mailgun.rb +4 -4
  28. data/lib/railgun/attachment.rb +9 -14
  29. data/lib/railgun/errors.rb +2 -3
  30. data/lib/railgun/mailer.rb +35 -39
  31. data/lib/railgun/railtie.rb +2 -0
  32. data/lib/railgun.rb +2 -0
  33. data/mailgun.gemspec +12 -11
  34. data/spec/integration/analytics_tags_spec.rb +54 -0
  35. data/spec/integration/bounces_spec.rb +12 -11
  36. data/spec/integration/campaign_spec.rb +20 -18
  37. data/spec/integration/complaints_spec.rb +8 -6
  38. data/spec/integration/domains_spec.rb +6 -6
  39. data/spec/integration/email_validation_spec.rb +35 -34
  40. data/spec/integration/events_spec.rb +7 -5
  41. data/spec/integration/list_members_spec.rb +27 -26
  42. data/spec/integration/list_spec.rb +22 -21
  43. data/spec/integration/logs_spec.rb +48 -46
  44. data/spec/integration/mailer_spec.rb +7 -3
  45. data/spec/integration/mailgun_spec.rb +82 -90
  46. data/spec/integration/metrics_spec.rb +130 -130
  47. data/spec/integration/routes_spec.rb +41 -40
  48. data/spec/integration/stats_spec.rb +4 -2
  49. data/spec/integration/subaccounts_spec.rb +9 -10
  50. data/spec/integration/suppressions_spec.rb +21 -20
  51. data/spec/integration/templates_spec.rb +14 -12
  52. data/spec/integration/unsubscribes_spec.rb +8 -6
  53. data/spec/integration/webhook_spec.rb +13 -12
  54. data/spec/spec_helper.rb +8 -8
  55. data/spec/unit/connection/test_client.rb +61 -55
  56. data/spec/unit/events/events_spec.rb +25 -22
  57. data/spec/unit/exceptions/exceptions_spec.rb +8 -7
  58. data/spec/unit/lists/opt_in_handler_spec.rb +8 -6
  59. data/spec/unit/mailgun_spec.rb +64 -63
  60. data/spec/unit/messages/batch_message_spec.rb +15 -15
  61. data/spec/unit/messages/message_builder_spec.rb +98 -94
  62. data/spec/unit/railgun/content_type_spec.rb +24 -23
  63. data/spec/unit/railgun/mailer_spec.rb +58 -58
  64. data/vcr_cassettes/analytics_tags.yml +187 -0
  65. metadata +49 -33
  66. data/.rubocop.yml +0 -8
  67. data/.rubocop_todo.yml +0 -22
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'mailgun'
3
5
 
@@ -37,65 +39,65 @@ describe Mailgun::Logs, vcr: vcr_opts do
37
39
  it 'responds with account logs' do
38
40
  expect(logs.account_logs(options)).to eq(
39
41
  {
40
- "start" => "Wed, 25 Jun 2025 00:00:00 -0000",
41
- "end" => "Wed, 25 Jun 2025 23:00:00 -0000",
42
- "items" => [
42
+ 'start' => 'Wed, 25 Jun 2025 00:00:00 -0000',
43
+ 'end' => 'Wed, 25 Jun 2025 23:00:00 -0000',
44
+ 'items' => [
43
45
  {
44
- "id" => "123",
45
- "event" => "accepted",
46
- "@timestamp" => "2025-06-25T17:19:51.166Z",
47
- "account" => {
48
- "id" => "123"
46
+ 'id' => '123',
47
+ 'event' => 'accepted',
48
+ '@timestamp' => '2025-06-25T17:19:51.166Z',
49
+ 'account' => {
50
+ 'id' => '123'
49
51
  },
50
- "method" => "HTTP",
51
- "originating-ip" => "123.123.12.123",
52
- "api-key-id" => "xxx",
53
- "domain" => {
54
- "name" => "example.mailgun.org"
52
+ 'method' => 'HTTP',
53
+ 'originating-ip' => '123.123.12.123',
54
+ 'api-key-id' => 'xxx',
55
+ 'domain' => {
56
+ 'name' => 'example.mailgun.org'
55
57
  },
56
- "recipient" => "alex@example.com",
57
- "recipient-domain" => "example.com",
58
- "envelope" => {
59
- "sender" => "example.mailgun.org",
60
- "transport" => "smtp",
61
- "targets" => "alex@example.com"
58
+ 'recipient' => 'alex@example.com',
59
+ 'recipient-domain' => 'example.com',
60
+ 'envelope' => {
61
+ 'sender' => 'example.mailgun.org',
62
+ 'transport' => 'smtp',
63
+ 'targets' => 'alex@example.com'
62
64
  },
63
- "storage" => {
64
- "region" => "us-east4",
65
- "env" => "production",
66
- "key" => "xxx",
67
- "url" => ["https://storage.api.mailgun.net/v3/domains/example.mailgun.org/messages/123"]
65
+ 'storage' => {
66
+ 'region' => 'us-east4',
67
+ 'env' => 'production',
68
+ 'key' => 'xxx',
69
+ 'url' => ['https://storage.api.mailgun.net/v3/domains/example.mailgun.org/messages/123']
68
70
  },
69
- "log-level" => "info",
70
- "user-variables" => "{}",
71
- "message" => {
72
- "headers" => {
73
- "to" => "alex@example.com",
74
- "message-id" => "123@example.mailgun.org",
75
- "from" => "bob@sending_domain.com+4",
76
- "subject" => "The Ruby SDK is awesome!"
71
+ 'log-level' => 'info',
72
+ 'user-variables' => '{}',
73
+ 'message' => {
74
+ 'headers' => {
75
+ 'to' => 'alex@example.com',
76
+ 'message-id' => '123@example.mailgun.org',
77
+ 'from' => 'bob@sending_domain.com+4',
78
+ 'subject' => 'The Ruby SDK is awesome!'
77
79
  },
78
- "attachments" => [
80
+ 'attachments' => [
79
81
  {
80
- "filename" => "image.jpg",
81
- "content-type" => "image/jpeg",
82
- "size" => 16712
82
+ 'filename' => 'image.jpg',
83
+ 'content-type' => 'image/jpeg',
84
+ 'size' => 16_712
83
85
  }
84
86
  ],
85
- "size" => 23476
87
+ 'size' => 23_476
86
88
  },
87
- "flags" => {
88
- "is-authenticated" => true,
89
- "is-system-test" => false,
90
- "is-routed" => false,
91
- "is-test-mode" => false,
92
- "is-delayed-bounce" => false,
93
- "is-callback" => false
89
+ 'flags' => {
90
+ 'is-authenticated' => true,
91
+ 'is-system-test' => false,
92
+ 'is-routed' => false,
93
+ 'is-test-mode' => false,
94
+ 'is-delayed-bounce' => false,
95
+ 'is-callback' => false
94
96
  }
95
97
  }
96
98
  ],
97
- "pagination" => {},
98
- "aggregates" => {}
99
+ 'pagination' => {},
100
+ 'aggregates' => {}
99
101
  }
100
102
  )
101
103
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'json'
3
5
  require 'logger'
@@ -21,7 +23,7 @@ class IntegrationUnitTestMailer < ActionMailer::Base
21
23
  end
22
24
  end
23
25
 
24
- vcr_opts = { :cassette_name => 'message_deliver' }
26
+ vcr_opts = { cassette_name: 'message_deliver' }
25
27
 
26
28
  describe 'Message deliver', vcr: vcr_opts do
27
29
  let(:domain) { TESTDOMAIN || 'DOMAIN.TEST' }
@@ -43,7 +45,7 @@ describe 'Message deliver', vcr: vcr_opts do
43
45
  end
44
46
  end
45
47
 
46
- vcr_opts = { :cassette_name => 'mailer_invalid_domain' }
48
+ vcr_opts = { cassette_name: 'mailer_invalid_domain' }
47
49
 
48
50
  describe 'Invalid domain', vcr: vcr_opts do
49
51
  let(:domain) { 'not-our-doma.in' }
@@ -56,6 +58,8 @@ describe 'Invalid domain', vcr: vcr_opts do
56
58
  let(:mail) { IntegrationUnitTestMailer.plain_message('sally@not-our-doma.in', "bob@#{domain}", 'subject', {}) }
57
59
 
58
60
  it 'raises expected error' do
59
- expect { Railgun::Mailer.new(config).deliver!(mail) }.to raise_error Mailgun::Unauthorized, /Invalid Domain or API key/
61
+ expect do
62
+ Railgun::Mailer.new(config).deliver!(mail)
63
+ end.to raise_error Mailgun::Unauthorized, /Invalid Domain or API key/
60
64
  end
61
65
  end
@@ -1,105 +1,99 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'mailgun'
3
5
  require 'mailgun/exceptions/exceptions'
4
6
 
5
- describe 'Mailgun instantiation', vcr: { :cassette_name => "instance" } do
7
+ describe 'Mailgun instantiation', vcr: { cassette_name: 'instance' } do
6
8
  it 'instantiates an HttpClient object' do
7
- expect {@mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)}.not_to raise_error
9
+ expect { @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL) }.not_to raise_error
8
10
  end
9
11
  end
10
12
 
11
- describe 'Client exceptions', vcr: { :cassette_name => "exceptions" } do
13
+ describe 'Client exceptions', vcr: { cassette_name: 'exceptions' } do
12
14
  before(:all) do
13
15
  @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
14
16
  @domain = TESTDOMAIN || 'DOMAIN.TEST'
15
17
  end
16
18
 
17
19
  it 'display useful error information' do
18
- begin
19
- @mg_obj.send_message("not-our-doma.in", {
20
- :from => "sally@not-our-doma.in",
21
- :to => "bob@#{@domain}",
22
- :subject => 'Exception Integration Test',
23
- :text => 'INTEGRATION TESTING'
24
- })
25
- rescue Mailgun::CommunicationError => err
26
- expect(err.message).to include('404')
27
- expect(err.message).to include('Domain not found: not-our-doma.in')
28
- else
29
- fail
30
- end
20
+ @mg_obj.send_message('not-our-doma.in', {
21
+ from: 'sally@not-our-doma.in',
22
+ to: "bob@#{@domain}",
23
+ subject: 'Exception Integration Test',
24
+ text: 'INTEGRATION TESTING'
25
+ })
26
+ rescue Mailgun::CommunicationError => e
27
+ expect(e.message).to include('404')
28
+ expect(e.message).to include('Domain not found: not-our-doma.in')
29
+ else
30
+ raise
31
31
  end
32
32
  end
33
33
 
34
- describe 'Client exceptions', vcr: { :cassette_name => "exceptions-invalid-api-key" } do
34
+ describe 'Client exceptions', vcr: { cassette_name: 'exceptions-invalid-api-key' } do
35
35
  before(:all) do
36
36
  @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
37
37
  @domain = TESTDOMAIN || 'DOMAIN.TEST'
38
38
  end
39
39
 
40
40
  it 'displays error information that API key is invalid' do
41
- begin
42
- @mg_obj.send_message(@domain, {
43
- :from => "sally@#{@domain}",
44
- :to => "sally@#{@domain}",
45
- :subject => 'Exception Integration Test',
46
- :text => 'INTEGRATION TESTING'
47
- })
48
- rescue Mailgun::Unauthorized => err
49
- expect(err.message).to include('401')
50
- expect(err.message).to include('Invalid Domain or API key')
51
- else
52
- fail
53
- end
41
+ @mg_obj.send_message(@domain, {
42
+ from: "sally@#{@domain}",
43
+ to: "sally@#{@domain}",
44
+ subject: 'Exception Integration Test',
45
+ text: 'INTEGRATION TESTING'
46
+ })
47
+ rescue Mailgun::Unauthorized => e
48
+ expect(e.message).to include('401')
49
+ expect(e.message).to include('Invalid Domain or API key')
50
+ else
51
+ raise
54
52
  end
55
53
  end
56
54
 
57
- describe 'Client exceptions', vcr: { :cassette_name => "exceptions-invalid-data" } do
55
+ describe 'Client exceptions', vcr: { cassette_name: 'exceptions-invalid-data' } do
58
56
  before(:all) do
59
57
  @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
60
58
  @domain = TESTDOMAIN || 'DOMAIN.TEST'
61
59
  end
62
60
 
63
61
  it 'display useful error information' do
64
- begin
65
- @mg_obj.send_message(@domain, {
66
- :from => "sally@#{@domain}",
67
- :to => "sally#{@domain}",
68
- :subject => 'Exception Integration Test',
69
- :text => 'INTEGRATION TESTING'
70
- })
71
- rescue Mailgun::BadRequest => err
72
- expect(err.message).to include('400')
73
- expect(err.message).to include('to parameter is not a valid address. please check documentation')
74
- else
75
- fail
76
- end
62
+ @mg_obj.send_message(@domain, {
63
+ from: "sally@#{@domain}",
64
+ to: "sally#{@domain}",
65
+ subject: 'Exception Integration Test',
66
+ text: 'INTEGRATION TESTING'
67
+ })
68
+ rescue Mailgun::BadRequest => e
69
+ expect(e.message).to include('400')
70
+ expect(e.message).to include('to parameter is not a valid address. please check documentation')
71
+ else
72
+ raise
77
73
  end
78
74
  end
79
75
 
80
- describe 'Client exceptions', vcr: { :cassette_name => "exceptions-not-allowed" } do
76
+ describe 'Client exceptions', vcr: { cassette_name: 'exceptions-not-allowed' } do
81
77
  before(:all) do
82
78
  @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
83
79
  @domain = TESTDOMAIN || 'DOMAIN.TEST'
84
80
  end
85
81
 
86
82
  it 'display useful error information' do
87
- begin
88
- @mg_obj.send_message(@domain, {
89
- :from => "invalid@#{@domain}",
90
- :to => "invalid#{@domain}",
91
- :subject => 'Exception Integration Test',
92
- :text => 'INTEGRATION TESTING'
93
- })
94
- rescue Mailgun::CommunicationError => err
95
- expect(err.message).to include('403')
96
- else
97
- fail
98
- end
83
+ @mg_obj.send_message(@domain, {
84
+ from: "invalid@#{@domain}",
85
+ to: "invalid#{@domain}",
86
+ subject: 'Exception Integration Test',
87
+ text: 'INTEGRATION TESTING'
88
+ })
89
+ rescue Mailgun::CommunicationError => e
90
+ expect(e.message).to include('403')
91
+ else
92
+ raise
99
93
  end
100
94
  end
101
95
 
102
- describe 'The method send_message()', vcr: { :cassette_name => "send_message" } do
96
+ describe 'The method send_message()', vcr: { cassette_name: 'send_message' } do
103
97
  before(:all) do
104
98
  @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
105
99
  @domain = TESTDOMAIN || 'DOMAIN.TEST'
@@ -107,15 +101,14 @@ describe 'The method send_message()', vcr: { :cassette_name => "send_message" }
107
101
 
108
102
  it 'sends a standard message in test mode.' do
109
103
  @mg_obj.enable_test_mode!
110
- result = @mg_obj.send_message(@domain, {:from => "bob@#{@domain}",
111
- :to => "sally@#{@domain}",
112
- :subject => 'Hash Integration Test',
113
- :text => 'INTEGRATION TESTING',
114
- 'o:testmode' => true}
115
- )
104
+ result = @mg_obj.send_message(@domain, { :from => "bob@#{@domain}",
105
+ :to => "sally@#{@domain}",
106
+ :subject => 'Hash Integration Test',
107
+ :text => 'INTEGRATION TESTING',
108
+ 'o:testmode' => true })
116
109
  result.to_h!
117
- expect(result.body).to include("message")
118
- expect(result.body).to include("id")
110
+ expect(result.body).to include('message')
111
+ expect(result.body).to include('id')
119
112
  end
120
113
 
121
114
  it 'fakes message send while in *client* test mode' do
@@ -123,10 +116,10 @@ describe 'The method send_message()', vcr: { :cassette_name => "send_message" }
123
116
 
124
117
  expect(@mg_obj.test_mode?).to eq(true)
125
118
 
126
- data = { :from => "joe@#{@domain}",
127
- :to => "bob@#{@domain}",
128
- :subject => "Test",
129
- :text => "Test Data" }
119
+ data = { from: "joe@#{@domain}",
120
+ to: "bob@#{@domain}",
121
+ subject: 'Test',
122
+ text: 'Test Data' }
130
123
  uuid = 'uuid'
131
124
 
132
125
  allow(SecureRandom).to receive(:uuid).and_return(uuid)
@@ -135,27 +128,27 @@ describe 'The method send_message()', vcr: { :cassette_name => "send_message" }
135
128
 
136
129
  result.to_h!
137
130
 
138
- expect(result.body).to include("message")
139
- expect(result.body).to include("id")
131
+ expect(result.body).to include('message')
132
+ expect(result.body).to include('id')
140
133
 
141
134
  expect(result.code).to eq(200)
142
135
  expect(result.body['id']).to eq("test-mode-mail-#{uuid}@localhost")
143
- expect(result.body['message']).to eq("Queued. Thank you.")
136
+ expect(result.body['message']).to eq('Queued. Thank you.')
144
137
  end
145
138
 
146
139
  it 'sends a message builder message in test mode.' do
147
- mb_obj = Mailgun::MessageBuilder.new()
148
- mb_obj.from("sender@#{@domain}", {'first' => 'Sending', 'last' => 'User'})
149
- mb_obj.add_recipient(:to, "recipient@#{@domain}", {'first' => 'Recipient', 'last' => 'User'})
150
- mb_obj.subject("Message Builder Integration Test")
151
- mb_obj.body_text("This is the text body.")
140
+ mb_obj = Mailgun::MessageBuilder.new
141
+ mb_obj.from("sender@#{@domain}", { 'first' => 'Sending', 'last' => 'User' })
142
+ mb_obj.add_recipient(:to, "recipient@#{@domain}", { 'first' => 'Recipient', 'last' => 'User' })
143
+ mb_obj.subject('Message Builder Integration Test')
144
+ mb_obj.body_text('This is the text body.')
152
145
  mb_obj.test_mode(true)
153
146
 
154
147
  result = @mg_obj.send_message(@domain, mb_obj)
155
148
 
156
149
  result.to_h!
157
- expect(result.body).to include("message")
158
- expect(result.body).to include("id")
150
+ expect(result.body).to include('message')
151
+ expect(result.body).to include('id')
159
152
  end
160
153
 
161
154
  it 'sends a custom MIME message in test mode.' do
@@ -175,15 +168,15 @@ Sender: me@samples.mailgun.org
175
168
 
176
169
  Testing some Mailgun awesomness!'
177
170
 
178
- message_params = {:from => "bobby@#{@domain}",
179
- :to => "sally@#{@domain}",
180
- :message => mime_string}
171
+ message_params = { from: "bobby@#{@domain}",
172
+ to: "sally@#{@domain}",
173
+ message: mime_string }
181
174
 
182
175
  result = @mg_obj.send_message(@domain, message_params)
183
176
 
184
177
  result.to_h!
185
- expect(result.body).to include("message")
186
- expect(result.body).to include("id")
178
+ expect(result.body).to include('message')
179
+ expect(result.body).to include('id')
187
180
  end
188
181
 
189
182
  it 'receives success response code' do
@@ -191,10 +184,10 @@ Testing some Mailgun awesomness!'
191
184
 
192
185
  expect(@mg_obj.test_mode?).to eq(true)
193
186
 
194
- data = { :from => "joe@#{@domain}",
195
- :to => "bob@#{@domain}",
196
- :subject => "Test",
197
- :text => "Test Data" }
187
+ data = { from: "joe@#{@domain}",
188
+ to: "bob@#{@domain}",
189
+ subject: 'Test',
190
+ text: 'Test Data' }
198
191
 
199
192
  result = @mg_obj.send_message(@domain, data)
200
193
  result.to_h!
@@ -202,4 +195,3 @@ Testing some Mailgun awesomness!'
202
195
  expect(result.success?).to be(true)
203
196
  end
204
197
  end
205
-