mailgun-ruby 1.2.0 → 1.2.10

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/docs/Domains.md +3 -0
  4. data/docs/OptInHandler.md +1 -1
  5. data/docs/Snippets.md +54 -61
  6. data/docs/railgun/Templates.md +92 -0
  7. data/lib/mailgun/address.rb +3 -28
  8. data/lib/mailgun/client.rb +43 -10
  9. data/lib/mailgun/domains/domains.rb +19 -1
  10. data/lib/mailgun/exceptions/exceptions.rb +28 -1
  11. data/lib/mailgun/messages/batch_message.rb +1 -0
  12. data/lib/mailgun/messages/message_builder.rb +55 -7
  13. data/lib/mailgun/suppressions.rb +15 -8
  14. data/lib/mailgun/version.rb +1 -1
  15. data/lib/mailgun-ruby.rb +1 -1
  16. data/lib/mailgun.rb +3 -1
  17. data/lib/railgun/mailer.rb +30 -9
  18. data/lib/railgun/message.rb +2 -1
  19. data/lib/railgun/railtie.rb +3 -2
  20. data/mailgun.gemspec +1 -1
  21. data/spec/integration/bounces_spec.rb +3 -3
  22. data/spec/integration/domains_spec.rb +8 -0
  23. data/spec/integration/email_validation_spec.rb +1 -8
  24. data/spec/integration/mailer_spec.rb +67 -0
  25. data/spec/integration/mailgun_spec.rb +76 -1
  26. data/spec/integration/suppressions_spec.rb +18 -2
  27. data/spec/unit/connection/test_client.rb +18 -1
  28. data/spec/unit/mailgun_spec.rb +43 -2
  29. data/spec/unit/messages/batch_message_spec.rb +56 -40
  30. data/spec/unit/messages/message_builder_spec.rb +149 -16
  31. data/spec/unit/messages/sample_data/unknown.type +0 -0
  32. data/spec/unit/railgun/mailer_spec.rb +171 -0
  33. data/vcr_cassettes/bounces.yml +12 -12
  34. data/vcr_cassettes/domains.yml +51 -1
  35. data/vcr_cassettes/exceptions-invalid-api-key.yml +52 -0
  36. data/vcr_cassettes/exceptions-invalid-data.yml +52 -0
  37. data/vcr_cassettes/exceptions-not-allowed.yml +54 -0
  38. data/vcr_cassettes/mailer_invalid_domain.yml +109 -0
  39. data/vcr_cassettes/message_deliver.yml +149 -0
  40. data/vcr_cassettes/suppressions.yml +66 -15
  41. metadata +15 -6
@@ -11,18 +11,23 @@ module Mailgun
11
11
  class Client
12
12
 
13
13
  def initialize(api_key = Mailgun.api_key,
14
- api_host = 'api.mailgun.net',
15
- api_version = 'v3',
14
+ api_host = Mailgun.api_host || 'api.mailgun.net',
15
+ api_version = Mailgun.api_version || 'v3',
16
16
  ssl = true,
17
17
  test_mode = false,
18
- timeout = nil)
18
+ timeout = nil,
19
+ proxy_url = Mailgun.proxy_url)
20
+
21
+ rest_client_params = {
22
+ user: 'api',
23
+ password: api_key,
24
+ user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}"
25
+ }
26
+ rest_client_params[:timeout] = timeout if timeout
19
27
 
20
28
  endpoint = endpoint_generator(api_host, api_version, ssl)
21
- @http_client = RestClient::Resource.new(endpoint,
22
- user: 'api',
23
- password: api_key,
24
- user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}",
25
- timeout: timeout)
29
+ RestClient.proxy = proxy_url
30
+ @http_client = RestClient::Resource.new(endpoint, rest_client_params)
26
31
  @test_mode = test_mode
27
32
  end
28
33
 
@@ -40,6 +45,11 @@ module Mailgun
40
45
  @test_mode = false
41
46
  end
42
47
 
48
+ # Change API key
49
+ def set_api_key(api_key)
50
+ @http_client.options[:password] = api_key
51
+ end
52
+
43
53
  # Client is in test mode?
44
54
  #
45
55
  # @return [Boolean] Is the client set in test mode?
