mailgun-ruby 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +8 -0
  4. data/.rubocop_todo.yml +22 -0
  5. data/.ruby-env.yml.example +12 -0
  6. data/.travis.yml +6 -12
  7. data/Domains.md +36 -0
  8. data/MessageBuilder.md +14 -14
  9. data/Messages.md +44 -30
  10. data/OptInHandler.md +34 -34
  11. data/README.md +74 -24
  12. data/Rakefile +22 -20
  13. data/Snippets.md +26 -26
  14. data/Webhooks.md +40 -0
  15. data/lib/mailgun.rb +26 -228
  16. data/lib/mailgun/chains.rb +16 -0
  17. data/lib/mailgun/client.rb +143 -0
  18. data/lib/mailgun/domains/domains.rb +84 -0
  19. data/lib/mailgun/events/events.rb +53 -35
  20. data/lib/mailgun/exceptions/exceptions.rb +43 -10
  21. data/lib/mailgun/lists/opt_in_handler.rb +18 -19
  22. data/lib/mailgun/messages/batch_message.rb +31 -48
  23. data/lib/mailgun/messages/message_builder.rb +160 -144
  24. data/lib/mailgun/response.rb +55 -0
  25. data/lib/mailgun/version.rb +2 -3
  26. data/lib/mailgun/webhooks/webhooks.rb +101 -0
  27. data/mailgun.gemspec +16 -10
  28. data/spec/integration/bounces_spec.rb +44 -0
  29. data/spec/integration/campaign_spec.rb +60 -0
  30. data/spec/integration/complaints_spec.rb +38 -0
  31. data/spec/integration/domains_spec.rb +39 -0
  32. data/spec/integration/email_validation_spec.rb +29 -0
  33. data/spec/integration/events_spec.rb +20 -0
  34. data/spec/integration/list_members_spec.rb +63 -0
  35. data/spec/integration/list_spec.rb +58 -0
  36. data/spec/integration/mailgun_spec.rb +26 -550
  37. data/spec/integration/routes_spec.rb +74 -0
  38. data/spec/integration/stats_spec.rb +15 -0
  39. data/spec/integration/unsubscribes_spec.rb +42 -0
  40. data/spec/integration/webhook_spec.rb +54 -0
  41. data/spec/spec_helper.rb +37 -7
  42. data/spec/unit/connection/test_client.rb +15 -95
  43. data/spec/unit/events/events_spec.rb +9 -6
  44. data/spec/unit/lists/opt_in_handler_spec.rb +6 -4
  45. data/spec/unit/mailgun_spec.rb +25 -19
  46. data/spec/unit/messages/batch_message_spec.rb +47 -38
  47. data/spec/unit/messages/message_builder_spec.rb +282 -111
  48. data/vcr_cassettes/bounces.yml +175 -0
  49. data/vcr_cassettes/complaints.yml +175 -0
  50. data/vcr_cassettes/domains.todo.yml +42 -0
  51. data/vcr_cassettes/domains.yml +360 -0
  52. data/vcr_cassettes/email_validation.yml +104 -0
  53. data/vcr_cassettes/events.yml +61 -0
  54. data/vcr_cassettes/list_members.yml +320 -0
  55. data/vcr_cassettes/mailing_list.todo.yml +43 -0
  56. data/vcr_cassettes/mailing_list.yml +390 -0
  57. data/vcr_cassettes/routes.yml +359 -0
  58. data/vcr_cassettes/send_message.yml +107 -0
  59. data/vcr_cassettes/stats.yml +44 -0
  60. data/vcr_cassettes/unsubscribes.yml +191 -0
  61. data/vcr_cassettes/webhooks.yml +276 -0
  62. metadata +114 -10
@@ -0,0 +1,55 @@
1
+ module Mailgun
2
+ # A Mailgun::Response object is instantiated for each response generated
3
+ # by the Client request. The Response object supports deserialization of
4
+ # the JSON result. Or, if you prefer JSON or YAML formatting, call the
5
+ # method for conversion.
6
+ #
7
+ # See the Github documentation for full examples.
8
+ class Response
9
+ # All responses have a payload and a code corresponding to http, though
10
+ # slightly different
11
+ attr_accessor :body, :code
12
+
13
+ def initialize(response)
14
+ @body = response.body
15
+ @code = response.code
16
+ end
17
+
18
+ # Return response as Ruby Hash
19
+ #
20
+ # @return [Hash] A standard Ruby Hash containing the HTTP result.
21
+
22
+ def to_h
23
+ JSON.parse(@body)
24
+ rescue => err
25
+ raise ParseError.new(err), err
26
+ end
27
+
28
+ # Replace @body with Ruby Hash
29
+ #
30
+ # @return [Hash] A standard Ruby Hash containing the HTTP result.
31
+ def to_h!
32
+ @body = JSON.parse(@body)
33
+ rescue => err
34
+ raise ParseError.new(err), err
35
+ end
36
+
37
+ # Return response as Yaml
38
+ #
39
+ # @return [String] A string containing response as YAML
40
+ def to_yaml
41
+ YAML.dump(to_h)
42
+ rescue => err
43
+ raise ParseError.new(err), err
44
+ end
45
+
46
+ # Replace @body with YAML
47
+ #
48
+ # @return [String] A string containing response as YAML
49
+ def to_yaml!
50
+ @body = YAML.dump(to_h)
51
+ rescue => err
52
+ raise ParseError.new(err), err
53
+ end
54
+ end
55
+ end
@@ -1,5 +1,4 @@
1
+ # It's the version. Yeay!
1
2
  module Mailgun
