mailgun-ruby 1.1.2 → 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.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-env.yml.example +1 -1
  3. data/.travis.yml +8 -5
  4. data/Gemfile +1 -1
  5. data/README.md +77 -9
  6. data/{Domains.md → docs/Domains.md} +18 -0
  7. data/{Events.md → docs/Events.md} +0 -0
  8. data/{MessageBuilder.md → docs/MessageBuilder.md} +24 -5
  9. data/{Messages.md → docs/Messages.md} +3 -3
  10. data/{OptInHandler.md → docs/OptInHandler.md} +0 -0
  11. data/{Snippets.md → docs/Snippets.md} +21 -2
  12. data/docs/Suppressions.md +82 -0
  13. data/{Webhooks.md → docs/Webhooks.md} +1 -1
  14. data/docs/railgun/Overview.md +11 -0
  15. data/docs/railgun/Parameters.md +83 -0
  16. data/lib/mailgun/address.rb +5 -2
  17. data/lib/mailgun/client.rb +39 -8
  18. data/lib/mailgun/events/events.rb +40 -12
  19. data/lib/mailgun/messages/batch_message.rb +3 -2
  20. data/lib/mailgun/messages/message_builder.rb +99 -26
  21. data/lib/mailgun/suppressions.rb +273 -0
  22. data/lib/mailgun/version.rb +1 -1
  23. data/lib/mailgun/webhooks/webhooks.rb +1 -1
  24. data/lib/mailgun-ruby.rb +2 -1
  25. data/lib/railgun/attachment.rb +56 -0
  26. data/lib/railgun/errors.rb +27 -0
  27. data/lib/railgun/mailer.rb +237 -0
  28. data/lib/railgun/message.rb +17 -0
  29. data/lib/railgun/railtie.rb +10 -0
  30. data/lib/railgun.rb +8 -0
  31. data/mailgun.gemspec +12 -12
  32. data/spec/integration/email_validation_spec.rb +14 -0
  33. data/spec/integration/events_spec.rb +9 -1
  34. data/spec/integration/mailgun_spec.rb +0 -0
  35. data/spec/integration/suppressions_spec.rb +142 -0
  36. data/spec/spec_helper.rb +3 -1
  37. data/spec/unit/events/events_spec.rb +36 -2
  38. data/spec/unit/messages/batch_message_spec.rb +1 -0
  39. data/spec/unit/messages/message_builder_spec.rb +95 -19
  40. data/spec/unit/messages/sample_data/unknown.type +0 -0
  41. data/spec/unit/railgun/content_type_spec.rb +71 -0
  42. data/spec/unit/railgun/mailer_spec.rb +242 -0
  43. data/vcr_cassettes/email_validation.yml +57 -9
  44. data/vcr_cassettes/events.yml +48 -1
  45. data/vcr_cassettes/suppressions.yml +727 -0
  46. metadata +68 -36
@@ -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
@@ -2,13 +2,13 @@
2
2
  http_interactions:
3
3
  - request:
4
4
  method: get
5
- uri: https://api:<PUBKEY>@api.mailgun.net/v3/address/parse?addresses=Alice%20%3Calice@example.com%3E%3Bbob@example.com%3Bexample.org&syntax_only=true
5
+ uri: https://api:<APIKEY>@api.mailgun.net/v3/address/parse?addresses=Alice%20%3Calice@example.com%3E%3Bbob@example.com%3Bexample.org&syntax_only=true
6
6
  body:
7
7
  encoding: US-ASCII
8
8
  string: ''
9
9
  headers:
10
10
  Accept:
11
- - "*/*"
11
+ - '*/*'
12
12
  Accept-Encoding:
13
13
  - gzip, deflate
14
14
  User-Agent:
@@ -33,7 +33,7 @@ http_interactions:
33
33
  Content-Disposition:
34
34
  - inline
35
35
  Access-Control-Allow-Origin:
36
- - "*"
36
+ - '*'
37
37
  Access-Control-Max-Age:
38
38
  - '600'
39
39
  Access-Control-Allow-Methods:
@@ -56,13 +56,13 @@ http_interactions:
56
56
  recorded_at: Wed, 26 Oct 2016 22:44:50 GMT
57
57
  - request:
58
58
  method: get
59
- uri: https://api:<PUBKEY>@api.mailgun.net/v3/address/validate?address=alice@mailgun.net
59
+ uri: https://api:<APIKEY>@api.mailgun.net/v3/address/validate?address=alice@mailgun.net
60
60
  body:
61
61
  encoding: US-ASCII
62
62
  string: ''
63
63
  headers:
64
64
  Accept:
65
- - "*/*"
65
+ - '*/*'
66
66
  Accept-Encoding:
67
67
  - gzip, deflate
68
68
  User-Agent:
@@ -87,7 +87,7 @@ http_interactions:
87
87
  Content-Disposition:
88
88
  - inline
89
89
  Access-Control-Allow-Origin:
90
- - "*"
90
+ - '*'
91
91
  Access-Control-Max-Age:
92
92
  - '600'
93
93
  Access-Control-Allow-Methods:
@@ -111,13 +111,13 @@ http_interactions:
111
111
  recorded_at: Wed, 26 Oct 2016 22:44:50 GMT
112
112
  - request:
113
113
  method: get
114
- uri: https://api:<PUBKEY>@api.mailgun.net/v3/address/validate?address=example.org
114
+ uri: https://api:<APIKEY>@api.mailgun.net/v3/address/validate?address=example.org
115
115
  body:
116
116
  encoding: US-ASCII
117
117
  string: ''
118
118
  headers:
119
119
  Accept:
120
- - "*/*"
120
+ - '*/*'
121
121
  Accept-Encoding:
122
122
  - gzip, deflate
123
123
  User-Agent:
@@ -142,7 +142,7 @@ http_interactions:
142
142
  Content-Disposition:
143
143
  - inline
144
144
  Access-Control-Allow-Origin:
145
- - "*"
145
+ - '*'
146
146
  Access-Control-Max-Age:
147
147
  - '600'
148
148
  Access-Control-Allow-Methods:
@@ -164,4 +164,52 @@ http_interactions:
164
164
  }
165
165
  http_version:
166
166
  recorded_at: Wed, 26 Oct 2016 22:44:50 GMT
167
+ - request:
168
+ method: get
169
+ uri: https://api:<APIKEY>@api.mailgun.net/v3/address/validate?address=alice@mailgun.net&mailbox_verification=true
170
+ body:
171
+ encoding: US-ASCII
172
+ string: ''
173
+ headers:
174
+ Accept:
175
+ - '*/*'
176
+ Accept-Encoding:
177
+ - gzip, deflate
178
+ User-Agent:
179
+ - rest-client/2.0.2 (darwin16.7.0 x86_64) ruby/2.0.0p0
180
+ Host:
181
+ - api.mailgun.net
182
+ response:
183
+ status:
184
+ code: 200
185
+ message: OK
186
+ headers:
187
+ Access-Control-Allow-Headers:
188
+ - Content-Type, x-requested-with
189
+ Access-Control-Allow-Methods:
190
+ - GET, POST, PUT, DELETE, OPTIONS
191
+ Access-Control-Allow-Origin:
192
+ - '*'
193
+ Access-Control-Max-Age:
194
+ - '600'
195
+ Content-Disposition:
196
+ - inline
197
+ Content-Type:
198
+ - application/json
199
+ Date:
200
+ - Tue, 12 Sep 2017 16:55:09 GMT
201
+ Server:
202
+ - nginx
203
+ Content-Length:
204
+ - '243'
205
+ Connection:
206
+ - keep-alive
207
+ body:
208
+ encoding: UTF-8
209
+ string: '{"address": "alice@mailgun.net", "did_you_mean": null, "is_disposable_address":
210
+ false, "is_role_address": false, "is_valid": true, "mailbox_verification":
211
+ "true", "parts": {"display_name": null, "domain": "mailgun.net", "local_part":
212
+ "alice"}}'
213
+ http_version:
214
+ recorded_at: Tue, 12 Sep 2017 16:55:09 GMT
167
215
  recorded_with: VCR 3.0.3