@@ -61,11 +71,13 @@ module Mailgun
61
71
  # containing required parameters for the requested resource.
62
72
  # @return [Mailgun::Response] A Mailgun::Response object.
63
73
  def send_message(working_domain, data)
74
+ perform_data_validation(working_domain, data)
75
+
64
76
  if test_mode? then
65
77
  Mailgun::Client.deliveries << data
66
78
  return Response.from_hash(
67
79
  {
68
- :body => '{"id": "test-mode-mail@localhost", "message": "Queued. Thank you."}',
80
+ :body => "{\"id\": \"test-mode-mail-#{SecureRandom.uuid}@localhost\", \"message\": \"Queued. Thank you.\"}",
69
81
  :code => 200,
70
82
  }
71
83
  )
@@ -193,9 +205,30 @@ module Mailgun
193
205
  #
194
206
  # @param [StandardException] e upstream exception object
195
207
  def communication_error(e)
196
- return CommunicationError.new(e.message, e.response) if e.respond_to? :response
208
+ if e.respond_to?(:response) && e.response
209
+ return case e.response.code
210
+ when Unauthorized::CODE
211
+ Unauthorized.new(e.message, e.response)
212
+ when BadRequest::CODE
213
+ BadRequest.new(e.message, e.response)
214
+ else
215
+ CommunicationError.new(e.message, e.response)
216
+ end
217
+ end
197
218
  CommunicationError.new(e.message)
198
219
  end
199
220
 
221
+ def perform_data_validation(working_domain, data)
222
+ message = data.respond_to?(:message) ? data.message : data
223
+ fail ParameterError.new('Missing working domain', working_domain) unless working_domain
224
+ fail ParameterError.new(
225
+ 'Missing `to` recipient, message should containg at least 1 recipient',
226
+ working_domain
227
+ ) if message.fetch('to', []).empty? && message.fetch(:to, []).empty?
228
+ fail ParameterError.new(
229
+ 'Missing a `from` sender, message should containg at least 1 `from` sender',
230
+ working_domain
231
+ ) if message.fetch('from', []).empty? && message.fetch(:from, []).empty?
232
+ end
200
233
  end
201
234
  end
@@ -53,8 +53,9 @@ module Mailgun
53
53
  # domain - [String] Name of the domain (ex. domain.com)
54
54
  # options - [Hash] of
55
55
  # smtp_password - [String] Password for SMTP authentication
56
- # spam_action - [String] disabled or tag
56
+ # spam_action - [String] disabled, blocked or tag
57
57
  # Disable, no spam filtering will occur for inbound messages.
58
+ # Block, inbound spam messages will not be delivered.
58
59
  # Tag, messages will be tagged wtih a spam header. See Spam Filter.
59
60
  # wildcard - [Boolean] true or false Determines whether the domain will accept email for sub-domains.
60
61
  #
@@ -80,5 +81,22 @@ module Mailgun
80
81
  alias_method :delete, :remove
81
82
  alias_method :delete_domain, :remove
82
83
 
84
+ # Public: Update domain
85
+ #
86
+ # domain - [String] Name of the domain (ex. domain.com)
87
+ # options - [Hash] of
88
+ # spam_action - [String] disabled, blocked or tag
89
+ # Disable, no spam filtering will occur for inbound messages.
90
+ # Block, inbound spam messages will not be delivered.
91
+ # Tag, messages will be tagged wtih a spam header. See Spam Filter.
92
+ # web_scheme - [String] http or https
93
+ # Set your open, click and unsubscribe URLs to use http or https
94
+ # wildcard - [Boolean] true or false Determines whether the domain will accept email for sub-domains.
95
+ #
96
+ # Returns [Hash] of updated domain
97
+ def update(domain, options = {})
98
+ fail(ParameterError, 'No domain given to add on Mailgun', caller) unless domain
99
+ @client.put("domains/#{domain}", options).to_h
100
+ end
83
101
  end
84
102
  end
@@ -34,6 +34,7 @@ module Mailgun
34
34
 
35
35
  # Public: fallback if there is no response code on the object
36
36
  NOCODE = 000
37
+ FORBIDDEN = 'Forbidden'
37
38
 
38
39
  # Public: initialization of new error given a message and/or object
39
40
  #
