mailgun-ruby 1.1.9 → 1.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -0
  3. data/.rubocop_todo.yml +0 -0
  4. data/.ruby-env.yml.example +0 -0
  5. data/.travis.yml +6 -5
  6. data/CHANGELOG.md +16 -0
  7. data/Gemfile +1 -1
  8. data/README.md +27 -3
  9. data/docs/Domains.md +3 -0
  10. data/docs/OptInHandler.md +1 -1
  11. data/docs/Snippets.md +54 -61
  12. data/docs/Webhooks.md +0 -0
  13. data/docs/railgun/Overview.md +11 -0
  14. data/docs/railgun/Parameters.md +83 -0
  15. data/docs/railgun/Templates.md +92 -0
  16. data/lib/mailgun/address.rb +3 -28
  17. data/lib/mailgun/chains.rb +0 -0
  18. data/lib/mailgun/client.rb +44 -9
  19. data/lib/mailgun/domains/domains.rb +20 -2
  20. data/lib/mailgun/events/events.rb +2 -2
  21. data/lib/mailgun/exceptions/exceptions.rb +28 -1
  22. data/lib/mailgun/messages/batch_message.rb +1 -0
  23. data/lib/mailgun/messages/message_builder.rb +56 -8
  24. data/lib/mailgun/response.rb +7 -0
  25. data/lib/mailgun/suppressions.rb +15 -8
  26. data/lib/mailgun/templates/templates.rb +187 -0
  27. data/lib/mailgun/version.rb +1 -1
  28. data/lib/mailgun/webhooks/webhooks.rb +2 -2
  29. data/lib/mailgun-ruby.rb +1 -1
  30. data/lib/mailgun.rb +4 -1
  31. data/lib/railgun/mailer.rb +83 -12
  32. data/lib/railgun/message.rb +2 -1
  33. data/lib/railgun/railtie.rb +3 -2
  34. data/mailgun.gemspec +15 -12
  35. data/spec/integration/bounces_spec.rb +3 -3
  36. data/spec/integration/campaign_spec.rb +0 -0
  37. data/spec/integration/complaints_spec.rb +0 -0
  38. data/spec/integration/domains_spec.rb +8 -0
  39. data/spec/integration/email_validation_spec.rb +10 -2
  40. data/spec/integration/events_spec.rb +1 -1
  41. data/spec/integration/list_members_spec.rb +0 -0
  42. data/spec/integration/list_spec.rb +0 -0
  43. data/spec/integration/mailer_spec.rb +67 -0
  44. data/spec/integration/mailgun_spec.rb +92 -1
  45. data/spec/integration/routes_spec.rb +0 -0
  46. data/spec/integration/stats_spec.rb +0 -0
  47. data/spec/integration/suppressions_spec.rb +18 -2
  48. data/spec/integration/templates_spec.rb +135 -0
  49. data/spec/integration/unsubscribes_spec.rb +0 -0
  50. data/spec/integration/webhook_spec.rb +0 -0
  51. data/spec/spec_helper.rb +3 -1
  52. data/spec/unit/connection/test_client.rb +18 -1
  53. data/spec/unit/events/events_spec.rb +19 -0
  54. data/spec/unit/mailgun_spec.rb +43 -2
  55. data/spec/unit/messages/batch_message_spec.rb +56 -40
  56. data/spec/unit/messages/message_builder_spec.rb +149 -16
  57. data/spec/unit/messages/sample_data/unknown.type +0 -0
  58. data/spec/unit/railgun/mailer_spec.rb +388 -0
  59. data/vcr_cassettes/bounces.yml +12 -12
  60. data/vcr_cassettes/complaints.yml +0 -0
  61. data/vcr_cassettes/domains.todo.yml +0 -0
  62. data/vcr_cassettes/domains.yml +51 -1
  63. data/vcr_cassettes/email_validation.yml +5 -5
  64. data/vcr_cassettes/events.yml +0 -0
  65. data/vcr_cassettes/exceptions-invalid-api-key.yml +52 -0
  66. data/vcr_cassettes/exceptions-invalid-data.yml +52 -0
  67. data/vcr_cassettes/exceptions-not-allowed.yml +54 -0
  68. data/vcr_cassettes/list_members.yml +0 -0
  69. data/vcr_cassettes/mailer_invalid_domain.yml +109 -0
  70. data/vcr_cassettes/mailing_list.todo.yml +0 -0
  71. data/vcr_cassettes/mailing_list.yml +0 -0
  72. data/vcr_cassettes/message_deliver.yml +149 -0
  73. data/vcr_cassettes/routes.yml +0 -0
  74. data/vcr_cassettes/send_message.yml +0 -0
  75. data/vcr_cassettes/stats.yml +0 -0
  76. data/vcr_cassettes/suppressions.yml +66 -15
  77. data/vcr_cassettes/templates.yml +1065 -0
  78. data/vcr_cassettes/unsubscribes.yml +0 -0
  79. data/vcr_cassettes/webhooks.yml +0 -0
  80. metadata +49 -29
  81. data/.ruby-version +0 -1
  82. /data/spec/unit/{railgun_spec.rb → railgun/content_type_spec.rb} +0 -0
