mailgun-ruby 1.1.9 → 1.2.4

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.
@@ -2,8 +2,9 @@ require 'railgun/mailer'
2
2
 
3
3
  module Railgun
4
4
  class Railtie < ::Rails::Railtie
5
- config.before_configuration do
6
- ActionMailer::Base.add_delivery_method :mailgun, Railgun::Mailer
5
+ ActiveSupport.on_load(:action_mailer) do
6
+ add_delivery_method :mailgun, Railgun::Mailer
7
+ ActiveSupport.run_load_hooks(:mailgun_mailer, Railgun::Mailer)
7
8
  end
8
9
  end
9
10
  end
data/mailgun.gemspec CHANGED
@@ -22,16 +22,16 @@ Gem::Specification.new do |spec|
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.required_ruby_version = '>= 2.0.0'
26
-
27
- spec.add_development_dependency 'bundler', '~> 1.5'
28
- spec.add_development_dependency 'rspec', '~> 3.0'
29
- spec.add_development_dependency 'rake', '~> 10.0'
30
- spec.add_development_dependency 'webmock', '~> 1.22'
31
- spec.add_development_dependency 'pry', '~> 0.9'
32
- spec.add_development_dependency 'vcr', '~> 3.0'
33
- spec.add_development_dependency 'simplecov', '~> 0.11'
34
- spec.add_development_dependency "rails"
35
- spec.add_dependency 'rest-client', '~> 2.0'
25
+ spec.required_ruby_version = '>= 2.2.2'
26
+
27
+ spec.add_development_dependency 'bundler', '>= 1.16.2'
28
+ spec.add_development_dependency 'rspec', '~> 3.8.0'
29
+ spec.add_development_dependency 'rake', '~> 12.3.2'
30
+ spec.add_development_dependency 'webmock', '~> 3.4.2'
31
+ spec.add_development_dependency 'pry', '~> 0.11.3'
32
+ spec.add_development_dependency 'vcr', '~> 3.0.3'
33
+ spec.add_development_dependency 'simplecov', '~> 0.16.1'
34
+ spec.add_development_dependency 'rails'
35
+ spec.add_dependency 'rest-client', '>= 2.0.2'
36
36
 
37
37
  end