@@ -42,7 +43,11 @@ module Mailgun
42
43
  #
43
44
  def initialize(message = nil, response = nil)
44
45
  @response = response
45
- @code = response.code || NOCODE
46
+ @code = if response.nil?
47
+ NOCODE
48
+ else
49
+ response.code
50
+ end
46
51
 
47
52
  begin
48
53
  api_message = JSON.parse(response.body)['message']
@@ -50,6 +55,8 @@ module Mailgun
50
55
  api_message = response.body
51
56
  rescue NoMethodError
52
57
  api_message = "Unknown API error"
58
+ rescue
59
+ api_message = 'Unknown API error'
53
60
  end
54
61
 
55
62
  message = message || ''
@@ -60,6 +67,26 @@ module Mailgun
60
67
  @code = NOCODE
61
68
  super(message, response)
62
69
  end
70
+ end
71
+
72
+ # Public: Class for managing unauthorized 401 errors
73
+ # Inherits from Mailgun::CommunicationError
74
+ class Unauthorized < CommunicationError
75
+ CODE = 401
63
76
 
77
+ def initialize(error_message, response)
78
+ error_message = error_message + ' - Invalid Domain or API key'
79
+ super(error_message, response)
80
+ end
81
+ end
82
+
83
+ # Public: Class for managing bad request 400 errors
84
+ # Inherits from Mailgun::CommunicationError
85
+ class BadRequest < CommunicationError
86
+ CODE = 400
87
+
88
+ def initialize(error_message, response)
89
+ super(error_message, response)
90
+ end
64
91
  end
65
92
  end
@@ -111,6 +111,7 @@ module Mailgun
111
111
  # This method resets the message object to prepare for the next batch
112
112
  # of recipients.
113
113
  def reset_message
114
+ @recipient_variables = {}
114
115
  @message.delete('recipient-variables')
115
116
  @message.delete(:to)
116
117
  @message.delete(:cc)
@@ -1,3 +1,4 @@
1
+ require 'mime/types'
1
2
  require 'time'
2
3
 
3
4
  module Mailgun
@@ -197,7 +198,9 @@ module Mailgun
197
198
  # @param [Boolean] tracking Boolean true or false.
198
199
  # @return [void]
199
200
  def track_opens(mode)
200
- set_multi_simple('o:tracking-opens', bool_lookup(mode))
201
+ value = bool_lookup(mode)
202
+ set_single('o:tracking-opens', value)
203
+ set_multi_simple('o:tracking', value)
201
204
  end
202
205
 
203
206
  # Deprecated: 'set_open_tracking' is deprecated. Please use 'track_opens' instead.
@@ -211,7 +214,9 @@ module Mailgun
211
214
  # @param [String] mode True, False, or HTML (for HTML only tracking)
212
215
  # @return [void]
213
216
  def track_clicks(mode)
214
- set_multi_simple('o:tracking-clicks', bool_lookup(mode))
217
+ value = bool_lookup(mode)
218
+ set_single('o:tracking-clicks', value)
219
+ set_multi_simple('o:tracking', value)
215
220
  end
216
221
 
217
222
  # Depreciated: 'set_click_tracking. is deprecated. Please use 'track_clicks' instead.
@@ -269,8 +274,12 @@ module Mailgun
269
274
  # @return [void]
270
275
  def variable(name, data)
271
276
  fail(Mailgun::ParameterError, 'Variable name must be specified') if name.to_s.empty?
272
- jsondata = make_json data
273
- set_single("v:#{name}", jsondata)
277
+ begin
278
+ jsondata = make_json data
279
+ set_single("v:#{name}", jsondata)
280
+ rescue Mailgun::ParameterError
281
+ set_single("v:#{name}", data)
282
+ end
274
283
  end
275
284
 
276
285
  # Add custom parameter to the message. A custom parameter is any parameter that
@@ -303,6 +312,38 @@ module Mailgun
303
312
  message_id data
304
313
  end
305
314
 