2
-
3
- VERSION = "1.0.3"
4
-
3
+ VERSION = '1.1.0'
5
4
  end
@@ -0,0 +1,101 @@
1
+ module Mailgun
2
+
3
+ # A Mailgun::Webhooks object is a simple CRUD interface to Mailgun Webhooks.
4
+ # Uses Mailgun
5
+ class Webhooks
6
+
7
+ # Public creates a new Mailgun::Webhooks instance.
8
+ # Defaults to Mailgun::Client
9
+ def initialize(client = Mailgun::Client.new)
10
+ @client = client
11
+ end
12
+
13
+ # Public: Get Webhooks
14
+ #
15
+ # domain - a string the domain name to retrieve webhooks for
16
+ # options - a Hash of options
17
+ #
18
+ # Returns a Hash of the list of domains or nil
19
+ def list(domain, options = {})
20
+ res = @client.get("domains/#{domain}/webhooks", options)
21
+ res.to_h['webhooks']
22
+ end
23
+ alias_method :get_webhooks, :list
24
+
25
+ # Public: Get webook information for a specific action
26
+ #
27
+ # domain - a String of Domain name to find a webhook url for
28
+ # action - a String identifying the webhook to get the URL for
29
+ #
30
+ # Returns a String of the url for the identified webhook or an
31
+ # empty String if one is not set
32
+ def info(domain, action)
33
+ res = @client.get("domains/#{domain}/webhooks/#{action}")
34
+ res.to_h['webhook']['url'] || ''
35
+ rescue NoMethodError
36
+ ''
37
+ end
38
+ alias_method :get_webhook_url, :info
39
+
40
+ # Public: Add webhook
41
+ #
42
+ # domain - A String of the domain name (ex. domain.com)
43
+ # action - A String of the action to create a webhook for
44
+ # url - A String of the url of the webhook
45
+ #
46
+ # Returns a Boolean of whether the webhook was created
47
+ def create(domain, action, url = '')
48
+ res = @client.post("domains/#{domain}/webhooks", id: action, url: url)
49
+ res.to_h['webhook'] == url && res.to_h[message] == 'Webhook has been created'
50
+ end
51
+ alias_method :add, :create
52
+ alias_method :add_webhook, :create
53
+
54
+ # Public: Sets all webhooks to the same URL
55
+ #
56
+ # domain - A String of the domain name
57
+ # url - A String of the url to set all webhooks to
58
+ #
59
+ # Returns true or false
60
+ def create_all(domain, url = '')
61
+ %w(bounce click deliver drop open spam unsubscribe).each do |action|
62
+ add_webhook domain, action, url
63
+ end
64
+ true
65
+ rescue
66
+ false
67
+ end
68
+ alias_method :add_all_webhooks, :create_all
69
+
70
+ # Public: Delete a specific webhook
71
+ #
72
+ # domain - The required String of domain name
73
+ # action - The required String of the webhook action to delete
74
+ #
75
+ # Returns a Boolean of the success
76
+ def remove(domain, action)
77
+ fail Mailgun::ParameterError('Domain not provided to remove webhook from') unless domain
78
+ fail Mailgun::ParameterError('Action not provided to identify webhook to remove') unless action
79
+ @client.delete("domains/#{domain}/webhooks/#{action}").to_h['message'] == 'Webhook has been deleted'
80
+ rescue Mailgun::CommunicationError
81
+ false
82
+ end
83
+ alias_method :delete, :remove
84
+ alias_method :delete_webhook, :remove
85
+
86
+ # Public: Delete all webhooks for a domain
87
+ #
88
+ # domain - A required String of the domain to remove all webhooks for
89
+ #
90
+ # Returns a Boolean on the success
91
+ def remove_all(domain)
92
+ fail Mailgun::ParameterError('Domain not provided to remove webhooks from') unless domain
93
+ %w(bounce click deliver drop open spam unsubscribe).each do |action|
94
+ delete_webhook domain, action
95
+ end
96
+ end
97
+ alias_method :delete_all, :remove_all
98
+ alias_method :delete_all_webooks, :remove_all
99
+
100
+ end
101
+ end
@@ -5,28 +5,34 @@ require 'mailgun/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
 
