mailgun 0.8 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20809378b057a083d20b98dd3dffb1d771d2845e
4
- data.tar.gz: b063e69d0b35dca7f8a934e7a2e2fd3f9f5d57ff
3
+ metadata.gz: f47c74dc32e3f6a7436d43f289f9af79f449156f
4
+ data.tar.gz: 554bef62dd88c32a6de42af428c882e2b4f9c122
5
5
  SHA512:
6
- metadata.gz: a568bf6b8ca38bd594d0f08e336c2d3a93961b32fe216e2d954e80b527675d8f8cbd91de0c8413e540135abed41be64e329e6dfe81911d71ad14196027daeed9
7
- data.tar.gz: b307a01536f51da5b8bbd462ae477105685e95adab6e48f8c6c02dca6438f2affb929e8a0e76da4830dcee00fb33d9cbd4c40bdfad51b4b264bad3ecf128492e
6
+ metadata.gz: 7f0b40b7ecbeda0baea7d9069c10f4516d79b4fcc51e22f2bb98078d64a44883ee095b0b42d8945f0cfdc2a7530ff8f5bebbb3da64397c9156087087429c0c24
7
+ data.tar.gz: 34e235408386e399fe7f19f4ec6f51d52cf1d3487ceca784d89976f315ab74f7bd54b61ec4f1403f5a2928491bfc2ae1825b4c5087b5a8fc7e552e2326ab3e52
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .byebug_history
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3.0
7
+
8
+ before_install:
9
+ - gem install bundler
10
+
11
+ cache: bundler
12
+
13
+ script: bundle exec rspec --color
@@ -20,4 +20,8 @@
20
20
  * new functionality and improvements
21
21
 