315
+ # Set name of a template stored via template API. See Templates for more information
316
+ # https://documentation.mailgun.com/en/latest/api-templates.html
317
+ #
318
+ # @param [String] tag A defined template name to use. Passing nil or
319
+ # empty string will delete template key and value from @message hash.
320
+ # @return [void]
321
+ def template(template_name = nil)
322
+ key = 'template'
323
+ return @message.delete(key) if template_name.to_s.empty?
324
+ set_single(key, template_name)
325
+ end
326
+
327
+ # Set specific template version.
328
+ #
329
+ # @param [String] tag A defined template name to use. Passing nil or
330
+ # empty string will delete template key and value from @message hash.
331
+ # @return [void]
332
+ def template_version(version = nil)
333
+ key = 't:version'
334
+ return @message.delete(key) if version.to_s.empty?
335
+ set_single(key, version)
336
+ end
337
+
338
+ # Turn off or on template rendering in the text part
339
+ # of the message in case of template sending.
340
+ #
341
+ # @param [Boolean] tracking Boolean true or false.
342
+ # @return [void]
343
+ def template_text(mode)
344
+ set_single('t:text', bool_lookup(mode))
345
+ end
346
+
306
347
  private
307
348
 
308
349
  # Sets a single value in the message hash where "multidict" features are not needed.
@@ -342,6 +383,7 @@ module Mailgun
342
383
  def bool_lookup(value)
343
384
  return 'yes' if %w(true yes yep).include? value.to_s.downcase
344
385
  return 'no' if %w(false no nope).include? value.to_s.downcase
386
+ warn 'WARN: for bool type actions next values are prefered: true yes yep | false no nope | htmlonly'
345
387
  value
346
388
  end
347
389
 
@@ -364,7 +406,7 @@ module Mailgun
364
406
  def make_json(obj)
365
407
  return JSON.parse(obj).to_json if obj.is_a?(String)
366
408
  return obj.to_json if obj.is_a?(Hash)
367
- return JSON.generate(obj).to_json
409
+ JSON.generate(obj).to_json
368
410
  rescue
369
411
  raise Mailgun::ParameterError, 'Provided data could not be made into JSON. Try a JSON string or Hash.', obj
370
412
  end
@@ -387,9 +429,9 @@ module Mailgun
387
429
  full_name = vars['full_name']
388
430
  elsif vars['first'] || vars['last']
389
431
  full_name = "#{vars['first']} #{vars['last']}".strip
390
- end
432
+ end
391
433
 
392
- return "'#{full_name}' <#{address}>" if defined?(full_name)
434
+ return "'#{full_name}' <#{address}>" if full_name
393
435
  address
394
436
  end
395
437
 
@@ -409,6 +451,12 @@ module Mailgun
409
451
  'Unable to access attachment file object.'
410
452
  ) unless attachment.respond_to?(:read)
411
453
 
454
+ if attachment.respond_to?(:path) && !attachment.respond_to?(:content_type)
455
+ mime_types = MIME::Types.type_for(attachment.path)
456
+ content_type = mime_types.empty? ? 'application/octet-stream' : mime_types[0].content_type
457
+ attachment.instance_eval "def content_type; '#{content_type}'; end"
458
+ end
459
+
412
460
  unless filename.nil?
413
461
  attachment.instance_variable_set :@original_filename, filename
414
462
  attachment.instance_eval 'def original_filename; @original_filename; end'
@@ -45,11 +45,11 @@ module Mailgun
45
45
  end
46
46
 
47
47
  def get_bounce(address)
48
- @client.get("#{@domain}/bounces/#{address}", nil)
48
+ @client.get("#{@domain}/bounces/#{escape_address(address)}", nil)
49
49
  end
50
50
 
51
51
  def create_bounce(params = {})
52
- @client.post("#{@domain/bounces}", params)
52
+ @client.post("#{@domain}/bounces", params)
53
53
  end
54
54
 
55
55
  # Creates multiple bounces on the Mailgun API.
@@ -100,7 +100,7 @@ module Mailgun
100
100
  end
101
101
 
102
102
  def delete_bounce(address)
103
- @client.delete("#{@domain}/bounces/#{address}")
103
+ @client.delete("#{@domain}/bounces/#{escape_address(address)}")
104
104
  end
105
105
 
106
106
  def delete_all_bounces
@@ -118,7 +118,7 @@ module Mailgun
118
118
  end
119
119
 
120
120
  def get_unsubscribe(address)
