wj-mailgun-ruby 1.1.7

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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rubocop.yml +8 -0
  4. data/.rubocop_todo.yml +22 -0
  5. data/.ruby-env.yml.example +12 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +24 -0
  8. data/Gemfile +6 -0
  9. data/LICENSE +191 -0
  10. data/README.md +241 -0
  11. data/Rakefile +35 -0
  12. data/docs/Domains.md +54 -0
  13. data/docs/Events.md +46 -0
  14. data/docs/MessageBuilder.md +105 -0
  15. data/docs/Messages.md +107 -0
  16. data/docs/OptInHandler.md +103 -0
  17. data/docs/Snippets.md +526 -0
  18. data/docs/Suppressions.md +82 -0
  19. data/docs/Webhooks.md +40 -0
  20. data/lib/mailgun-ruby.rb +2 -0
  21. data/lib/mailgun.rb +39 -0
  22. data/lib/mailgun/address.rb +45 -0
  23. data/lib/mailgun/chains.rb +16 -0
  24. data/lib/mailgun/client.rb +199 -0
  25. data/lib/mailgun/domains/domains.rb +84 -0
  26. data/lib/mailgun/events/events.rb +120 -0
  27. data/lib/mailgun/exceptions/exceptions.rb +65 -0
  28. data/lib/mailgun/lists/opt_in_handler.rb +58 -0
  29. data/lib/mailgun/messages/batch_message.rb +125 -0
  30. data/lib/mailgun/messages/message_builder.rb +413 -0
  31. data/lib/mailgun/response.rb +62 -0
  32. data/lib/mailgun/suppressions.rb +270 -0
  33. data/lib/mailgun/version.rb +4 -0
  34. data/lib/mailgun/webhooks/webhooks.rb +101 -0
  35. data/lib/railgun.rb +8 -0
  36. data/lib/railgun/attachment.rb +56 -0
  37. data/lib/railgun/errors.rb +27 -0
  38. data/lib/railgun/mailer.rb +161 -0
  39. data/lib/railgun/message.rb +17 -0
  40. data/lib/railgun/railtie.rb +9 -0
  41. data/mailgun.gemspec +37 -0
  42. data/spec/integration/bounces_spec.rb +44 -0
  43. data/spec/integration/campaign_spec.rb +60 -0
  44. data/spec/integration/complaints_spec.rb +38 -0
  45. data/spec/integration/domains_spec.rb +39 -0
  46. data/spec/integration/email_validation_spec.rb +57 -0
  47. data/spec/integration/events_spec.rb +28 -0
  48. data/spec/integration/list_members_spec.rb +63 -0
  49. data/spec/integration/list_spec.rb +58 -0
  50. data/spec/integration/mailgun_spec.rb +121 -0
  51. data/spec/integration/messages/sample_data/mime.txt +38 -0
  52. data/spec/integration/routes_spec.rb +74 -0
  53. data/spec/integration/stats_spec.rb +15 -0
  54. data/spec/integration/suppressions_spec.rb +126 -0
  55. data/spec/integration/unsubscribes_spec.rb +42 -0
  56. data/spec/integration/webhook_spec.rb +54 -0
  57. data/spec/spec_helper.rb +45 -0
  58. data/spec/unit/connection/test_client.rb +99 -0
  59. data/spec/unit/events/events_spec.rb +50 -0
  60. data/spec/unit/lists/opt_in_handler_spec.rb +24 -0
  61. data/spec/unit/mailgun_spec.rb +127 -0
  62. data/spec/unit/messages/batch_message_spec.rb +131 -0
  63. data/spec/unit/messages/message_builder_spec.rb +584 -0
  64. data/spec/unit/messages/sample_data/mailgun_icon.png +0 -0
  65. data/spec/unit/messages/sample_data/mime.txt +38 -0
  66. data/spec/unit/messages/sample_data/rackspace_logo.jpg +0 -0
  67. data/vcr_cassettes/bounces.yml +175 -0
  68. data/vcr_cassettes/complaints.yml +175 -0
  69. data/vcr_cassettes/domains.todo.yml +42 -0
  70. data/vcr_cassettes/domains.yml +360 -0
  71. data/vcr_cassettes/email_validation.yml +167 -0
  72. data/vcr_cassettes/events.yml +108 -0
  73. data/vcr_cassettes/exceptions.yml +45 -0
  74. data/vcr_cassettes/list_members.yml +320 -0
  75. data/vcr_cassettes/mailing_list.todo.yml +43 -0
  76. data/vcr_cassettes/mailing_list.yml +390 -0
  77. data/vcr_cassettes/routes.yml +359 -0
  78. data/vcr_cassettes/send_message.yml +107 -0
  79. data/vcr_cassettes/stats.yml +44 -0
  80. data/vcr_cassettes/suppressions.yml +676 -0
  81. data/vcr_cassettes/unsubscribes.yml +191 -0
  82. data/vcr_cassettes/webhooks.yml +276 -0
  83. metadata +263 -0
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "stats" }
5
+
6
+ describe 'For the Stats endpoint', vcr: vcr_opts do
7
+ before(:all) do
8
+ @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
9
+ @domain = TESTDOMAIN
10
+ end
11
+
12
+ it 'get some stats.' do
13
+ @mg_obj.get("#{@domain}/stats", {:limit => 50, :skip => 10, :event => 'sent'})
14
+ end
15
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ require 'mailgun'
4
+ require 'mailgun/suppressions'
5
+
6
+ vcr_opts = { :cassette_name => 'suppressions' }
7
+
8
+ describe 'For the suppressions handling class', order: :defined, vcr: vcr_opts do
9
+
10
+ before(:all) do
11
+ @mg_obj = Mailgun::Client.new(APIKEY)
12
+ @suppress = Mailgun::Suppressions.new(@mg_obj, TESTDOMAIN)
13
+
14
+ @addresses = ['test1@example.com', 'test2@example.org', 'test3@example.net', 'test4@example.info']
15
+ end
16
+
17
+ it 'can batch-add bounces' do
18
+ bounces = []
19
+ @addresses.each do |addr|
20
+ bounces.push({
21
+ :address => addr,
22
+ :code => 500,
23
+ :error => 'integration testing',
24
+ })
25
+ end
26
+
27
+ response, nested = @suppress.create_bounces bounces
28
+ response.to_h!
29
+
30
+ expect(response.code).to eq(200)
31
+ expect(response.body['message']).to eq('4 addresses have been added to the bounces table')
32
+ expect(nested.length).to eq(0)
33
+ end
34
+
35
+ it 'raises ParameterError if no bounce[:address] is present' do
36
+ bounces = []
37
+ bounces.push({
38
+ :code => 500,
39
+ :error => 'integration testing',
40
+ })
41
+
42
+ expect { @suppress.create_bounces bounces }.to raise_error(Mailgun::ParameterError)
43
+ end
44
+
45
+ it 'removes a single bounce address' do
46
+ @addresses.each do |addr|
47
+ response = @suppress.delete_bounce addr
48
+ response.to_h!
49
+
50
+ expect(response.code).to eq(200)
51
+ expect(response.body['message']).to eq('Bounced address has been removed')
52
+ end
53
+ end
54
+
55
+ it 'can batch-add unsubscribes' do
56
+ unsubscribes = []
57
+ @addresses.each do |addr|
58
+ unsubscribes.push({
59
+ :address => addr,
60
+ :tag => 'integration',
61
+ })
62
+ end
63
+
64
+ response, nested = @suppress.create_unsubscribes unsubscribes
65
+ response.to_h!
66
+
67
+ expect(response.code).to eq(200)
68
+ expect(response.body['message']).to eq('4 addresses have been added to the unsubscribes table')
69
+ expect(nested.length).to eq(0)
70
+ end
71
+
72
+ it 'raises ParameterError if no unsubscribe[:address] is present' do
73
+ unsubscribes = []
74
+ unsubscribes.push({
75
+ :tag => 'integration',
76
+ })
77
+
78
+ expect { @suppress.create_unsubscribes unsubscribes }.to raise_error(Mailgun::ParameterError)
79
+ end
80
+
81
+ it 'removes a single unsubscribe address' do
82
+ @addresses.each do |addr|
83
+ response = @suppress.delete_unsubscribe addr
84
+ response.to_h!
85
+
86
+ expect(response.code).to eq(200)
87
+ expect(response.body['message']).to eq('Unsubscribe event has been removed')
88
+ end
89
+ end
90
+
91
+ it 'can batch-add complaints' do
92
+ complaints = []
93
+ @addresses.each do |addr|
94
+ complaints.push :address => addr
95
+ end
96
+
97
+ response, nested = @suppress.create_complaints complaints
98
+ response.to_h!
99
+
100
+ expect(response.code).to eq(200)
101
+ expect(response.body['message']).to eq('4 complaint addresses have been added to the complaints table')
102
+ expect(nested.length).to eq(0)
103
+ end
104
+
105
+ it 'raises ParameterError if no complaint[:address] is present' do
106
+ complaints = []
107
+ complaints.push({
108
+ :tag => 'integration',
109
+ })
110
+
111
+ expect { @suppress.create_complaints complaints }.to raise_error(Mailgun::ParameterError)
112
+ end
113
+
114
+ it 'removes a single complaint address' do
115
+ @addresses.each do |addr|
116
+ response = @suppress.delete_complaint addr
117
+ response.to_h!
118
+
119
+ expect(response.code).to eq(200)
120
+ expect(response.body['message']).to eq('Spam complaint has been removed')
121
+ end
122
+ end
123
+
124
+ # TODO: Add tests for pagination support.
125
+ end
126
+
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "unsubscribes" }
5
+
6
+ describe 'For the Unsubscribes endpoint', order: :defined, vcr: vcr_opts do
7
+ before(:all) do
8
+ @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
9
+ @domain = TESTDOMAIN
10
+ @email = "integration-test-email@#{TESTDOMAIN}"
11
+ end
12
+
13
+ it 'adds an unsubscriber' do
14
+ result = @mg_obj.post "#{@domain}/unsubscribes", address: @email, tag: '*'
15
+
16
+ result.to_h!
17
+ expect(result.body["message"]).to eq("Address has been added to the unsubscribes table")
18
+ expect(result.body["address"]).to eq(@email)
19
+ end
20
+
21
+ it 'get an unsubscribee.' do
22
+ result = @mg_obj.get "#{@domain}/unsubscribes/#{@email}"
23
+
24
+ result.to_h!
25
+ expect(result.body["address"]).to eq(@email)
26
+ end
27
+
28
+ it 'gets a list of unsubscribes.' do
29
+ result = @mg_obj.get "#{@domain}/unsubscribes"
30
+
31
+ result.to_h!
32
+ expect(result.body["items"].length).to be > 0
33
+ end
34
+
35
+ it 'removes an unsubscribee' do
36
+ result = @mg_obj.delete "#{@domain}/unsubscribes/#{@email}"
37
+
38
+ result.to_h!
39
+ expect(result.body['address']).to eq(@email)
40
+ expect(result.body["message"]).to eq("Unsubscribe event has been removed")
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "webhooks" }
5
+
6
+ describe 'For the webhooks endpoint', order: :defined, vcr: vcr_opts do
7
+ before(:all) do
8
+ @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
9
+ @domain = TESTDOMAIN
10
+ @testhook = 'bounce'
11
+ @testhookup = 'bounceup'
12
+ end
13
+
14
+ it 'creates a webhook' do
15
+ result = @mg_obj.post("domains/#{@domain}/webhooks", { id: 'bounce',
16
+ url: "http://example.com/mailgun/events/#{@testhook}" } )
17
+
18
+ result.to_h!
19
+ expect(result.body["message"]).to eq("Webhook has been created")
20
+ expect(result.body["webhook"]["url"]).to eq("http://example.com/mailgun/events/#{@testhook}")
21
+ end
22
+
23
+ it 'gets a webhook.' do
24
+ result = @mg_obj.get("domains/#{@domain}/webhooks/#{@testhook}")
25
+
26
+ result.to_h!
27
+ expect(result.body["webhook"]["url"]).to eq("http://example.com/mailgun/events/#{@testhook}")
28
+ end
29
+
30
+ it 'gets a list of all webhooks.' do
31
+ result = @mg_obj.get("domains/#{@domain}/webhooks")
32
+
33
+ result.to_h!
34
+ expect(result.body["webhooks"]["bounce"]["url"]).to eq("http://example.com/mailgun/events/#{@testhook}")
35
+ end
36
+
37
+ it 'updates a webhook.' do
38
+ result = @mg_obj.put("domains/#{@domain}/webhooks/bounce", {:id => 'bounce',
39
+ :url => "http://example.com/mailgun/events/#{@testhookup}"})
40
+
41
+ result.to_h!
42
+ expect(result.body["message"]).to eq("Webhook has been updated")
43
+ expect(result.body["webhook"]["url"]).to eq("http://example.com/mailgun/events/#{@testhookup}")
44
+ end
45
+
46
+ it 'removes a webhook' do
47
+ result = @mg_obj.delete("domains/#{@domain}/webhooks/bounce")
48
+
49
+ result.to_h!
50
+ expect(result.body['message']).to eq("Webhook has been deleted")
51
+ expect(result.body['webhook']['url']).to eq("http://example.com/mailgun/events/#{@testhookup}")
52
+ end
53
+
54
+ end
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'bundler/setup'
4
+ Bundler.setup(:development)
5
+
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ add_filter "/spec/"
9
+ end
10
+
11
+ require 'mailgun'
12
+
13
+ require 'vcr'
14
+ require 'webmock/rspec'
15
+
16
+ #WebMock.disable_net_connect!(allow_localhost: true)
17
+ require_relative 'unit/connection/test_client'
18
+
19
+ RSpec.configure do |c|
20
+ c.raise_errors_for_deprecations!
21
+ end
22
+
23
+ APIHOST = "api.mailgun.net"
24
+ APIVERSION = "v3"
25
+ SSL = true
26
+
27
+ # For integration tests modify .ruby-env.yml
28
+ # use .ruby-env.yml.example for an example
29
+ # alternatively
30
+ # set environment variables as named in .ruby-env.yml.example
31
+ envfile = File.join(File.dirname(__FILE__), '..','.ruby-env.yml')
32
+ envs = File.exist?(envfile) ? YAML.load_file(envfile) : ENV
33
+ APIKEY = envs['MAILGUN_APIKEY']
34
+ PUB_APIKEY = envs['MAILGUN_PUB_APIKEY']
35
+ TESTDOMAIN = envs['MAILGUN_TESTDOMAIN']
36
+
37
+ VCR.configure do |c|
38
+ c.cassette_library_dir = 'vcr_cassettes'
39
+ c.hook_into :webmock
40
+ c.configure_rspec_metadata!
41
+ c.default_cassette_options = { record: :new_episodes }
42
+ c.filter_sensitive_data('<APIKEY>') { APIKEY }
43
+ c.filter_sensitive_data('DOMAIN.TEST') { TESTDOMAIN }
44
+ c.filter_sensitive_data('<PUBKEY>') { PUB_APIKEY }
45
+ end
@@ -0,0 +1,99 @@
1
+ require 'time'
2
+ require 'json'
3
+
4
+ module Mailgun
5
+ class UnitClient < Mailgun::Client
6
+
7
+ attr_reader :options, :block, :body, :code, :response
8
+
9
+ def initialize(endpoint, &block)
10
+ @block = block
11
+ @endpoint = endpoint
12
+ @body = nil
13
+ @code = nil
14
+ end
15
+
16
+ def [](endpoint, &new_block)
17
+ case
18
+ when block_given? then self.class.new(endpoint, &new_block)
19
+ when block then self.class.new(endpoint, &block)
20
+ else
21
+ self.class.new(endpoint)
22
+ end
23
+ end
24
+
25
+ def send_message(working_domain, data)
26
+ case data
27
+ when Hash
28
+ if data.has_key?(:message)
29
+ if data[:message].is_a?(String)
30
+ data[:message] = convert_string_to_file(data[:message])
31
+ end
32
+ post("#{working_domain}/messages.mime", data)
33
+ else
34
+ post("#{working_domain}/messages", data)
35
+ end
36
+ when MessageBuilder
37
+ post("#{working_domain}/messages", data.message)
38
+ else
39
+ raise ParameterError.new("Unknown data type for data parameter.", data)
40
+ end
41
+ end
42
+
43
+ def post(path, data)
44
+ begin
45
+ Mailgun::Response.new(response_generator(@endpoint))
46
+ rescue => e
47
+ p e
48
+ raise CommunicationError.new(e), e.response
49
+ end
50
+ end
51
+
52
+ def get(path, query_string = nil)
53
+ begin
54
+ Mailgun::Response.new(response_generator(@endpoint))
55
+ rescue => e
56
+ raise CommunicationError.new(e), e.response
57
+ end
58
+ end
59
+
60
+ def put(path, data)
61
+ begin
62
+ Mailgun::Response.new(response_generator(@endpoint))
63
+ rescue => e
64
+ raise CommunicationError.new(e), e.response
65
+ end
66
+ end
67
+
68
+ def delete(path)
69
+ begin
70
+ Mailgun::Response.new(response_generator(@endpoint))
71
+ rescue => e
72
+ raise CommunicationError.new(e), e.response
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def response_generator(resource_endpoint)
79
+ if resource_endpoint == "messages"
80
+ t = Time.now
81
+ id = "<#{t.to_i}.#{rand(99999999)}.5817@example.com>"
82
+ return OpenStruct.new({ "body" => JSON.generate({"message" => "Queued. Thank you.", "id" => id}) })
83
+ end
84
+ if resource_endpoint == "bounces"
85
+ return OpenStruct.new({ "body" => JSON.generate({"total_count" => 1, "items" => {"created_at" => "Fri, 21 Oct 2011 11:02:55 GMT", "code" => 550, "address" => "baz@example.com", "error" => "Message was not accepted -- invalid mailbox. Local mailbox baz@example.com is unavailable: user not found"}}) })
86
+ end
87
+ if resource_endpoint == "lists"
88
+ return OpenStruct.new({ "body" => JSON.generate({"member" => {"vars" => {"age" => 26}, "name" => "Foo Bar", "subscribed" => false, "address" => "bar@example.com"}, "message" => "Mailing list member has been updated"}) })
89
+ end
90
+ if resource_endpoint == "campaigns"
91
+ return OpenStruct.new({ "body" => JSON.generate({"message" => "Campaign has been deleted", "id" => "ABC123"}) })
92
+ end
93
+ if resource_endpoint == "events"
94
+ return OpenStruct.new({ "body" => JSON.generate({"items" => [], "paging" => {"next"=> "https://api.mailgun.net/v3/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIFsiZiJdLCBudWxsLCB7ImFjY291bnQuaWQiOiAiNGU4MjMwZjYxNDc2ZDg2NzEzMDBjNDc2IiwgImRvbWFpbi5uYW1lIjogInRoaXNpc2F0ZXN0ZG9tYWluZm9ybWFpbGd1bi5jb20iLCAic2V2ZXJpdHkiOiAiTk9UIGludGVybmFsIn0sIDEwMCwgbnVsbF0=", "previous"=> "https://api.mailgun.net/v2/thisisatestdomainformailgun.com/events/W3siYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDVUMDA6NDU6NTEuNzQwOTgzKzAwOjAwIn0sIHsiYiI6ICIyMDE0LTA1LTA3VDAwOjQ1OjUxLjc0MDg5MiswMDowMCIsICJlIjogIjIwMTQtMDUtMDdUMDA6NDU6NTEuNzQxODkyKzAwOjAwIn0sIFsicCIsICJmIl0sIG51bGwsIHsiYWNjb3VudC5pZCI6ICI0ZTgyMzBmNjE0NzZkODY3MTMwMGM0NzYiLCAiZG9tYWluLm5hbWUiOiAidGhpc2lzYXRlc3Rkb21haW5mb3JtYWlsZ3VuLmNvbSIsICJzZXZlcml0eSI6ICJOT1QgaW50ZXJuYWwifSwgMTAwLCBudWxsXQ=="}}) })
95
+ end
96
+ end
97
+ end
98
+
99
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The method get' do
4
+ it 'should return a proper hash of log data.' do
5
+ @mg_obj = Mailgun::UnitClient.new('events')
6
+ events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
7
+ result = events.get()
8
+
9
+ expect(result.body).to include("items")
10
+ expect(result.body).to include("paging")
11
+ end
12
+ end
13
+
14
+
15
+ describe 'The method next' do
16
+ it 'should return the next series of data.' do
17
+ @mg_obj = Mailgun::UnitClient.new('events')
18
+ events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
19
+ result = events.next()
20
+
21
+ expect(result.body).to include("items")
22
+ expect(result.body).to include("paging")
23
+ end
24
+ end
25
+
26
+ describe 'The method previous' do
27
+ it 'should return the previous series of data.' do
28
+ @mg_obj = Mailgun::UnitClient.new('events')
29
+ events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
30
+ result = events.previous()
31
+
32
+ expect(result.body).to include("items")
33
+ expect(result.body).to include("paging")
34
+ end
35
+ end
36
+
37
+ describe 'The method each' do
38
+ it 'should iterate over all event items.' do
39
+ @mg_obj = Mailgun::UnitClient.new('events')
40
+ events = Mailgun::Events.new(@mg_obj, "samples.mailgun.org")
41
+ # Events from the UnitClient are actually empty.
42
+ count = 0
43
+ events.each do |e|
44
+ count = count + 1
45
+ end
46
+
47
+ # Better than nothing..
48
+ expect(count).to eq(0)
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The method generate_hash' do
4
+ before(:each) do
5
+ @mailing_list = "mylist@example.com"
6
+ @secret_app_id = "mysupersecretpassword"
7
+ @recipient_address = "bob@example.com"
8
+ @precalculated_hash = "eyJoIjoiMmY3ZmY1MzFlOGJmMjA0OWNhMTI3ZmU4ZTQyNjZkOTljYzhkMTdk%0AMiIsInAiOiJleUpzSWpvaWJYbHNhWE4wUUdWNFlXMXdiR1V1WTI5dElpd2lj%0AaUk2SW1KdllrQmxlR0Z0Y0d4bExtTnZcbmJTSjlcbiJ9%0A"
9
+ end
10
+
11
+ it 'generates a web safe hash for the recipient wishing to subscribe' do
12
+ my_hash = Mailgun::OptInHandler.generate_hash(@mailing_list, @secret_app_id, @recipient_address)
13
+
14
+ expect(my_hash).to eq(@precalculated_hash)
15
+ end
16
+
17
+ it 'generates a web safe hash for the recipient wishing to subscribe' do
18
+ validate_result = Mailgun::OptInHandler.validate_hash(@secret_app_id, @precalculated_hash)
19
+
20
+ expect(validate_result.length).to eq(2)
21
+ expect(validate_result['recipient_address']).to eq(@recipient_address)
22
+ expect(validate_result['mailing_list']).to eq(@mailing_list)
23
+ end
24
+ end