8
- spec.name = "mailgun-ruby"
8
+ spec.name = 'mailgun-ruby'
9
9
  spec.version = Mailgun::VERSION
10
- spec.homepage = "http://www.mailgun.com"
10
+ spec.homepage = 'http://www.mailgun.com'
11
11
  spec.platform = Gem::Platform::RUBY
12
12
  spec.license = 'Apache'
13
13
 
14
14
  spec.summary = "Mailgun's Official Ruby SDK"
15
15
  spec.description = "Mailgun's Official Ruby SDK for interacting with the Mailgun API."
16
16
 
17
- spec.authors = ["Mailgun", "Travis Swientek"]
18
- spec.email = "support@mailgunhq.com"
17
+ spec.authors = ['Mailgun', 'Travis Swientek']
18
+ spec.email = 'support@mailgunhq.com'
19
19
 
20
- spec.files = `git ls-files`.split($/)
20
+ spec.files = `git ls-files -z`.split("\x0")
21
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_development_dependency "bundler", "~> 1.3"
26
- spec.add_development_dependency "rspec", "~> 2.14"
27
- spec.add_development_dependency "rake", "~> 10.1"
25
+ spec.required_ruby_version = '>= 1.9.3'
28
26
 
29
- spec.add_dependency "rest-client", "~> 1.6"
30
- spec.add_dependency "json", "~> 1.8"
27
+ spec.add_development_dependency 'bundler', '~> 1.5'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'webmock', '~> 1.22'
31
+ spec.add_development_dependency 'pry', '~> 0.9'
32
+ spec.add_development_dependency 'vcr', '~> 3.0'
33
+ spec.add_development_dependency 'simplecov', '~> 0.11'
34
+
35
+ spec.add_dependency 'rest-client', '~> 1.6'
36
+ spec.add_dependency 'json', '~> 1.8'
31
37
 
32
38
  end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "bounces" }