121
- @client.get("#{@domain}/unsubscribes/#{address}")
121
+ @client.get("#{@domain}/unsubscribes/#{escape_address(address)}")
122
122
  end
123
123
 
124
124
  def create_unsubscribe(params = {})
@@ -157,7 +157,10 @@ module Mailgun
157
157
 
158
158
  unsubscribe.each do |k, v|
159
159
  # Hash values MUST be strings.
160
- if not v.is_a? String then
160
+ # However, unsubscribes contain an array of tags
161
+ if v.is_a? Array
162
+ unsubscribe[k] = v.map(&:to_s)
163
+ elsif !v.is_a? String
161
164
  unsubscribe[k] = v.to_s
162
165
  end
163
166
  end
@@ -170,7 +173,7 @@ module Mailgun
170
173
  end
171
174
 
172
175
  def delete_unsubscribe(address, params = {})
173
- @client.delete("#{@domain}/unsubscribes/#{address}")
176
+ @client.delete("#{@domain}/unsubscribes/#{escape_address(address)}")
174
177
  end
175
178
 
176
179
  ####
@@ -184,7 +187,7 @@ module Mailgun
184
187
  end
185
188
 
186
189
  def get_complaint(address)
187
- @client.get("#{@domain}/complaints/#{address}", nil)
190
+ @client.get("#{@domain}/complaints/#{escape_address(address)}", nil)
188
191
  end
189
192
 
190
193
  def create_complaint(params = {})
@@ -236,11 +239,15 @@ module Mailgun
236
239
  end
237
240
 
238
241
  def delete_complaint(address)
239
- @client.delete("#{@domain}/complaints/#{address}")
242
+ @client.delete("#{@domain}/complaints/#{escape_address(address)}")
240
243
  end
241
244
 
242
245
  private
243
246
 
247
+ def escape_address(address)
248
+ CGI.escape address
249
+ end
250
+
244
251
  def get_from_paging(uri, params = {})
245
252
  @client.get(uri, params)
246
253
  end
@@ -1,4 +1,4 @@
1
1
  # It's the version. Yeay!
2
2
  module Mailgun
3
- VERSION = '1.2.0'
3
+ VERSION = '1.2.10'
4
4
  end
data/lib/mailgun-ruby.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  require 'mailgun'
2
- require 'railgun' if defined?(Rails)
2
+ require 'railgun' if defined?(Rails) && defined?(ActionMailer)
data/lib/mailgun.rb CHANGED
@@ -22,10 +22,12 @@ require 'mailgun/webhooks/webhooks'
22
22
  module Mailgun
23
23
 
24
24
  class << self
25
- attr_accessor :api_key,
25
+ attr_accessor :api_host,
26
+ :api_key,
26
27
  :api_version,
27
28
  :protocol,
28
29
  :mailgun_host,
30
+ :proxy_url,
29
31
  :test_mode,
30
32
  :domain
31
33
 
@@ -11,7 +11,7 @@ module Railgun
11
11
  class Mailer
12
12
 
13
13
  # List of the headers that will be ignored when copying headers from `mail.header_fields`
14
- IGNORED_HEADERS = %w[ to from subject reply-to ]
14
+ IGNORED_HEADERS = %w[ to from subject reply-to mime-version template ]
15
15
 
16
16
  # [Hash] config ->
17
17
  # Requires *at least* `api_key` and `domain` keys.
@@ -32,6 +32,8 @@ module Railgun
32
32
  config[:api_host] || 'api.mailgun.net',
33
33
  config[:api_version] || 'v3',
34
34
  config[:api_ssl].nil? ? true : config[:api_ssl],
35
+ false,
36
+ config[:timeout]
35
37
  )
36
38
  @domain = @config[:domain]
37
39
 
@@ -45,8 +47,14 @@ module Railgun
45
47
  end
46
48
 
47
49
  def deliver!(mail)
50
+ @mg_domain = set_mg_domain(mail)
51
+ @mg_client.set_api_key(mail[:api_key].value) if mail[:api_key].present?
52
+
53
+ mail[:domain] = nil if mail[:domain].present?
54
+ mail[:api_key] = nil if mail[:api_key].present?
55
+
48
56
  mg_message = Railgun.transform_for_mailgun(mail)
