mailgun-ruby 1.1.9 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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