22
22
  * Yomi Colledge / [@baphled](http://github.com/baphled)
23
- * For refactoring API configuration and some documentation
23
+ * For refactoring API configuration and some documentation
24
+
25
+ * Gregory Hilkert / [@EpiphanyMachine](http://github.com/EpiphanyMachine) and [@asheeshchoksi](https://github.com/asheeshchoksi)
26
+ * Support for Webhooks API
27
+ * Support for Address API
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Mailgun rubygem
2
2
 
3
+ ![](https://travis-ci.org/HashNuke/mailgun.svg?branch=master)
4
+
3
5
  This gem allows for idiomatic Mailgun usage from within ruby. Mailgun is a kickass email-as-a-service that lets you use email as if it made sense. Check it out at http://mailgun.net
4
6
 
5
7
  Mailgun exposes the following resources:
@@ -16,6 +18,8 @@ Mailgun exposes the following resources:
16
18
  * Unsubscribes
17
19
  * Complaints
18
20
  * Domain management
21
+ * Webhook management
22
+ * Address Validation
19
23
 
20
24
  Patches are welcome (and easy!).
21
25
 
@@ -94,6 +98,9 @@ parameters = {
94
98
  # Add a member to a list
95
99
  @mailgun.list_members.add "devs@your.mailgun.domain", "Q@mi6.co.uk"
96
100
 
101
+ # Add multiple mailing list members to a list (limit 1,000 per call)
102
+ @mailgun.list_members.add_multi "devs@your.mailgun.domain", [{"address": "Alice <alice@example.com>", "vars": {"age": 26}}, {"name": "Bob", "address": "bob@example.com", "vars": {"age": 34}}].to_json, {:upsert => true}
103
+
97
104
  # Update a member on a list
98
105
  @mailgun.list_members.update "devs@your.mailgun.domain", "Q@mi6.co.uk", "Q", {:gender => 'male'}.to_json, :subscribed => 'no')
99
106
 
@@ -181,6 +188,36 @@ Supported route actions are: `:forward`, and `:stop`
181
188
  @mailbox.domains.delete "example.com"
182
189
  ```
183
190
 
191
+ #### Webhooks
192
+ ```ruby
193
+ # List of currently available webhooks
194
+ @mailgun.webhooks.available_ids
195
+
196
+ # Returns a list of webhooks set for the specified domain
197
+ @mailgun.webhooks.list
198
+
199
+ # Returns details about the webhook specified
200
+ @mailgun.webhooks.find(:open)
201
+
202
+ # Creates a new webhook
203
+ # Note: Creating an Open or Click webhook will enable Open or Click tracking
204
+ @mailgun.webhooks.create(:open, "http://bin.example.com/8de4a9c4")
205
+
206
+ # Updates an existing webhook
207
+ @mailgun.webhooks.update(:open, "http://bin.example.com/8de4a9c4")
208
+
209
+ # Deletes an existing webhook
210
+ # Note: Deleting an Open or Click webhook will disable Open or Click tracking
211
+ @mailgun.webhooks.delete(:open)
212
+ ```
213
+
214
+ #### Address Validation
215
+ Requires the `public_api_key` to be set. The Mailgun public key is available in the My Account tab of the Control Panel.
216
+ ```ruby
217
+ # Given an arbitrary address, validates address based off defined checks
218
+ @mailgun.addresses.validate('hello@example.com')
219
+ ```
220
+
184
221
  ## Making Your Changes
185
222
 
186
223
  * Fork the project (Github has really good step-by-step directions)
@@ -208,9 +245,9 @@ Supported route actions are: `:forward`, and `:stop`
208
245
  * Campaign?
209
246
 
210
247
 
211
- ## Maintainer
248
+ ## Maintainers
212
249
 
213
- Akash Manohar / [@HashNuke](http://github.com/HashNuke)
250
+ * Hairihan / [@hairihan](http://github.com/hairihan)
214
251
 
215
252
 
216
253
  ## Authors
@@ -1,4 +1,3 @@
1
- require "rest-client"
2
1
  require "json"
3
2
  require "multimap/lib/multimap"
4
3
  require "multimap/lib/multiset"
@@ -11,16 +10,22 @@ require "mailgun/route"
11
10
  require "mailgun/mailbox"
12
11
  require "mailgun/bounce"
13
12
  require "mailgun/unsubscribe"
13
+ require "mailgun/webhook"
14
14
  require "mailgun/complaint"
15
15
  require "mailgun/log"
16
16
  require "mailgun/list"
17
17
  require "mailgun/list/member"
18
18
  require "mailgun/message"
19
+ require "mailgun/secure"
20
+ require "mailgun/address"
21
+ require "mailgun/client"
19
22
 
20
23
  #require "startup"
21
24
 
22
25
  def Mailgun(options={})
23
26
  options[:api_key] = Mailgun.api_key if Mailgun.api_key
24
27
  options[:domain] = Mailgun.domain if Mailgun.domain
28
+ options[:webhook_url] = Mailgun.webhook_url if Mailgun.webhook_url
29
+ options[:public_api_key] = Mailgun.public_api_key if Mailgun.public_api_key
25
30
  Mailgun::Base.new(options)
26
31
  end
@@ -0,0 +1,20 @@
1
+ module Mailgun
2
+ # https://documentation.mailgun.com/api-email-validation.html#email-validation
3
+ class Address
4
+ # Used internally, called from Mailgun::Base
5
+ def initialize(mailgun)
6
+ @mailgun = mailgun
7
+ end
8
+
9
+ # Given an arbitrary address, validates address based off defined checks
10
+ def validate(email)
11
+ Mailgun.submit :get, address_url('validate'), {:address => email}
12
+ end
13
+
14
+ private
15
+
16
+ def address_url(action)
17
+ "#{@mailgun.public_base_url}/address/#{action}"
18
+ end
19
+ end
20
+ end
@@ -7,13 +7,17 @@ module Mailgun
7
7
  # * API key and version
8
8
  # * Test mode - if enabled, doesn't actually send emails (see http://documentation.mailgun.net/user_manual.html#sending-in-test-mode)
9
9
  # * Domain - domain to use
10
+ # * Webhook URL - default url to use if one is not specified in each request
11
+ # * Public API Key - used for address endpoint
10
12
  def initialize(options)
11
- Mailgun.mailgun_host = options.fetch(:mailgun_host) {"api.mailgun.net"}
12
- Mailgun.protocol = options.fetch(:protocol) { "https" }
13
- Mailgun.api_version = options.fetch(:api_version) { "v2" }
13
+ Mailgun.mailgun_host = options.fetch(:mailgun_host) { "api.mailgun.net" }
14
+ Mailgun.protocol = options.fetch(:protocol) { "https" }
15
+ Mailgun.api_version = options.fetch(:api_version) { "v3" }
14
16
  Mailgun.test_mode = options.fetch(:test_mode) { false }
15
- Mailgun.api_key = options.fetch(:api_key) { raise ArgumentError.new(":api_key is a required argument to initialize Mailgun") if Mailgun.api_key.nil?}
17
+ Mailgun.api_key = options.fetch(:api_key) { raise ArgumentError.new(":api_key is a required argument to initialize Mailgun") if Mailgun.api_key.nil? }
16
18
  Mailgun.domain = options.fetch(:domain) { nil }
19
+ Mailgun.webhook_url = options.fetch(:webhook_url) { nil }
20
+ Mailgun.public_api_key = options.fetch(:public_api_key) { nil }
17
21
  end
18
22
 
19
23
  # Returns the base url used in all Mailgun API calls
@@ -21,6 +25,10 @@ module Mailgun
21
25
  "#{Mailgun.protocol}://api:#{Mailgun.api_key}@#{Mailgun.mailgun_host}/#{Mailgun.api_version}"
22
26
  end
23
27
 
28
+ def public_base_url
29
+ "#{Mailgun.protocol}://api:#{Mailgun.public_api_key}@#{Mailgun.mailgun_host}/#{Mailgun.api_version}"
30
+ end
31
+
24
32
  # Returns an instance of Mailgun::Mailbox configured for the current API user
25
33
  def mailboxes(domain = Mailgun.domain)
26
34
  Mailgun::Mailbox.new(self, domain)
@@ -46,6 +54,17 @@ module Mailgun
46
54
  Mailgun::Unsubscribe.new(self, domain)
47
55
  end
48
56
 
57
+ def webhooks(domain = Mailgun.domain, webhook_url = Mailgun.webhook_url)
58
+ Mailgun::Webhook.new(self, domain, webhook_url)
59
+ end
60
+
61
+ def addresses(domain = Mailgun.domain)
62
+ if Mailgun.public_api_key.nil?
63
+ raise ArgumentError.new(":public_api_key is a required argument to validate addresses")
64
+ end
65
+ Mailgun::Address.new(self)
66
+ end
67
+
49
68
  def complaints(domain = Mailgun.domain)
50
69
  Mailgun::Complaint.new(self, domain)
51
70
  end
@@ -61,25 +80,33 @@ module Mailgun
61
80
  def list_members(address)
62
81
  Mailgun::MailingList::Member.new(self, address)
63
82
  end
83
+
84
+ def secure
85
+ Mailgun::Secure.new(self)
86
+ end
64
87
  end
65
88
 
66
89
 
67
90
  # Submits the API call to the Mailgun server
68
91
  def self.submit(method, url, parameters={})
69
92
  begin
70
- parameters = {:params => parameters} if method == :get
71
- return JSON(RestClient.send(method, url, parameters))
93
+ JSON.parse(Client.new(url).send(method, parameters))
72
94
  rescue => e
73
- error_message = nil
74
- if e.respond_to? :http_body
75
- begin
76
- error_message = JSON(e.http_body)["message"]
77
- rescue
78
- raise e
79
- end
80
- raise Mailgun::Error.new(error_message)
95
+ error_code = e.http_code
96
+ error_message = begin
97
+ JSON(e.http_body)["message"]
98
+ rescue JSON::ParserError
99
+ ''
100
+ end
101
+ error = Mailgun::Error.new(
102
+ :code => error_code || nil,
103
+ :message => error_message || nil
104
+ )
105
+ if error.handle.kind_of? Mailgun::ErrorBase
106
+ raise error.handle
107
+ else
108
+ raise error
81
109
  end
82
- raise e
83
110
  end
84
111
  end
85
112
 
@@ -92,7 +119,9 @@ module Mailgun
92
119
  :protocol,
93
120
  :mailgun_host,
94
121
  :test_mode,
95
- :domain
122
+ :domain,
123
+ :webhook_url,
124
+ :public_api_key
96
125
 
97
126
  def configure
98
127
  yield self
@@ -0,0 +1,87 @@
1
+ module Mailgun
2
+ class Client
3
+ attr_reader :url
4
+
5
+ def initialize(url)
6
+ @url = url
7
+ end
8
+
9
+ def get(params = {})
10
+ request_path = path
11
+ request_path += "?#{URI.encode_www_form(params)}" if params.any?
12
+
13
+ request = Net::HTTP::Get.new(request_path)
14
+
15
+ make_request(request)
16
+ end
17
+
18
+ def post(params = {})
19
+ request = Net::HTTP::Post.new(path)
20
+ request.set_form_data(params)
21
+
22
+ make_request(request)
23
+ end
24
+
25
+ def put(params = {})
26
+ request = Net::HTTP::Put.new(path)
27
+ request.set_form_data(params)
28
+
29
+ make_request(request)
30
+ end
31
+
32
+ def delete(params = {})
33
+ request = Net::HTTP::Delete.new(path)
34
+ request.set_form_data(params)
35
+
36
+ make_request(request)
37
+ end
38
+
39
+ private
40
+
41
+ def make_request(request)
42
+ set_auth(request)
43
+ response = http_client.request(request)
44
+
45
+ check_for_errors(response)
46
+
47
+ response.body
48
+ end
49
+
50
+ def check_for_errors(response)
51
+ return if response.code == '200'
52
+
53
+ error = ClientError.new
54
+ error.http_code = response.code.to_i
55
+ error.http_body = response.body
56
+ raise error
57
+ end
58
+
59
+ def path
60
+ parsed_url.path
61
+ end
62
+
63
+ def parsed_url
64
+ @parsed_url ||= URI.parse url
65
+ end
66
+
67
+ def http_client
68
+ http = Net::HTTP.new(mailgun_url.host, mailgun_url.port)
69
+ http.use_ssl = true
70
+ http
71
+ end
72
+
73
+ def mailgun_url
74
+ URI.parse Mailgun().base_url
75
+ end
76
+
77
+ def set_auth(request)
78
+ request.basic_auth(parsed_url.user, parsed_url.password)
79
+ end
80
+ end
81
+ end
82
+
83
+ module Mailgun
84
+ class ClientError < StandardError
85
+ attr_accessor :http_code, :http_body
86
+ end
87
+ end
@@ -2,12 +2,11 @@ module Mailgun
2
2
 
3
3
  # Interface to manage domains
4
4
  class Domain
5
-
6
5
  # Used internally, called from Mailgun::Base
7
6
  def initialize(mailgun)
8
7
  @mailgun = mailgun
9
8
  end
10
-
9
+
11
10
  # List all domains on the account
12
11
  def list(options={})
13
12
  Mailgun.submit(:get, domain_url, options)["items"] || []
@@ -29,12 +28,18 @@ module Mailgun
29
28
  Mailgun.submit :delete, domain_url(domain)
30
29
  end
31
30
 
31
+ # Verifies a domain from account (Check DNS Records Now from Mailgun Web UI)
32
+ # The method is still in beta and you will need
33
+ # access from Mailgun to use it
34
+ def verify(domain)
35
+ Mailgun.submit :put, "#{domain_url(domain)}/verify"
36
+ end
37
+
32
38
  private
33
39
 
34
40
  # Helper method to generate the proper url for Mailgun domain API calls
35
41
  def domain_url(domain = nil)
36
42
  "#{@mailgun.base_url}/domains#{'/' + domain if domain}"
37
43
  end
38
-
39
44
  end
40
- end
45
+ end
@@ -27,6 +27,11 @@ module Mailgun
27
27
  Mailgun.submit :post, list_member_url, params.merge(options)
28
28
  end
29
29
 
30
+ def add_multi(members=[], options={})
31
+ params = {:members => members}
32
+ Mailgun.submit :post, list_member_json, params.merge(options)
33
+ end
34
+
30
35
  # TODO add spec?
31
36
  alias_method :create, :add
32
37
 
@@ -48,6 +53,9 @@ module Mailgun
48
53
  def list_member_url(member_address=nil)
49
54
  "#{@mailgun.base_url}/lists#{'/' + @address}/members#{'/' + member_address if member_address}"
50
55
  end
51
-
56
+
57
+ def list_member_json
58
+ "#{@mailgun.base_url}/lists#{'/' + @address}/members.json"
59
+ end
52
60
  end
53
61
  end
@@ -1,4 +1,57 @@
1
1
  module Mailgun
2
- class Error < StandardError
2
+ class Error
3
+ attr_accessor :error
4
+
5
+ def initialize(options={})
6
+ @error =
7
+ case options[:code]
8
+ when 200
9
+ # Not an error
10
+ when 404
11
+ Mailgun::NotFound.new(options[:message])
12
+ when 400
13
+ Mailgun::BadRequest.new(options[:message])
14
+ when 401
15
+ Mailgun::Unauthorized.new(options[:message])
16
+ when 402
17
+ Mailgun::ResquestFailed.new(options[:message])
18
+ when 500, 502, 503, 504
19
+ Mailgun::ServerError.new(options[:message])
20
+ else
21
+ Mailgun::ErrorBase.new(options[:message])
22
+ end
23
+ end
24
+
25
+ def handle
26
+ return error.handle
27
+ end
28
+ end
29
+
30
+ class ErrorBase < StandardError
31
+ # Handles the error if needed
32
+ # by default returns an error
33
+ #
34
+ # @return [type] [description]
35
+ def handle
36
+ return self
37
+ end
38
+ end
39
+
40
+ class NotFound < ErrorBase
41
+ def handle
42
+ return nil
43
+ end
44
+ end
45
+
46
+ class BadRequest < ErrorBase
47
+ end
48
+
49
+ class Unauthorized < ErrorBase
50
+ end
51
+
52
+ class ResquestFailed < ErrorBase
53
+ end
54
+
55
+ class ServerError < ErrorBase
3
56
  end
4
57
  end