49
- response = @mg_client.send_message(@domain, mg_message)
57
+ response = @mg_client.send_message(@mg_domain, mg_message)
50
58
 
51
59
  if response.code == 200 then
52
60
  mg_id = response.to_h['id']
@@ -59,6 +67,14 @@ module Railgun
59
67
  @mg_client
60
68
  end
61
69
 
70
+ private
71
+
72
+ # Set @mg_domain from mail[:domain] header if present, then remove it to prevent being sent.
73
+ def set_mg_domain(mail)
74
+ return mail[:domain].value if mail[:domain]
75
+ domain
76
+ end
77
+
62
78
  end
63
79
 
64
80
  module_function
@@ -76,14 +92,14 @@ module Railgun
76
92
  def transform_for_mailgun(mail)
77
93
  message = build_message_object(mail)
78
94
 
79
- # v:* attributes (variables)
80
- mail.mailgun_variables.try(:each) do |k, v|
81
- message["v:#{k}"] = JSON.dump(v)
82
- end
83
-
84
95
  # o:* attributes (options)
85
96
  mail.mailgun_options.try(:each) do |k, v|
86
- message["o:#{k}"] = v
97
+ message["o:#{k}"] = v.dup
98
+ end
99
+
100
+ # t:* attributes (options)
101
+ mail.mailgun_template_variables.try(:each) do |k, v|
102
+ message["t:#{k}"] = v.dup
87
103
  end
88
104
 
89
105
  # support for using ActionMailer's `headers()` inside of the mailer
@@ -151,6 +167,7 @@ module Railgun
151
167
 
152
168
  mb.from mail[:from]
153
169
  mb.reply_to(mail[:reply_to].to_s) if mail[:reply_to].present?
170
+ mb.template(mail[:template].to_s) if mail[:template].present?
154
171
  mb.subject mail.subject
155
172
  mb.body_html extract_body_html(mail)
156
173
  mb.body_text extract_body_text(mail)
@@ -170,6 +187,11 @@ module Railgun
170
187
  end
171
188
  end
172
189
 
190
+ # v:* attributes (variables)
191
+ mail.mailgun_variables.try(:each) do |name, value|
192
+ mb.variable(name, value)
193
+ end
194
+
173
195
  return mb.message if mail.attachments.empty?
174
196
 
175
197
  mail.attachments.each do |attach|
@@ -231,5 +253,4 @@ module Railgun
231
253
  return mail.html_part if mail.multipart?
232
254
  (mail.mime_type =~ /^text\/html$/i) && mail
233
255
  end
234
-
235
256
  end
@@ -11,7 +11,8 @@ module Mail
11
11
  attr_accessor :mailgun_variables,
12
12
  :mailgun_options,
13
13
  :mailgun_recipient_variables,
14
- :mailgun_headers
14
+ :mailgun_headers,
15
+ :mailgun_template_variables
15
16
 
16
17
  end
17
18
  end
@@ -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
@@ -32,6 +32,6 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency 'vcr', '~> 3.0.3'
33
33
  spec.add_development_dependency 'simplecov', '~> 0.16.1'
34
34
  spec.add_development_dependency 'rails'
35
- spec.add_dependency 'rest-client', '~> 2.0.2'
35
+ spec.add_dependency 'rest-client', '>= 2.0.2'
36
36
 
37
37
  end
@@ -7,7 +7,7 @@ describe 'For the Bounces endpoint', order: :defined, vcr: vcr_opts do
7
7
  before(:all) do
8
8
  @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
9
9
  @domain = TESTDOMAIN
10
- @email = "integration-test-email@#{TESTDOMAIN}"
10
+ @email = "integration-test+email@#{TESTDOMAIN}"
11
11
  end
12
12
 
13
13
  it 'creates a bounce' do
@@ -22,7 +22,7 @@ describe 'For the Bounces endpoint', order: :defined, vcr: vcr_opts do
22
22
  end
23
23
 
24
24
  it 'get a bounce.' do
25
- result = @mg_obj.get("#{@domain}/bounces/#{@email}")
25
+ result = @mg_obj.get("#{@domain}/bounces/#{CGI.escape(@email)}")
26
26
 
27
27
  result.to_h!
28
28
  expect(result.body["code"]).to eq("550")
