mailgun-ruby 1.1.10 → 1.2.5

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.
File without changes
@@ -0,0 +1,388 @@
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
+ def message_with_template(address, subject, template_name)
35
+ mail(to: address, subject: subject, template: template_name) do |format|
36
+ format.text { render plain: "Test!" }
37
+ end
38
+ end
39
+
40
+ def message_with_domain(address, subject, domain)
41
+ mail(to: address, subject: subject, domain: domain) do |format|
42
+ format.text { render plain: "Test!" }
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe 'Railgun::Mailer' do
49
+
50
+ it 'has a mailgun_client property which returns a Mailgun::Client' do
51
+ config = {
52
+ api_key: {},
53
+ domain: {}
54
+ }
55
+ @mailer_obj = Railgun::Mailer.new(config)
56
+
57
+ expect(@mailer_obj.mailgun_client).to be_a(Mailgun::Client)
58
+ end
59
+
60
+ context 'when config does not have api_key or domain' do
61
+ it 'raises configuration error' do
62
+ config = {
63
+ api_key: {}
64
+ }
65
+
66
+ expect { Railgun::Mailer.new(config) }.to raise_error(Railgun::ConfigurationError)
67
+ end
68
+ end
69
+
70
+ context 'when fake_message_send is present in config' do
71
+ it 'enables test mode' do
72
+ config = {
73
+ api_key: {},
74
+ domain: {},
75
+ fake_message_send: true
76
+ }
77
+ client_double = double(Mailgun::Client)
78
+ allow(Mailgun::Client).to receive(:new).and_return(client_double)
79
+ expect(client_double).to receive(:enable_test_mode!)
80
+
81
+ Railgun::Mailer.new(config)
82
+ end
83
+ end
84
+
85
+ it 'properly creates a message body' do
86
+ message = UnitTestMailer.plain_message('test@example.org', 'Test!', {})
87
+ body = Railgun.transform_for_mailgun(message)
88
+
89
+ [:from, :subject, :text, :html, 'to'].each do |param|
90
+ expect(body).to include(param)
91
+ end
92
+
93
+ expect(body[:from][0].value).to eq('unittest@example.org')
94
+ expect(body['to']).to eq(['test@example.org'])
95
+ expect(body[:subject]).to eq(['Test!'])
96
+ expect(body[:text]).to eq(['Test!'])
97
+ expect(body[:html]).to eq(['<p>Test!</p>'.html_safe])
98
+ end
99
+
100
+ it 'adds options to message body' do
101
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
102
+ message.mailgun_options ||= {
103
+ 'tracking-opens' => 'true',
104
+ }
105
+
106
+ body = Railgun.transform_for_mailgun(message)
107
+
108
+ expect(body).to include('o:tracking-opens')
109
+ expect(body['o:tracking-opens']).to eq('true')
110
+ end
111
+
112
+ it 'accepts frozen options to message body' do
113
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
114
+ message.mailgun_options ||= {
115
+ 'tags' => ['some-tag']
116
+ }
117
+
118
+ body = Railgun.transform_for_mailgun(message)
119
+
120
+ expect(body).to include('o:tags')
121
+ expect(body['o:tags']).to eq(['some-tag'])
122
+ end
123
+
124
+ it 'adds variables to message body' do
125
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
126
+ message.mailgun_variables ||= {
127
+ 'user' => {:id => '1', :name => 'tstark'},
128
+ }
129
+
130
+ body = Railgun.transform_for_mailgun(message)
131
+
132
+ expect(body).to include('v:user')
133
+
134
+ var_body = JSON.load(body['v:user'])
135
+ expect(var_body).to include('id')
136
+ expect(var_body).to include('name')
137
+ expect(var_body['id']).to eq('1')
138
+ expect(var_body['name']).to eq('tstark')
139
+ end
140
+
141
+ it 'adds headers to message body' do
142
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
143
+ message.mailgun_headers ||= {
144
+ 'x-unit-test' => 'true',
145
+ }
146
+
147
+ body = Railgun.transform_for_mailgun(message)
148
+
149
+ expect(body).to include('h:x-unit-test')
150
+ expect(body['h:x-unit-test']).to eq('true')
151
+ end
152
+
153
+ it 'adds headers to message body from mailer' do
154
+ message = UnitTestMailer.plain_message('test@example.org', '', {
155
+ 'x-unit-test-2' => 'true',
156
+ })
157
+
158
+ body = Railgun.transform_for_mailgun(message)
159
+
160
+ expect(body).to include('h:x-unit-test-2')
161
+ expect(body['h:x-unit-test-2']).to eq('true')
162
+ end
163
+
164
+ it 'properly handles headers that are passed as separate POST params' do
165
+ message = UnitTestMailer.plain_message('test@example.org', 'Test!', {
166
+ # `From`, `To`, and `Subject` are set on the envelope, so they should be ignored as headers
167
+ 'From' => 'units@example.net',
168
+ 'To' => 'user@example.com',
169
+ 'Subject' => 'This should disappear',
170
+ # If `Bcc` or `Cc` are set as headers, they should be carried over as POST params, not headers
171
+ 'Bcc' => ['list@example.org'],
172
+ 'Cc' => ['admin@example.com'],
173
+ # This is an arbitrary header and should be carried over properly
174
+ 'X-Source' => 'unit tests',
175
+ })
176
+
177
+ body = Railgun.transform_for_mailgun(message)
178
+
179
+ ['From', 'To', 'Subject'].each do |header|
180
+ expect(body).not_to include("h:#{header}")
181
+ end
182
+
183
+ ['bcc', 'cc', 'to', 'h:x-source'].each do |param|
184
+ expect(body).to include(param)
185
+ end
186
+
187
+ expect(body[:from][0].value).to eq('unittest@example.org')
188
+ expect(body['to']).to eq(['test@example.org'])
189
+ expect(body[:subject]).to eq(['Test!'])
190
+ expect(body[:text]).to eq(['Test!'])
191
+ expect(body[:html]).to eq(['<p>Test!</p>'.html_safe])
192
+ expect(body['bcc']).to eq(['list@example.org'])
193
+ expect(body['cc']).to eq(['admin@example.com'])
194
+ expect(body['h:x-source']).to eq('unit tests')
195
+ end
196
+
197
+ context 'when mailgun_variables are present' do
198
+ it 'accepts valid JSON and stores it as message[param].' do
199
+ message = UnitTestMailer.plain_message('test@example.org', '', {}).tap do |message|
200
+ message.mailgun_variables = {
201
+ 'my-data' => '{"key":"value"}'
202
+ }
203
+ end
204
+ body = Railgun.transform_for_mailgun(message)
205
+ expect(body["v:my-data"]).to be_kind_of(String)
206
+ expect(body["v:my-data"].to_s).to eq('{"key":"value"}')
207
+ end
208
+
209
+ it 'accepts a hash and appends as data to the message.' do
210
+ message = UnitTestMailer.plain_message('test@example.org', '', {}).tap do |message|
211
+ message.mailgun_variables = {
212
+ 'my-data' => {'key' => 'value'}
213
+ }
214
+ end
215
+ body = Railgun.transform_for_mailgun(message)
216
+
217
+ expect(body["v:my-data"]).to be_kind_of(String)
218
+ expect(body["v:my-data"].to_s).to eq('{"key":"value"}')
219
+ end
220
+
221
+ it 'accepts string values' do
222
+ message = UnitTestMailer.plain_message('test@example.org', '', {}).tap do |message|
223
+ message.mailgun_variables = {
224
+ 'my-data' => 'String Value.'
225
+ }
226
+ end
227
+ body = Railgun.transform_for_mailgun(message)
228
+
229
+ expect(body["v:my-data"]).to be_kind_of(String)
230
+ expect(body["v:my-data"].to_s).to eq('String Value.')
231
+ end
232
+ end
233
+
234
+ it 'properly adds attachments' do
235
+ message = UnitTestMailer.message_with_attachment('test@example.org', '')
236
+ body = Railgun.transform_for_mailgun(message)
237
+
238
+ expect(body).to include(:attachment)
239
+ attachment = body[:attachment][0]
240
+
241
+ expect(attachment.filename).to eq('info.txt')
242
+ expect(attachment.content_type).to eq('text/plain')
243
+ end
244
+
245
+ it 'delivers!' do
246
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
247
+ message.deliver_now
248
+
249
+ expect(ActionMailer::Base.deliveries).to include(message)
250
+ end
251
+
252
+ it 'ignores `reply-to` in headers' do
253
+ message = UnitTestMailer.plain_message('test@example.org', '', {
254
+ 'reply-to' => 'user@example.com',
255
+ })
256
+ message.mailgun_headers = {
257
+ 'Reply-To' => 'administrator@example.org',
258
+ }
259
+ message.headers({'REPLY-TO' => 'admin@example.net'})
260
+ message.reply_to = "dude@example.com.au"
261
+
262
+ body = Railgun.transform_for_mailgun(message)
263
+ expect(body).to include('h:reply-to')
264
+ expect(body).not_to include('h:Reply-To')
265
+ expect(body['h:reply-to']).to eq('dude@example.com.au')
266
+ end
267
+
268
+ it 'ignores `mime-version` in headers' do
269
+ message = UnitTestMailer.plain_message('test@example.org', '', {
270
+ 'mime-version' => '1.0',
271
+ })
272
+ message.mailgun_headers = {
273
+ 'Mime-Version' => '1.1',
274
+ }
275
+ message.headers({'MIME-VERSION' => '1.2'})
276
+
277
+ body = Railgun.transform_for_mailgun(message)
278
+ expect(body).not_to include('h:mime-version')
279
+ end
280
+
281
+ it 'treats `headers()` names as case-insensitve' do
282
+ message = UnitTestMailer.plain_message('test@example.org', '', {
283
+ 'X-BIG-VALUE' => 1,
284
+ })
285
+
286
+ body = Railgun.transform_for_mailgun(message)
287
+ expect(body).to include('h:x-big-value')
288
+ expect(body['h:x-big-value']).to eq("1")
289
+ end
290
+
291
+ it 'treats `mailgun_headers` names as case-insensitive' do
292
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
293
+ message.mailgun_headers = {
294
+ 'X-BIG-VALUE' => 1,
295
+ }
296
+
297
+ body = Railgun.transform_for_mailgun(message)
298
+ expect(body).to include('h:x-big-value')
299
+ expect(body['h:x-big-value']).to eq("1")
300
+ end
301
+
302
+ it 'handles multi-value, mixed case headers correctly' do
303
+ message = UnitTestMailer.plain_message('test@example.org', '', {})
304
+ message.headers({
305
+ 'x-neat-header' => 'foo',
306
+ 'X-Neat-Header' => 'bar',
307
+ 'X-NEAT-HEADER' => 'zoop',
308
+ })
309
+
310
+ body = Railgun.transform_for_mailgun(message)
311
+ expect(body).to include('h:x-neat-header')
312
+ expect(body['h:x-neat-header']).to include('foo')
313
+ expect(body['h:x-neat-header']).to include('bar')
314
+ expect(body['h:x-neat-header']).to include('zoop')
315
+ end
316
+
317
+ context 'when message with template' do
318
+ it 'adds template header to message from mailer params' do
319
+ template_name = 'template.name'
320
+ message = UnitTestMailer.message_with_template('test@example.org', '', template_name)
321
+
322
+ body = Railgun.transform_for_mailgun(message)
323
+
324
+ expect(body).to include('template')
325
+ expect(body['template']).to eq(template_name)
326
+ end
327
+
328
+ context 'when mailgun_template_variables are assigned' do
329
+ it 'adds template variables to message body' do
330
+ message = UnitTestMailer.message_with_template('test@example.org', '', 'template.name')
331
+ version = 'version_1'
332
+ message.mailgun_template_variables ||= {
333
+ 'version' => version,
334
+ 'text' => 'yes'
335
+ }
336
+
337
+ body = Railgun.transform_for_mailgun(message)
338
+
339
+ expect(body).to include('t:version')
340
+ expect(body['t:version']).to eq('version_1')
341
+ expect(body).to include('t:text')
342
+ expect(body['t:text']).to eq('yes')
343
+ end
344
+ end
345
+ end
346
+
347
+ describe 'deliver!' do
348
+ let(:config) do
349
+ {
350
+ api_key: 'api_key',
351
+ domain: 'domain'
352
+ }
353
+ end
354
+ let(:mail) { UnitTestMailer.plain_message('test@example.org', '', {}) }
355
+ let(:response) do
356
+ response = Struct.new(:code, :id)
357
+ response.new(200, rand(50..100))
358
+ end
359
+
360
+ it 'initiates client message send' do
361
+ result = { from: 'test@example.org' }
362
+ allow(Railgun).to receive(:transform_for_mailgun).and_return(result)
363
+
364
+ expect_any_instance_of(Mailgun::Client).to receive(:send_message)
365
+ .with(config[:domain], result)
366
+ .and_return(response)
367
+ Railgun::Mailer.new(config).deliver!(mail)
368
+ end
369
+
370
+ it 'returns response' do
371
+ expect_any_instance_of(Mailgun::Client).to receive(:send_message).and_return(response)
372
+ expect(Railgun::Mailer.new(config).deliver!(mail)).to eq(response)
373
+ end
374
+
375
+ context 'when domain is provided in arguments' do
376
+ let(:new_domain) { 'new_domain' }
377
+ let(:mail) { UnitTestMailer.message_with_domain('test@example.org', '', new_domain) }
378
+
379
+ it 'uses provided domain' do
380
+ result = { from: 'test@example.org' }
381
+ allow(Railgun).to receive(:transform_for_mailgun).and_return(result)
382
+ expect_any_instance_of(Mailgun::Client).to receive(:send_message)
383
+ .with(new_domain, result).and_return(response)
384
+ Railgun::Mailer.new(config).deliver!(mail)
385
+ end
386
+ end
387
+ end
388
+ end
@@ -0,0 +1,109 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.mailgun.net/v3/not-our-doma.in/messages
6
+ body:
7
+ encoding: US-ASCII
8
+ string: from[]=sally%40not-our-doma.in&subject[]=subject&html[]=%3Cp%3ETest%21%3C%2Fp%3E&text[]=Test%21&to[]=bob%40DOMAIN.TEST&h%3Acontent-type=multipart%2Falternative%3B+boundary%3D%22--%3D%3D_mimepart_6098fb5a12edf_78633ff4e00521889696a%22%3B+charset%3DUTF-8
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ User-Agent:
13
+ - rest-client/2.1.0 (darwin18.7.0 x86_64) ruby/2.2.2p95
14
+ Content-Length:
15
+ - '262'
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ Accept-Encoding:
19
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
20
+ Host:
21
+ - api.mailgun.net
22
+ Authorization:
23
+ - Basic YXBpOmQ5MTViNWNkYjlhNTgzNjg1ZDhmM2ZiMWJlYzBmMjBmLTA3YmM3YjA1LWZhNDgxNmEx
24
+ response:
25
+ status:
26
+ code: 401
27
+ message: UNAUTHORIZED
28
+ headers:
29
+ Access-Control-Allow-Headers:
30
+ - Content-Type, x-requested-with, Authorization
31
+ Access-Control-Allow-Methods:
32
+ - GET, POST, PUT, DELETE, OPTIONS
33
+ Access-Control-Allow-Origin:
34
+ - "*"
35
+ Access-Control-Max-Age:
36
+ - '600'
37
+ Cache-Control:
38
+ - no-store
39
+ Content-Type:
40
+ - text/html; charset=utf-8
41
+ Date:
42
+ - Mon, 10 May 2021 09:22:34 GMT
43
+ Server:
44
+ - nginx
45
+ Www-Authenticate:
46
+ - Basic realm="MG API"
47
+ Content-Length:
48
+ - '9'
49
+ Connection:
50
+ - keep-alive
51
+ body:
52
+ encoding: UTF-8
53
+ string: Forbidden
54
+ http_version:
55
+ recorded_at: Mon, 10 May 2021 09:22:34 GMT
56
+ - request:
57
+ method: post
58
+ uri: https://api.mailgun.net/v3/not-our-doma.in/messages
59
+ body:
60
+ encoding: US-ASCII
61
+ string: from[]=sally%40not-our-doma.in&subject[]=subject&html[]=%3Cp%3ETest%21%3C%2Fp%3E&text[]=Test%21&to[]=bob%40DOMAIN.TEST&h%3Acontent-type=multipart%2Falternative%3B+boundary%3D%22--%3D%3D_mimepart_6098fb5a12edf_78633ff4e00521889696a%22%3B+charset%3DUTF-8
62
+ headers:
63
+ Accept:
64
+ - "*/*"
65
+ User-Agent:
66
+ - rest-client/2.1.0 (darwin18.7.0 x86_64) ruby/2.2.2p95
67
+ Content-Length:
68
+ - '262'
69
+ Content-Type:
70
+ - application/x-www-form-urlencoded
71
+ Accept-Encoding:
72
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
73
+ Host:
74
+ - api.mailgun.net
75
+ Authorization:
76
+ - Basic YXBpOmQ5MTViNWNkYjlhNTgzNjg1ZDhmM2ZiMWJlYzBmMjBmLTA3YmM3YjA1LWZhNDgxNmEx
77
+ response:
78
+ status:
79
+ code: 401
80
+ message: UNAUTHORIZED
81
+ headers:
82
+ Access-Control-Allow-Headers:
83
+ - Content-Type, x-requested-with, Authorization
84
+ Access-Control-Allow-Methods:
85
+ - GET, POST, PUT, DELETE, OPTIONS
86
+ Access-Control-Allow-Origin:
87
+ - "*"
88
+ Access-Control-Max-Age:
89
+ - '600'
90
+ Cache-Control:
91
+ - no-store
92
+ Content-Type:
93
+ - text/html; charset=utf-8
94
+ Date:
95
+ - Mon, 10 May 2021 09:22:40 GMT
96
+ Server:
97
+ - nginx
98
+ Www-Authenticate:
99
+ - Basic realm="MG API"
100
+ Content-Length:
101
+ - '9'
102
+ Connection:
103
+ - keep-alive
104
+ body:
105
+ encoding: UTF-8
106
+ string: Forbidden
107
+ http_version:
108
+ recorded_at: Mon, 10 May 2021 09:22:40 GMT
109
+ recorded_with: VCR 3.0.3