@@ -0,0 +1,83 @@
1
+ Parameters
2
+ ==========
3
+
4
+ When sending messages via Railgun, it is often useful to set options, headers, and variables
5
+ that should be added to the `POST` request against the messages endpoint.
6
+
7
+
8
+ ## Options
9
+
10
+ See [Mailgun Docs | Sending](https://documentation.mailgun.com/en/latest/api-sending.html#sending) for available options.
11
+
12
+ ---
13
+
14
+ To set options on a message:
15
+
16
+ ```ruby
17
+ # app/controllers/some_controller.rb
18
+
19
+ message = YourMailer.your_message(@args)
20
+
21
+ message.mailgun_options ||= {
22
+ "tracking-opens" => "true",
23
+ "tracking-clicks" => "htmlonly",
24
+ "tag" => "some,tags",
25
+ }
26
+ ```
27
+
28
+
29
+ ## Variables
30
+
31
+ See [Mailgun Docs | Attaching Data to Messages](https://documentation.mailgun.com/en/latest/user_manual.html#attaching-data-to-messages) for more information.
32
+
33
+ ---
34
+
35
+ To set variables on a message:
36
+
37
+ ```ruby
38
+ # app/controllers/some_controller.rb
39
+
40
+ message = YourMailer.your_message(@args)
41
+
42
+ message.mailgun_variables ||= {
43
+ "user_info" => {"id" => "1", "name" => "tstark"},
44
+ }
45
+ ```
46
+
47
+
48
+ ## Headers
49
+
50
+ See [Mailgun Docs | Sending](https://documentation.mailgun.com/en/latest/api-sending.html#sending) for more information.
51
+
52
+ ---
53
+
54
+ To set headers on a message *from a controller*:
55
+
56
+ ```ruby
57
+ # app/controllers/some_controller.rb
58
+
59
+ message = YourMailer.your_message(@args)
60
+
61
+ message.mailgun_headers ||= {
62
+ "X-Sent-From-Rails" => "true",
63
+ }
64
+ ```
65
+
66
+ To set headers on a message *from a mailer*:
67
+
68
+ ```ruby
69
+ # app/mailers/your_mailer.rb
70
+
71
+ class YourMailer < ApplicationMailer
72
+ # ...
73
+
74
+ def your_message(args)
75
+ headers({
76
+ "X-Sent-From-Rails" => "true",
77
+ })
78
+
79
+ mail to: "some-address@example.org", ...
80
+ end
81
+
82
+ end
83
+ ```
@@ -0,0 +1,92 @@
1
+ Mailgun - Templates
2
+ ====================
3
+
4
+ This is the Mailgun Ruby *Templates* utilities.
5
+
6
+ The below assumes you've already installed the Mailgun Ruby SDK in to your
7
+ project. If not, go back to the master README for instructions.
8
+
9
+ Usage - Templates
10
+ -----------------------
11
+
12
+ **Build a message with a template:**
13
+
14
+ ```ruby
15
+ mb_obj = Mailgun::MessageBuilder.new
16
+
17
+ mb_obj.from("sender@example.com")
18
+ mb_obj.add_recipient("to", "recipient@example.com")
19
+ mb_obj.subject ("This is the subject!")
20
+ message.template('example.template.name')
21
+ message.template_version('example.tag')
22
+
23
+ mg_client.send_message "sending_domain.com", mb_obj
24
+ ```
25
+
26
+ **Rails Example. Build a message with a template:**
27
+
28
+ ```ruby
29
+ class UserMailer < ApplicationMailer
30
+ def welcome_email
31
+ message = mail(
32
+ from: "sender@example.com",
33
+ to: "recipient@example.com",
34
+ subject: "This is the subject!",
35
+ template: 'example.template.name'
36
+ ) do |format|
37
+ format.text { render plain: "Test!" }
38
+ end
39
+ message.tap do |message|
40
+ message.mailgun_template_variables ||= {
41
+ 'version' => 'example.tag'
42
+ }
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
48
+ Template Handlebars
49
+ -------------------------
50
+
51
+ ```
52
+ {{#if english}}
53
+ <p>This text is in the English language.</p>
54
+ {{else if spanish}}
55
+ <p>Este texto está en idioma español.</p>
56
+ {{else if french}}
57
+ <p>Ce texte est en langue française.</p>
58
+ {{/if}}
59
+ ```
60
+
61
+ In order to send the spanish version, for example:
62
+
63
+ ```ruby
64
+ message.variable('spanish', 'true')
65
+ ```
66
+
67
+ Also, Rails example:
68
+
69
+ ```ruby
70
+ class UserMailer < ApplicationMailer
71
+ def welcome_email
72
+ message = mail(
73
+ from: "sender@example.com",
74
+ to: "recipient@example.com",
75
+ subject: "This is the subject!",
76
+ template: 'example.template.name'
77
+ ) do |format|
78
+ format.text { render plain: "Test!" }
79
+ end
80
+ message.tap do |message|
81
+ message.mailgun_variables ||= {
82
+ 'spanish' => 'true'
83
+ }
84
+ end
85
+ end
86
+ end
87
+ ```
88
+
89
+ More Documentation
90
+ ------------------
91
+ See the official [Mailgun Templates Docs](https://documentation.mailgun.com/en/latest/api-templates.html)
92
+ for more information
@@ -4,45 +4,20 @@ module Mailgun
4
4
 
5
5
  # Mailgun::Address is a simple interface to the Email Validation API.
6
6
  class Address
7
-
8
- # @param [String] api_key Mailgun API - public key
9
- def initialize(api_key = "")
10
- if api_key == "" then
11
- fail ParameterError.new('Public API key is required for Mailgun::Address.initialize()', nil)
12
- end
13
-
14
- @api_key = api_key
15
- @client = Mailgun::Client.new(api_key = api_key)
7
+ def initialize
8
+ @client = Mailgun::Client.new(Mailgun.api_key, Mailgun.api_host || 'api.mailgun.net', 'v4')
16
9
  end
17
10
 
18
11
  # Given an arbitrary address, validates it based on defined checks.
19
12
  #
20
13
  # @param [String] address Email address to validate (max 512 chars.)
21
14
  def validate(address, mailbox_verification = false)
22
- params = {:address => address}
15
+ params = {address: address}
23
16
  params[:mailbox_verification] = true if mailbox_verification
24
17
 
25
18
  res = @client.get "address/validate", params
26
19
  return res.to_h!
27
20
  end
28
-
29
- # Parses a delimiter separated list of email addresses into two lists:
30
- # parsed addresses and unparsable portions. The parsed addresses are a
31
- # list of addresses that are syntactically valid (and optionally have
32
- # DNS and ESP specific grammar checks) the unparsable list is a list
33
- # of characters sequences that the parser was not able to understand.
34
- # These often align with invalid email addresses, but not always.
35
- # Delimiter characters are comma (,) and semicolon (;).
36
- #
37
- # @param [Array] addresses Addresses to parse
38
- # @param [TrueClass|FalseClass] syntax_only Perform only syntax checks
39
- def parse(addresses, syntax_only = true)
40
- validate_addrs = addresses.join(";")
41
-
42
- res = @client.get "address/parse", {:addresses => validate_addrs,
43
- :syntax_only => syntax_only.to_s}
44
- return res.to_h!
45
- end
46
21
  end
47
22
 
48
23
  end
File without changes
@@ -11,16 +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
- test_mode = false)
17
+ test_mode = false,
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
18
27
 
19
28
  endpoint = endpoint_generator(api_host, api_version, ssl)
20
- @http_client = RestClient::Resource.new(endpoint,
21
- user: 'api',
22
- password: api_key,
23
- user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}")
29
+ RestClient.proxy = proxy_url
30
+ @http_client = RestClient::Resource.new(endpoint, rest_client_params)
24
31
  @test_mode = test_mode
25
32
  end
26
33
 
@@ -38,6 +45,11 @@ module Mailgun
38
45
  @test_mode = false
39
46
  end
40
47
 
48
+ # Change API key
49
+ def set_api_key(api_key)
50
+ @http_client.options[:password] = api_key
51
+ end
52
+
41
53
  # Client is in test mode?
42
54
  #
43
55
  # @return [Boolean] Is the client set in test mode?
@@ -59,11 +71,13 @@ module Mailgun
59
71
  # containing required parameters for the requested resource.
60
72
  # @return [Mailgun::Response] A Mailgun::Response object.
61
73
  def send_message(working_domain, data)
74
+ perform_data_validation(working_domain, data)
75
+
62
76
  if test_mode? then
63
77
  Mailgun::Client.deliveries << data
64
78
  return Response.from_hash(
65
79
  {
66
- :body => '{"id": "test-mode-mail@localhost", "message": "Queued. Thank you."}',
80
+ :body => "{\"id\": \"test-mode-mail-#{SecureRandom.uuid}@localhost\", \"message\": \"Queued. Thank you.\"}",
67
81
  :code => 200,
68
82
  }
69
83
  )
@@ -191,9 +205,30 @@ module Mailgun
191
205
  #
192
206
  # @param [StandardException] e upstream exception object
193
207
  def communication_error(e)
194
- 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
195
218
  CommunicationError.new(e.message)
196
219
  end
197
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 contain 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 contain at least 1 `from` sender',
230
+ working_domain
231
+ ) if message.fetch('from', []).empty? && message.fetch(:from, []).empty?
232
+ end
198
233
  end
199
234
  end
@@ -53,9 +53,10 @@ 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
- # Tag, messages will be tagged wtih a spam header. See Spam Filter.
58
+ # Block, inbound spam messages will not be delivered.
59
+ # Tag, messages will be tagged with 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
  #
61
62
  # Returns [Hash] of created domain
@@ -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
@@ -88,7 +88,7 @@ module Mailgun
88
88
  # Return is irrelevant.
89
89
  def extract_paging(response)
90
90
  paging = response.to_h['paging']
91
- next_page_url = paging && paging['next'] # gives nil when any one of the keys doens't exist
91
+ next_page_url = paging && paging['next'] # gives nil when any one of the keys doesn't exist
92
92
  previous_page_url = paging && paging['previous'] # can be replaced with Hash#dig for ruby >= 2.3.0
93
93
  @paging_next = extract_endpoint_from(next_page_url)
94
94
  @paging_previous = extract_endpoint_from(previous_page_url)
@@ -101,7 +101,7 @@ module Mailgun
101
101
  # Returns a String of the partial URI if the given url follows the regular API format
102
102
  # Returns nil in other cases (e.g. when given nil, or an irrelevant url)
103
103
  def extract_endpoint_from(url = nil)
104
- URI.parse(url).path[/api.mailgun.net\/v[\d]\/#{@domain}\/events\/(.+)/,1]
104
+ URI.parse(url).path[/\/v[\d]\/#{@domain}\/events\/(.+)/,1]
105
105
  rescue URI::InvalidURIError
106
106
  nil
107
107
  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
@@ -124,7 +125,7 @@ module Mailgun
124
125
  add_file(:attachment, attachment, filename)
125
126
  end
126
127
 
127
- # Adds an inline image to the mesage object.
128
+ # Adds an inline image to the message object.
128
129
  #
129
130
  # @param [String|File] inline_image A file object for attaching an inline image.
130
131
  # @param [String] filename The filename you wish the inline image to be.
@@ -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 preferred: 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'
@@ -58,5 +58,12 @@ module Mailgun
58
58
  rescue => err
59
59
  raise ParseError.new(err), err
60
60
  end
61
+
62
+ # Returns true if response code is 2xx
63
+ #
64
+ # @return [Boolean] A boolean that binarizes the response code result.
65
+ def success?
66
+ (200..299).include?(code)
67
+ end
61
68
  end
62
69
  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