@@ -38,7 +38,7 @@ describe 'For the Bounces endpoint', order: :defined, vcr: vcr_opts do
38
38
  end
39
39
 
40
40
  it 'deletes a bounce' do
41
- @mg_obj.delete("#{@domain}/bounces/#{@email}")
41
+ @mg_obj.delete("#{@domain}/bounces/#{CGI.escape(@email)}")
42
42
  end
43
43
 
44
44
  end
@@ -36,4 +36,12 @@ describe 'For the domains endpoint', vcr: vcr_opts do
36
36
 
37
37
  expect(result).to be_truthy
38
38
  end
39
+
40
+ it 'updates the domain' do
41
+ result = @mg_obj.update(@domain, { spam_action: 'block', web_scheme: 'https', wildcard: true })
42
+
43
+ expect(result['domain']["spam_action"]).to eq('block')
44
+ expect(result['domain']["web_scheme"]).to eq('https')
45
+ expect(result['domain']["wildcard"]).to eq(true)
46
+ end
39
47
  end
@@ -7,7 +7,7 @@ vcr_opts = { :cassette_name => "email_validation" }
7
7
 
8
8
  describe 'For the email validation endpoint', order: :defined, vcr: vcr_opts do
9
9
  before(:all) do
10
- @mg_obj = Mailgun::Address.new(PUB_APIKEY)
10
+ @mg_obj = Mailgun::Address.new
11
11
 
12
12
  @valid = ["Alice <alice@example.com>", "bob@example.com"]
13
13
  @invalid = ["example.org"]
@@ -15,13 +15,6 @@ describe 'For the email validation endpoint', order: :defined, vcr: vcr_opts do
15
15
  @all_addrs = @valid + @invalid
16
16
  end
17
17
 
18
- it 'returns parsed and unparsable lists' do
19
- res = @mg_obj.parse(@all_addrs)
20
-
21
- expect(res["parsed"]).to eq(@valid)
22
- expect(res["unparseable"]).to eq(@invalid)
23
- end
24
-
25
18
  it 'validates alice@mailgun.net with info' do
26
19
  res = @mg_obj.validate("alice@mailgun.net")
27
20
 
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+ require 'logger'
4
+ require 'railgun'
5
+ require 'mailgun'
6
+ require 'mailgun/exceptions/exceptions'
7
+
8
+ ActionMailer::Base.raise_delivery_errors = true
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, from, subject, headers)
16
+ headers(headers)
17
+ mail(to: address, from: from, 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
+ end
23
+
24
+ vcr_opts = { :cassette_name => 'message_deliver' }
25
+
26
+ describe 'Message deliver', vcr: vcr_opts do
27
+ let(:domain) { TESTDOMAIN }
28
+ let(:config) do
29
+ {
30
+ api_key: APIKEY,
31
+ domain: domain
32
+ }
33
+ end
34
+ let(:mail) { UnitTestMailer.plain_message("bob@#{domain}", "bob@#{domain}", 'subject', {}) }
35
+
36
+ it 'successfully delivers message' do
37
+ result = Railgun::Mailer.new(config).deliver!(mail)
38
+ result.to_h!
39
+
40
+ expect(result.body['message']).to eq('Queued. Thank you.')
41
+ expect(result.body).to include('id')
42
+ expect(result.code).to eq(200)
43
+ end
44
+ end
45
+
46
+ vcr_opts = { :cassette_name => 'mailer_invalid_domain' }
47
+
48
+ describe 'Invalid domain', vcr: vcr_opts do
49
+ let(:domain) { 'not-our-doma.in' }
50
+ let(:config) do
51
+ {
52
+ api_key: APIKEY,
53
+ domain: domain
54
+ }
55
+ end
56
+ let(:mail) { UnitTestMailer.plain_message("bob@#{domain}", 'sally@not-our-doma.in' 'subject', {}) }
57
+
58
+ it 'raises expected error' do
59
+
60
+ Railgun::Mailer.new(config).deliver!(mail)
61
+ rescue Mailgun::CommunicationError => err
62
+ expect(err.message).to eq('401 Unauthorized: Forbidden - Invalid Domain or API key')
63
+ else
64
+ fail
65
+
66
+ end
67
+ end