mailgun-ruby 1.1.9 → 1.2.13

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 (89) 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 +1 -0
  5. data/.travis.yml +6 -5
  6. data/CHANGELOG.md +16 -0
  7. data/Gemfile +1 -1
  8. data/README.md +30 -3
  9. data/docs/Domains.md +3 -0
  10. data/docs/EmailValidation.md +34 -0
  11. data/docs/OptInHandler.md +1 -1
  12. data/docs/Snippets.md +54 -61
  13. data/docs/Subaccounts.md +68 -0
  14. data/docs/Suppressions.md +10 -0
  15. data/docs/Webhooks.md +0 -0
  16. data/docs/railgun/EmailValidation.md +34 -0
  17. data/docs/railgun/Overview.md +11 -0
  18. data/docs/railgun/Parameters.md +83 -0
  19. data/docs/railgun/Templates.md +92 -0
  20. data/lib/mailgun/address.rb +3 -28
  21. data/lib/mailgun/chains.rb +0 -0
  22. data/lib/mailgun/client.rb +55 -9
  23. data/lib/mailgun/domains/domains.rb +20 -2
  24. data/lib/mailgun/events/events.rb +2 -2
  25. data/lib/mailgun/exceptions/exceptions.rb +28 -1
  26. data/lib/mailgun/messages/batch_message.rb +1 -0
  27. data/lib/mailgun/messages/message_builder.rb +56 -8
  28. data/lib/mailgun/response.rb +7 -0
  29. data/lib/mailgun/subaccounts/subaccounts.rb +84 -0
  30. data/lib/mailgun/suppressions.rb +15 -8
  31. data/lib/mailgun/templates/templates.rb +187 -0
  32. data/lib/mailgun/version.rb +1 -1
  33. data/lib/mailgun/webhooks/webhooks.rb +2 -2
  34. data/lib/mailgun-ruby.rb +1 -1
  35. data/lib/mailgun.rb +5 -1
  36. data/lib/railgun/mailer.rb +85 -12
  37. data/lib/railgun/message.rb +2 -1
  38. data/lib/railgun/railtie.rb +3 -2
  39. data/mailgun.gemspec +15 -12
  40. data/spec/integration/bounces_spec.rb +3 -3
  41. data/spec/integration/campaign_spec.rb +0 -0
  42. data/spec/integration/complaints_spec.rb +0 -0
  43. data/spec/integration/domains_spec.rb +8 -0
  44. data/spec/integration/email_validation_spec.rb +10 -2
  45. data/spec/integration/events_spec.rb +1 -1
  46. data/spec/integration/list_members_spec.rb +0 -0
  47. data/spec/integration/list_spec.rb +0 -0
  48. data/spec/integration/mailer_spec.rb +67 -0
  49. data/spec/integration/mailgun_spec.rb +92 -1
  50. data/spec/integration/routes_spec.rb +0 -0
  51. data/spec/integration/stats_spec.rb +0 -0
  52. data/spec/integration/subaccounts_spec.rb +58 -0
  53. data/spec/integration/suppressions_spec.rb +18 -2
  54. data/spec/integration/templates_spec.rb +135 -0
  55. data/spec/integration/unsubscribes_spec.rb +0 -0
  56. data/spec/integration/webhook_spec.rb +0 -0
  57. data/spec/spec_helper.rb +3 -1
  58. data/spec/unit/connection/test_client.rb +18 -1
  59. data/spec/unit/events/events_spec.rb +19 -0
  60. data/spec/unit/mailgun_spec.rb +43 -2
  61. data/spec/unit/messages/batch_message_spec.rb +56 -40
  62. data/spec/unit/messages/message_builder_spec.rb +149 -16
  63. data/spec/unit/messages/sample_data/unknown.type +0 -0
  64. data/spec/unit/railgun/mailer_spec.rb +388 -0
  65. data/vcr_cassettes/bounces.yml +12 -12
  66. data/vcr_cassettes/complaints.yml +0 -0
  67. data/vcr_cassettes/domains.todo.yml +0 -0
  68. data/vcr_cassettes/domains.yml +51 -1
  69. data/vcr_cassettes/email_validation.yml +5 -5
  70. data/vcr_cassettes/events.yml +0 -0
  71. data/vcr_cassettes/exceptions-invalid-api-key.yml +52 -0
  72. data/vcr_cassettes/exceptions-invalid-data.yml +52 -0
  73. data/vcr_cassettes/exceptions-not-allowed.yml +54 -0
  74. data/vcr_cassettes/list_members.yml +0 -0
  75. data/vcr_cassettes/mailer_invalid_domain.yml +109 -0
  76. data/vcr_cassettes/mailing_list.todo.yml +0 -0
  77. data/vcr_cassettes/mailing_list.yml +0 -0
  78. data/vcr_cassettes/message_deliver.yml +149 -0
  79. data/vcr_cassettes/routes.yml +0 -0
  80. data/vcr_cassettes/send_message.yml +0 -0
  81. data/vcr_cassettes/stats.yml +0 -0
  82. data/vcr_cassettes/subaccounts.yml +270 -0
  83. data/vcr_cassettes/suppressions.yml +66 -15
  84. data/vcr_cassettes/templates.yml +1065 -0
  85. data/vcr_cassettes/unsubscribes.yml +0 -0
  86. data/vcr_cassettes/webhooks.yml +0 -0
  87. metadata +56 -29
  88. data/.ruby-version +0 -1
  89. /data/spec/unit/{railgun_spec.rb → railgun/content_type_spec.rb} +0 -0
