mailgun-ruby 1.2.0 → 1.2.10

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