5
+
6
+ describe 'For the Bounces 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 'creates a bounce' do
14
+ @result = @mg_obj.post("#{@domain}/bounces",
15
+ {:address => @email,
16
+ :code => 550,
17
+ :error => "Integration Test"})
18
+
19
+ @result.to_h!
20
+ expect(@result.body["message"]).to eq("Address has been added to the bounces table")
21
+ expect(@result.body["address"]).to eq(@email)
22
+ end
23
+
24
+ it 'get a bounce.' do
25
+ result = @mg_obj.get("#{@domain}/bounces/#{@email}")
26
+
27
+ result.to_h!
28
+ expect(result.body["code"]).to eq("550")
29
+ expect(result.body["address"]).to eq(@email)
30
+ expect(result.body["error"]).to eq("Integration Test")
31
+ end
32
+
33
+ it 'gets a list of bounces.' do
34
+ result = @mg_obj.get("#{@domain}/bounces")
35
+
36
+ result.to_h!
37
+ expect(result.body["items"].length).to be > 0
38
+ end
39
+
40
+ it 'deletes a bounce' do
41
+ @mg_obj.delete("#{@domain}/bounces/#{@email}")
42
+ end
43
+
44
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "campaigns" }
5
+
6
+ describe 'For the campaigns endpoint', vcr: vcr_opts do
7
+ before(:all) do
8
+ skip 'pending removal'
9
+ @mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
10
+ @domain = TESTDOMAIN
11
+ @campaign_id = "integration_test_campaign"
12
+ end
13
+
14
+ it 'creates a campaign' do
15
+ result = @mg_obj.post("#{@domain}/campaigns", {:name => 'My Campaign',
16
+ :id => @campaign_id})
17
+
18
+ result.to_h!
19
+ expect(result.body["message"]).to eq("Campaign created")
20
+ expect(result.body["campaign"]["id"]).to eq(@campaign_id)
21
+ expect(result.body["campaign"]["name"]).to eq('My Campaign')
22
+ end
23
+
24
+ it 'get a campaign.' do
25
+ result = @mg_obj.get("#{@domain}/campaigns/#{@campaign_id}")
26
+
27
+ result.to_h!
28
+ expect(result.body["id"]).to eq(@campaign_id)
29
+ expect(result.body["name"]).to eq('My Campaign')
30
+ end
31
+
32
+ it 'gets a list of all campaigns.' do
33
+ result = @mg_obj.get("#{@domain}/campaigns", {:limit => 50})
34
+
35
+ result.to_h!
36
+ expect(result.body["total_count"]).to be > 0
37
+ end
38
+
39
+ it 'update a campaign.' do
40
+ result = @mg_obj.put("#{@domain}/campaigns/#{@campaign_id}", {:name => 'My Updated Campaign',
41
+ :id => @campaign_id})
42
+
43
+ result.to_h!
44
+ expect(result.body["message"]).to eq("Campaign updated")
45
+ expect(result.body["campaign"]["id"]).to eq(@campaign_id)
46
+ expect(result.body["campaign"]["name"]).to eq('My Updated Campaign')
47
+ end
48
+
49
+ it 'get campaign events.' do
50
+ expect{@mg_obj.get("#{@domain}/campaigns/#{@campaign_id}/events", {:groupby => "clicked"})}.not_to raise_error
51
+ end
52
+
53
+ it 'get campaign stats.' do
54
+ expect{@mg_obj.get("#{@domain}/campaigns/#{@campaign_id}/stats", {:groupby => "domain"})}.not_to raise_error
55
+ end
56
+
57
+ it 'removes a campaign' do
58
+ @mg_obj.delete("#{@domain}/campaigns/#{@campaign_id}")
59
+ end
60
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "complaints" }
5
+
6
+ describe 'For the Complaints 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 'creates a complaint' do
14
+ @result = @mg_obj.post("#{@domain}/complaints", {:address => @email})
15
+
16
+ @result.to_h!
17
+ expect(@result.body["message"]).to eq("Address has been added to the complaints table")
18
+ expect(@result.body["address"]).to eq(@email)
19
+ end
20
+
21
+ it 'get a complaint.' do
22
+ result = @mg_obj.get("#{@domain}/complaints/#{@email}")
23
+
24
+ result.to_h!
25
+ expect(result.body["address"]).to eq(@email)
26
+ end
27
+
28
+ it 'gets a list of complaints.' do
29
+ result = @mg_obj.get("#{@domain}/complaints")
30
+
31
+ result.to_h!
32
+ expect(result.body["items"].length).to be > 0
33
+ end
34
+
35
+ it 'removes a complaint' do
36
+ @mg_obj.delete("#{@domain}/complaints/#{@email}")
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "domains" }
5
+
6
+ describe 'For the domains endpoint', vcr: vcr_opts do
7
+ before(:all) do
8
+ @mg_client = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
9
+ @mg_obj = Mailgun::Domains.new(@mg_client)
10
+ @domain = "integration-test.domain.invalid"
11
+ end
12
+
13
+ it 'creates the domain' do
14
+ result = @mg_obj.add_domain(@domain, { smtp_password: 'super_secret', spam_action: 'tag' })
15
+
16
+ expect(result['domain']["name"]).to eq(@domain)
17
+ expect(result['domain']["spam_action"]).to eq("tag")
18
+ expect(result['domain']["smtp_password"]).to eq("super_secret")
19
+ end
20
+
21
+ it 'get the domain.' do
22
+ result = @mg_obj.get(@domain)
23
+
24
+ expect(result).to include("domain")
25
+ expect(result["domain"]["name"]).to eq(@domain)
26
+ end
27
+
28
+ it 'gets a list of domains.' do
29
+ result = @mg_obj.get_domains
30
+
31
+ expect(result.size).to be > 0
32
+ end
33
+
34
+ it 'deletes a domain.' do
35
+ result = @mg_obj.delete(@domain)
36
+
37
+ expect(result).to be_truthy
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "email_validation" }
5
+
6
+ describe 'For the Email Validation endpoint', vcr: vcr_opts do
7
+ before(:all) do
8
+ @mg_obj = Mailgun::Client.new(PUB_APIKEY)
9
+ end
10
+
11
+ it 'validates an address.' do
12
+ result = @mg_obj.get("address/validate",
13
+ {:address => "test@#{TESTDOMAIN}"})
14
+
15
+ result.to_h!
16
+ expect(result.body["is_valid"]).to eq(true)
17
+ expect(result.body["address"]).to eq("test@#{TESTDOMAIN}")
18
+ end
19
+
20
+ it 'parses an address.' do
21
+ result = @mg_obj.get("address/parse",
22
+ {:addresses => "Alice <alice@#{TESTDOMAIN}>,bob@#{TESTDOMAIN},#{TESTDOMAIN}"})
23
+
24
+ result.to_h!
25
+ expect(result.body["parsed"]).to include("Alice <alice@#{TESTDOMAIN}>")
26
+ expect(result.body["parsed"]).to include("bob@#{TESTDOMAIN}")
27
+ expect(result.body["unparseable"]).to include("#{TESTDOMAIN}")
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'mailgun'
3
+
4
+ vcr_opts = { :cassette_name => "events" }
5
+
6
+ describe 'For the Events 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 an event.' do
13
+ result = @mg_obj.get("#{@domain}/events", {:limit => 1})
14
+
15
+ result.to_h!
16
+ expect(result.body["items"].length).to be_within(1).of(1)
17
+ expect(result.body["paging"]).to include("next")
18
+ expect(result.body["paging"]).to include("previous")
19
+ end
20
+ end