@@ -0,0 +1,68 @@
1
+ Mailgun - [Subaccounts](https://help.mailgun.com/hc/en-us/articles/16380043681435-Subaccounts)
2
+ ====================
3
+
4
+ Rails
5
+ -----
6
+
7
+ The library can be initialized with a Rails initializer containing similar:
8
+ ```ruby
9
+ Mailgun.configure do |config|
10
+ config.api_key = 'your-secret-api-key'
11
+ end
12
+ ```
13
+ Or have the initializer read your environment setting if you prefer.
14
+
15
+ ```ruby
16
+ Mailgun.api_key = 'your-secret-api-key'
17
+ ```
18
+
19
+ ```ruby
20
+ mb_obj = Mailgun::Subaccounts.new
21
+
22
+ # Get subaccounts list
23
+ mb_obj.get_subaccounts(limit: 10, skip: 0, sort: 'ask', enabled: true)
24
+ => {"subaccounts"=>[{"id"=>"XYZ", "name"=>"test.subaccount1", "status"=>"open"}, {"id"=>"YYY", "name"=>"test.subaccount2", "status"=>"open"}], "total"=>2}
25
+
26
+ # Get subaccount information
27
+ mb_obj.info(subaccount_id)
28
+ => {"subaccount"=>{"id"=>"XYZ", "name"=>"test.subaccount1", "status"=>"open"}
29
+
30
+ # Add Subaccount
31
+ mb_obj.create(name)
32
+ => {"subaccount"=>{"id"=>"XYZ", "name"=>"test.subaccount1", "status"=>"open"}}
33
+
34
+ # Disable
35
+ mb_obj.disable(subaccount_id)
36
+ => {"subaccount"=>{"id"=>"XYZ", "name"=>"test.subaccount1", "status"=>"disabled"}}
37
+
38
+ # Enable
39
+ mb_obj.enable(subaccount_id)
40
+ => {"subaccount"=>{"id"=>"XYZ", "name"=>"test.subaccount1", "status"=>"open"}}
41
+ ```
42
+
43
+ Primary accounts can make API calls on behalf of their subaccounts.
44
+ ```ruby
45
+ # First, instantiate the Mailgun Client with your API key
46
+ mg_client = Mailgun::Client.new 'your-api-key'
47
+ mg_client.set_subaccount('SUBACCOUNT_ID')
48
+
49
+ # Define your message parameters
50
+ message_params = { from: 'bob@SUBACCOUNT_DOMAIN',
51
+ to: 'sally@example.com',
52
+ subject: 'The Ruby SDK is awesome!',
53
+ text: 'It is really easy to send a message!'
54
+ }
55
+
56
+ # Send your message through the client
57
+ # Note: This will not actually hit the API, and will return a generic OK response.
58
+ mg_client.send_message('SUBACCOUNT_DOMAIN', message_params)
59
+
60
+ # Reset subaccount for primary usage
61
+ mg_client.reset_subaccount
62
+ ```
63
+
64
+
65
+ More Documentation
66
+ ------------------
67
+ See the official [Mailgun Docs](https://documentation.mailgun.com/en/latest/subaccounts.html#subaccounts)
68
+ for more information.
data/docs/Suppressions.md CHANGED
@@ -38,6 +38,16 @@ supp_client.list_complaints
38
38
 
39
39
  ----
40
40
 
41
+ To get the next or previous suppressions page:
42
+
43
+ ```ruby
44
+ supp_client.list_bounces # returns first *limit* records + next, previous pages urls
45
+ supp_client.next # returns next *limit* records
46
+ supp_client.prev # returns previous *limit* records
47
+ ```
48
+
49
+ ----
50
+
41
51
  To batch-add a set of bounces:
42
52
 
43
53
  ```ruby
data/docs/Webhooks.md CHANGED
File without changes
@@ -0,0 +1,34 @@
1
+ Mailgun - Email Validation
2
+ ====================
3
+
4
+ This is the Mailgun Ruby *Email Validation* 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 - Email Validation
10
+ -----------------------
11
+
12
+ ```ruby
13
+ # First, instantiate the Mailgun Address. It pulls api key for Client from Mailgun.api_key variable.
14
+ email_validator = Mailgun::Address.new
15
+
16
+ # Given an arbitrary address, validates address based off defined checks.
17
+ # Response Example:
18
+ # {
19
+ # "address": "existingemail@realdomain.com",
20
+ # "is_disposable_address": false,
21
+ # "is_role_address": false,
22
+ # "reason": [],
23
+ # "result": "deliverable",
24
+ # "risk": "low"
25
+ # }
26
+ email_validator.validate('email@example.com')
27
+
28
+
29
+ ```
30
+
31
+ More Documentation
32
+ ------------------
33
+ See the official [Mailgun Email Validation Docs](https://documentation.mailgun.com/en/latest/api-email-validation.html)
34
+ for more information
@@ -0,0 +1,11 @@
1
+ Overview
2
+ ========
3
+
4
+ Railgun is a Rails add-on that allows ActionMailer to send via the Mailgun API.
5
+
6
+ See [railgun-sample](https://github.com/pirogoeth/railgun-sample/) for examples of integrating Railgun with your Rails app.
7
+
8
+
9
+ ## Table of Contents
10
+
11
+ - [Parameters](/docs/railgun/Parameters.md)
@@ -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
@@ -9,18 +9,26 @@ module Mailgun
9
9
  #
10
10
  # See the Github documentation for full examples.
11
11
  class Client
12
+ SUBACCOUNT_HEADER = 'X-Mailgun-On-Behalf-Of'.freeze
12
13
 
13
14
  def initialize(api_key = Mailgun.api_key,
14
- api_host = 'api.mailgun.net',
15
- api_version = 'v3',
15
+ api_host = Mailgun.api_host || 'api.mailgun.net',
16
+ api_version = Mailgun.api_version || 'v3',
16
17
  ssl = true,
17
- test_mode = false)
18
+ test_mode = false,
19
+ timeout = nil,
20
+ proxy_url = Mailgun.proxy_url)
21
+
22
+ rest_client_params = {
23
+ user: 'api',
24
+ password: api_key,
25
+ user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}"
26
+ }
27
+ rest_client_params[:timeout] = timeout if timeout
18
28
 
19
29
  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}")
30
+ RestClient.proxy = proxy_url
31
+ @http_client = RestClient::Resource.new(endpoint, rest_client_params)
24
32
  @test_mode = test_mode
25
33
  end
26
34
 
@@ -38,6 +46,21 @@ module Mailgun
38
46
  @test_mode = false
39
47
  end
40
48
 
49
+ # Change API key
50
+ def set_api_key(api_key)
51
+ @http_client.options[:password] = api_key
52
+ end
53
+
54
+ # Add subaccount id to headers
55
+ def set_subaccount(subaccount_id)
56
+ @http_client.options[:headers] = { SUBACCOUNT_HEADER => subaccount_id }
57
+ end
58
+
59
+ # Reset subaccount for primary usage
60
+ def reset_subaccount
61
+ @http_client.options[:headers].delete(SUBACCOUNT_HEADER)
62
+ end
63
+
41
64
  # Client is in test mode?
42
65
  #
43
66
  # @return [Boolean] Is the client set in test mode?
@@ -59,11 +82,13 @@ module Mailgun
59
82
  # containing required parameters for the requested resource.
60
83
  # @return [Mailgun::Response] A Mailgun::Response object.
61
84
  def send_message(working_domain, data)
85
+ perform_data_validation(working_domain, data)
86
+
62
87
  if test_mode? then
63
88
  Mailgun::Client.deliveries << data
64
89
  return Response.from_hash(
65
90
  {
66
- :body => '{"id": "test-mode-mail@localhost", "message": "Queued. Thank you."}',
91
+ :body => "{\"id\": \"test-mode-mail-#{SecureRandom.uuid}@localhost\", \"message\": \"Queued. Thank you.\"}",
67
92
  :code => 200,
68
93
  }
69
94
  )
@@ -191,9 +216,30 @@ module Mailgun
191
216
  #
192
217
  # @param [StandardException] e upstream exception object
193
218
  def communication_error(e)
194
- return CommunicationError.new(e.message, e.response) if e.respond_to? :response
219
+ if e.respond_to?(:response) && e.response
220
+ return case e.response.code
221
+ when Unauthorized::CODE
222
+ Unauthorized.new(e.message, e.response)
223
+ when BadRequest::CODE
224
+ BadRequest.new(e.message, e.response)
225
+ else
226
+ CommunicationError.new(e.message, e.response)
227
+ end
228
+ end
195
229
  CommunicationError.new(e.message)
196
230
  end
197
231
 
232
+ def perform_data_validation(working_domain, data)
233
+ message = data.respond_to?(:message) ? data.message : data
234
+ fail ParameterError.new('Missing working domain', working_domain) unless working_domain
235
+ fail ParameterError.new(
236
+ 'Missing `to` recipient, message should contain at least 1 recipient',
237
+ working_domain
238
+ ) if message.fetch('to', []).empty? && message.fetch(:to, []).empty?
239
+ fail ParameterError.new(
240
+ 'Missing a `from` sender, message should contain at least 1 `from` sender',
241
+ working_domain
242
+ ) if message.fetch('from', []).empty? && message.fetch(:from, []).empty?
243
+ end
198
244
  end
199
245
  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)