mailgun 0.8 → 0.11

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