@@ -28,7 +28,11 @@ describe 'For the email validation endpoint', order: :defined, vcr: vcr_opts do
28
28
  expected = {
29
29
  "address" => "alice@mailgun.net",
30
30
  "did_you_mean" => nil,
31
+ "is_disposable_address" => false,
32
+ "is_role_address" => false,
31
33
  "is_valid" => true,
34
+ "mailbox_verification" => "true",
35
+ "reason" => nil,
32
36
  "parts" => {
33
37
  "display_name" => nil,
34
38
  "domain" => "mailgun.net",
@@ -50,7 +54,11 @@ describe 'For the email validation endpoint', order: :defined, vcr: vcr_opts do
50
54
  expected = {
51
55
  "address" => "example.org",
52
56
  "did_you_mean" => nil,
57
+ "is_disposable_address" => false,
58
+ "is_role_address" => false,
53
59
  "is_valid" => false,
60
+ "mailbox_verification" => "unknown",
61
+ "reason" => "Validation failed for 'example.org', reason: 'malformed address; missing @ sign'",
54
62
  "parts" => {
55
63
  "display_name" => nil,
56
64
  "domain" => nil,
@@ -22,7 +22,7 @@ describe 'For the Events endpoint', vcr: vcr_opts do
22
22
 
23
23
  it 'can iterate over all events with `each`' do
24
24
  @events.each do |e|
25
- expect(e.id).to eq("JAx9z641TuGGUyaJlD9sCQ")
25
+ expect(e["id"]).to eq("JAx9z641TuGGUyaJlD9sCQ")
26
26
  end
27
27
  end
28
28
  end
@@ -52,7 +52,7 @@ describe 'For the suppressions handling class', order: :defined, vcr: vcr_opts d
52
52
  end
53
53
  end
54
54
 
55
- it 'can batch-add unsubscribes' do
55
+ it 'can batch-add unsubscribes with tags as string' do
56
56
  unsubscribes = []
57
57
  @addresses.each do |addr|
58
58
  unsubscribes.push({
@@ -69,6 +69,23 @@ describe 'For the suppressions handling class', order: :defined, vcr: vcr_opts d
69
69
  expect(nested.length).to eq(0)
70
70
  end
71
71
 
72
+ it 'can batch-add unsubscribes with tags as array' do
73
+ unsubscribes = []
74
+ @addresses.each do |addr|
75
+ unsubscribes.push({
76
+ :address => addr,
77
+ :tags => ['integration'],
78
+ })
79
+ end
80
+
81
+ response, nested = @suppress.create_unsubscribes unsubscribes
82
+ response.to_h!
83
+
84
+ expect(response.code).to eq(200)
85
+ expect(response.body['message']).to eq('4 addresses have been added to the unsubscribes table')
86
+ expect(nested.length).to eq(0)
87
+ end
88
+
72
89
  it 'raises ParameterError if no unsubscribe[:address] is present' do
73
90
  unsubscribes = []
74
91
  unsubscribes.push({
@@ -123,4 +140,3 @@ describe 'For the suppressions handling class', order: :defined, vcr: vcr_opts d
123
140
 
124
141
  # TODO: Add tests for pagination support.
125
142
  end
126
-
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rubygems'
2
+ require 'base64'
2
3
  require 'bundler'
3
4
  require 'bundler/setup'
4
5
  Bundler.setup(:development)
@@ -37,9 +38,10 @@ TESTDOMAIN = envs['MAILGUN_TESTDOMAIN']
37
38
  VCR.configure do |c|
38
39
  c.cassette_library_dir = 'vcr_cassettes'
39
40
  c.hook_into :webmock
40
- c.configure_rspec_metadata!
41
41
  c.default_cassette_options = { record: :new_episodes }
42
42
  c.filter_sensitive_data('<APIKEY>') { APIKEY }
43
43
  c.filter_sensitive_data('DOMAIN.TEST') { TESTDOMAIN }
44
44
  c.filter_sensitive_data('<PUBKEY>') { PUB_APIKEY }
45
+
46
+ c.configure_rspec_metadata!
45
47
  end
@@ -11,6 +11,25 @@ describe 'The method get' do
11
11
  end
12
12
  end
13
13
 
14
+ describe 'Pagination' do
15
+ it 'should return a proper hash of log data.' do
16
+ @mg_obj = Mailgun::UnitClient.new('events')
17
+ events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
18
+ result = events.get()
19
+
20
+ json = JSON.parse(result.body)
21
+ expect(json).to include("paging")
22
+ expect(json["paging"]).to include("next")
23
+ expect(json["paging"]).to include{"previous"}
24
+ end
25
+
26
+ it 'should calculate proper next-page url' do
27
+ events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
28
+ output = events.send(:extract_endpoint_from, '/v3/samples.mailgun.org/events/W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTAwLCBudWxsXQ==')
29
+
30
+ expect(output).to eq 'W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTAwLCBudWxsXQ=='
31
+ end
32
+ end
14
33
 
15
34
  describe 'The method next' do
16
35
  it 'should return the next series of data.' do
@@ -95,6 +95,7 @@ describe 'The method add_recipient' do
95
95
  expect(@mb_obj.counters[:recipients][recipient_type]).to eq(1000)
96
96
  @mb_obj.finalize
97
97
 
98
+ expect(@mb_obj.recipient_variables).to eq({})
98
99
  expect(@mb_obj.message['recipient-variables'].length).to eq(0)
99
100
  expect(@mb_obj.message[:to].length).to eq(0)
100
101
  expect(@mb_obj.counters[:recipients][recipient_type]).to eq(0)
@@ -50,6 +50,16 @@ describe 'The method add_recipient' do
50
50
  expect(@mb_obj.counters[:recipients][recipient_type]).to eq(1)
51
51
  end
52
52
 
53
+ context 'when variables is empty and recepeint type - "to"' do
54
+ it 'adds email address as "to" recipient type and increments counter' do
55
+ recipient_type = :to
56
+ @mb_obj.add_recipient(recipient_type, @address, {})
57
+
58
+ expect(@mb_obj.message[recipient_type][0]).to eq("#{@address}")
59
+ expect(@mb_obj.counters[:recipients][recipient_type]).to eq(1)
60
+ end
61
+ end
62
+
53
63
  it 'adds a "cc" recipient type to the message body and counter is incremented' do
54
64
  recipient_type = :cc
55
65
  @mb_obj.add_recipient(recipient_type, @address, @variables)
@@ -246,6 +256,16 @@ describe 'The method add_attachment' do
246
256
  expect(@mb_obj.message[:attachment].length).to eq(1)
247
257
  expect(@mb_obj.message[:attachment].first.original_filename).to eq 'mailgun_icon.png'
248
258
  end
259
+
260
+ context 'when attachment has unknown type' do
261
+ it 'sets content type application/octet-stream for attachment' do
262
+ file = File.dirname(__FILE__) + "/sample_data/unknown.type"
263
+
264
+ @mb_obj.add_attachment(file)
265
+
266
+ expect(@mb_obj.message[:attachment][0].content_type).to eq('application/octet-stream')
267
+ end
268
+ end
249
269
  end
250
270
 
251
271
  describe 'The method add_inline_image' do
@@ -440,19 +460,19 @@ describe 'The method track_opens' do
440
460
  it 'enables/disables open tracking on a per message basis.' do
441
461
  @mb_obj.track_opens('Yes')
442
462
 
443
- expect(@mb_obj.message["o:tracking-opens"][0]).to eq("yes")
463
+ expect(@mb_obj.message["o:tracking-opens"]).to eq("yes")
444
464
 
445
465
  @mb_obj.track_opens('No')
446
466
 
447
- expect(@mb_obj.message["o:tracking-opens"][0]).to eq("no")
467
+ expect(@mb_obj.message["o:tracking-opens"]).to eq("no")
448
468
 
449
469
  @mb_obj.track_opens(true)
450
470
 
451
- expect(@mb_obj.message["o:tracking-opens"][0]).to eq("yes")
471
+ expect(@mb_obj.message["o:tracking-opens"]).to eq("yes")
452
472
 
453
473
  @mb_obj.track_opens(false)
454
474
 
455
- expect(@mb_obj.message["o:tracking-opens"][0]).to eq("no")
475
+ expect(@mb_obj.message["o:tracking-opens"]).to eq("no")
456
476
  end
457
477
  end
458
478
 
@@ -471,23 +491,23 @@ describe 'The method track_clicks' do
471
491
  it 'enables/disables click tracking on a per message basis.' do
472
492
  @mb_obj.track_clicks('Yes')
473
493
 
474
- expect(@mb_obj.message["o:tracking-clicks"][0]).to eq("yes")
494
+ expect(@mb_obj.message["o:tracking-clicks"]).to eq("yes")
475
495
 
476
496
  @mb_obj.track_clicks('No')
477
497
 
478
- expect(@mb_obj.message["o:tracking-clicks"][0]).to eq("no")
498
+ expect(@mb_obj.message["o:tracking-clicks"]).to eq("no")
479
499
 
480
500
  @mb_obj.track_clicks(true)
481
501
 
482
- expect(@mb_obj.message["o:tracking-clicks"][0]).to eq("yes")
502
+ expect(@mb_obj.message["o:tracking-clicks"]).to eq("yes")
483
503
 
484
504
  @mb_obj.track_clicks(false)
485
505
 
486
- expect(@mb_obj.message["o:tracking-clicks"][0]).to eq("no")
506
+ expect(@mb_obj.message["o:tracking-clicks"]).to eq("no")
487
507
 
488
508
  @mb_obj.track_clicks('html')
489
509
 
490
- expect(@mb_obj.message["o:tracking-clicks"][0]).to eq("html")
510
+ expect(@mb_obj.message["o:tracking-clicks"]).to eq("html")
491
511
  end
492
512
  end
493
513
 
@@ -547,9 +567,13 @@ describe 'The method variable' do
547
567
  expect(@mb_obj.message["v:my-data"]).to be_kind_of(String)
548
568
  expect(@mb_obj.message["v:my-data"].to_s).to eq('{"key":"value"}')
549
569
  end
550
- it 'throws an exception on broken JSON.' do
551
- data = 'This is some crappy JSON.'
552
- expect {@mb_obj.variable('my-data', data)}.to raise_error(Mailgun::ParameterError)
570
+ it 'accepts string values' do
571
+ data = 'String Value.'
572
+
573
+ @mb_obj.variable('my-data', data)
574
+
575
+ expect(@mb_obj.message["v:my-data"]).to be_kind_of(String)
576
+ expect(@mb_obj.message["v:my-data"].to_s).to eq('String Value.')
553
577
  end
554
578
  end
555
579
 
File without changes
@@ -0,0 +1,242 @@
1
+ require 'json'
2
+ require 'logger'
3
+ require 'spec_helper'
4
+ require 'mailgun'
5
+ require 'railgun'
6
+
7
+ ActionMailer::Base.raise_delivery_errors = true
8
+ ActionMailer::Base.delivery_method = :test
9
+ Rails.logger = Logger.new('/dev/null')
10
+ Rails.logger.level = Logger::DEBUG
11
+
12
+ class UnitTestMailer < ActionMailer::Base
13
+ default from: 'unittest@example.org'
14
+
15
+ def plain_message(address, subject, headers)
16
+ headers(headers)
17
+ mail(to: address, subject: subject) do |format|
18
+ format.text { render plain: "Test!" }
19
+ format.html { render html: "<p>Test!</p>".html_safe }
20
+ end
21
+ end
22
+
23
+ def message_with_attachment(address, subject)
24
+ attachments['info.txt'] = {
25
+ :content => File.read('docs/railgun/Overview.md'),
26
+ :mime_type => 'text/plain',
27
+ }
28
+ mail(to: address, subject: subject) do |format|
29
+ format.text { render plain: "Test!" }
30
+ format.html { render html: "<p>Test!</p>".html_safe }
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ describe 'Railgun::Mailer' do
37
+
38
+ it 'has a mailgun_client property which returns a Mailgun::Client' do
39
+ config = {
40
+ api_key: {},
41
+ domain: {}
42
+ }
43
+ @mailer_obj = Railgun::Mailer.new(config)
44
+
45
+ expect(@mailer_obj.mailgun_client).to be_a(Mailgun::Client)
46
+ end
47
+
48
+ it 'properly creates a message body' do
49
+ message = UnitTestMailer.plain_message('test@example.org', 'Test!', {})
50
+ body = Railgun.transform_for_mailgun(message)
51
+
52
+ [:from, :subject, :text, :html, 'to'].each do |param|
53
+ expect(body).to include(param)
54
+ end
55
+
56
+ expect(body[:from][0].value).to eq('unittest@example.org')
57
+ expect(body['to']).to eq(['test@example.org'])
58
+ expect(body[:subject]).to eq(['Test!'])
59
+ expect(body[:text]).to eq(['Test!'])
60
+ expect(body[:html]).to eq(['<p>Test!</p>'.html_safe])
61
+ end
62
+
63
+ it 'adds options to message body' do
64
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
65
+ message.mailgun_options ||= {
66
+ 'tracking-opens' => 'true',
67
+ }
68
+
69
+ body = Railgun.transform_for_mailgun(message)
70
+
71
+ expect(body).to include('o:tracking-opens')
72
+ expect(body['o:tracking-opens']).to eq('true')
73
+ end
74
+
75
+ it 'accepts frozen options to message body' do
76
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
77
+ message.mailgun_options ||= {
78
+ 'tags' => ['some-tag']
79
+ }
80
+
81
+ body = Railgun.transform_for_mailgun(message)
82
+
83
+ expect(body).to include('o:tags')
84
+ expect(body['o:tags']).to eq(['some-tag'])
85
+ end
86
+
87
+ it 'adds variables to message body' do
88
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
89
+ message.mailgun_variables ||= {
90
+ 'user' => {:id => '1', :name => 'tstark'},
91
+ }
92
+
93
+ body = Railgun.transform_for_mailgun(message)
94
+
95
+ expect(body).to include('v:user')
96
+
97
+ var_body = JSON.load(body['v:user'])
98
+ expect(var_body).to include('id')
99
+ expect(var_body).to include('name')
100
+ expect(var_body['id']).to eq('1')
101
+ expect(var_body['name']).to eq('tstark')
102
+ end
103
+
104
+ it 'adds headers to message body' do
105
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
106
+ message.mailgun_headers ||= {
107
+ 'x-unit-test' => 'true',
108
+ }
109
+
110
+ body = Railgun.transform_for_mailgun(message)
111
+
112
+ expect(body).to include('h:x-unit-test')
113
+ expect(body['h:x-unit-test']).to eq('true')
114
+ end
115
+
116
+ it 'adds headers to message body from mailer' do
117
+ message = UnitTestMailer.plain_message('test@example.org', '', {
118
+ 'x-unit-test-2' => 'true',
119
+ })
120
+
121
+ body = Railgun.transform_for_mailgun(message)
122
+
123
+ expect(body).to include('h:x-unit-test-2')
124
+ expect(body['h:x-unit-test-2']).to eq('true')
125
+ end
126
+
127
+ it 'properly handles headers that are passed as separate POST params' do
128
+ message = UnitTestMailer.plain_message('test@example.org', 'Test!', {
129
+ # `From`, `To`, and `Subject` are set on the envelope, so they should be ignored as headers
130
+ 'From' => 'units@example.net',
131
+ 'To' => 'user@example.com',
132
+ 'Subject' => 'This should disappear',
133
+ # If `Bcc` or `Cc` are set as headers, they should be carried over as POST params, not headers
134
+ 'Bcc' => ['list@example.org'],
135
+ 'Cc' => ['admin@example.com'],
136
+ # This is an arbitrary header and should be carried over properly
137
+ 'X-Source' => 'unit tests',
138
+ })
139
+
140
+ body = Railgun.transform_for_mailgun(message)
141
+
142
+ ['From', 'To', 'Subject'].each do |header|
143
+ expect(body).not_to include("h:#{header}")
144
+ end
145
+
146
+ ['bcc', 'cc', 'to', 'h:x-source'].each do |param|
147
+ expect(body).to include(param)
148
+ end
149
+
150
+ expect(body[:from][0].value).to eq('unittest@example.org')
151
+ expect(body['to']).to eq(['test@example.org'])
152
+ expect(body[:subject]).to eq(['Test!'])
153
+ expect(body[:text]).to eq(['Test!'])
154
+ expect(body[:html]).to eq(['<p>Test!</p>'.html_safe])
155
+ expect(body['bcc']).to eq(['list@example.org'])
156
+ expect(body['cc']).to eq(['admin@example.com'])
157
+ expect(body['h:x-source']).to eq('unit tests')
158
+ end
159
+
160
+ it 'properly adds attachments' do
161
+ message = UnitTestMailer.message_with_attachment('test@example.org', '')
162
+ body = Railgun.transform_for_mailgun(message)
163
+
164
+ expect(body).to include(:attachment)
165
+ attachment = body[:attachment][0]
166
+
167
+ expect(attachment.filename).to eq('info.txt')
168
+ expect(attachment.content_type).to eq('text/plain')
169
+ end
170
+
171
+ it 'delivers!' do
172
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
173
+ message.deliver_now
174
+
175
+ expect(ActionMailer::Base.deliveries).to include(message)
176
+ end
177
+
178
+ it 'ignores `reply-to` in headers' do
179
+ message = UnitTestMailer.plain_message('test@example.org', '', {
180
+ 'reply-to' => 'user@example.com',
181
+ })
182
+ message.mailgun_headers = {
183
+ 'Reply-To' => 'administrator@example.org',
184
+ }
185
+ message.headers({'REPLY-TO' => 'admin@example.net'})
186
+ message.reply_to = "dude@example.com.au"
187
+
188
+ body = Railgun.transform_for_mailgun(message)
189
+ expect(body).to include('h:reply-to')
190
+ expect(body).not_to include('h:Reply-To')
191
+ expect(body['h:reply-to']).to eq('dude@example.com.au')
192
+ end
193
+
194
+ it 'ignores `mime-version` in headers' do
195
+ message = UnitTestMailer.plain_message('test@example.org', '', {
196
+ 'mime-version' => '1.0',
197
+ })
198
+ message.mailgun_headers = {
199
+ 'Mime-Version' => '1.1',
200
+ }
201
+ message.headers({'MIME-VERSION' => '1.2'})
202
+
203
+ body = Railgun.transform_for_mailgun(message)
204
+ expect(body).not_to include('h:mime-version')
205
+ end
206
+
207
+ it 'treats `headers()` names as case-insensitve' do
208
+ message = UnitTestMailer.plain_message('test@example.org', '', {
209
+ 'X-BIG-VALUE' => 1,
210
+ })
211
+
212
+ body = Railgun.transform_for_mailgun(message)
213
+ expect(body).to include('h:x-big-value')
214
+ expect(body['h:x-big-value']).to eq("1")
215
+ end
216
+
217
+ it 'treats `mailgun_headers` names as case-insensitive' do
218
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
219
+ message.mailgun_headers = {
220
+ 'X-BIG-VALUE' => 1,
221
+ }
222
+
223
+ body = Railgun.transform_for_mailgun(message)
224
+ expect(body).to include('h:x-big-value')
225
+ expect(body['h:x-big-value']).to eq("1")
226
+ end
227
+
228
+ it 'handles multi-value, mixed case headers correctly' do
229
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
230
+ message.headers({
231
+ 'x-neat-header' => 'foo',
232
+ 'X-Neat-Header' => 'bar',
233
+ 'X-NEAT-HEADER' => 'zoop',
234
+ })
235
+
236
+ body = Railgun.transform_for_mailgun(message)
237
+ expect(body).to include('h:x-neat-header')
238
+ expect(body['h:x-neat-header']).to include('foo')
239
+ expect(body['h:x-neat-header']).to include('bar')
240
+ expect(body['h:x-neat-header']).to include('zoop')
241
+ end
242
+ end