mailgun-ruby 1.0.3 → 1.1.0

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 (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