@@ -58,4 +58,51 @@ http_interactions:
58
58
  \ }\n}"
59
59
  http_version:
60
60
  recorded_at: Thu, 07 Jan 2016 22:08:06 GMT
61
- recorded_with: VCR 3.0.1
61
+ - request:
62
+ method: get
63
+ uri: https://api:<APIKEY>@api.mailgun.net/v3/DOMAIN.TEST/events
64
+ body:
65
+ encoding: US-ASCII
66
+ string: ''
67
+ headers:
68
+ Accept:
69
+ - "*/*"
70
+ Accept-Encoding:
71
+ - gzip, deflate
72
+ User-Agent:
73
+ - rest-client/2.0.1 (linux-gnu x86_64) ruby/2.3.3p222
74
+ Host:
75
+ - api.mailgun.net
76
+ response:
77
+ status:
78
+ code: 200
79
+ message: OK
80
+ headers:
81
+ Access-Control-Allow-Headers:
82
+ - Content-Type, x-requested-with
83
+ Access-Control-Allow-Methods:
84
+ - GET, POST, PUT, DELETE, OPTIONS
85
+ Access-Control-Allow-Origin:
86
+ - "*"
87
+ Access-Control-Max-Age:
88
+ - '600'
89
+ Content-Type:
90
+ - application/json
91
+ Date:
92
+ - Wed, 10 May 2017 20:06:54 GMT
93
+ Server:
94
+ - nginx
95
+ Content-Length:
96
+ - '2060'
97
+ Connection:
98
+ - keep-alive
99
+ body:
100
+ encoding: UTF-8
101
+ string: "{\n \"items\": [], \n \"paging\": {\n \"next\": \"https://api.mailgun.net/v3/DOMAIN.TEST/events/W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTAwLCBudWxsXQ==\",
102
+ \n \"last\": \"https://api.mailgun.net/v3/DOMAIN.TEST/events/W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTA4VDIwOjA2OjU0LjU3NyswMDowMCIsICJlIjogIjIwMTctMDUtMTBUMjA6MDY6NTQuNTc2KzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIFtbImFjY291bnQuaWQiLCAiNTgwNTIxODY3OGZhMTYxM2M3OTBiNTBmIl0sIFsiZG9tYWluLm5hbWUiLCAic2FuZGJveDI5NzAxNTJhZjNkMzQ1NTliZmM3ZTcxNzAzYTZjZjI0Lm1haWxndW4ub3JnIl1dLCAxMDAsIG51bGxd\",
103
+ \n \"first\": \"https://api.mailgun.net/v3/DOMAIN.TEST/events/W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsiZiJdLCBudWxsLCBbWyJhY2NvdW50LmlkIiwgIjU4MDUyMTg2NzhmYTE2MTNjNzkwYjUwZiJdLCBbImRvbWFpbi5uYW1lIiwgInNhbmRib3gyOTcwMTUyYWYzZDM0NTU5YmZjN2U3MTcwM2E2Y2YyNC5tYWlsZ3VuLm9yZyJdXSwgMTAwLCBudWxsXQ==\",
104
+ \n \"previous\": \"https://api.mailgun.net/v3/DOMAIN.TEST/events/W3siYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMDhUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIHsiYiI6ICIyMDE3LTA1LTEwVDIwOjA2OjU0LjU3NiswMDowMCIsICJlIjogIjIwMTctMDUtMTBUMjA6MDY6NTQuNTc3KzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIFtbImFjY291bnQuaWQiLCAiNTgwNTIxODY3OGZhMTYxM2M3OTBiNTBmIl0sIFsiZG9tYWluLm5hbWUiLCAic2FuZGJveDI5NzAxNTJhZjNkMzQ1NTliZmM3ZTcxNzAzYTZjZjI0Lm1haWxndW4ub3JnIl1dLCAxMDAsIG51bGxd\"\n
105
+ \ }\n}"
106
+ http_version:
107
+ recorded_at: Wed, 10 May 2017 20:06:54 GMT
108
+ recorded_with: VCR 3.0.3