mailgun 0.8 → 0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +13 -0
- data/CONTRIBUTORS.md +5 -1
- data/README.md +39 -2
- data/lib/mailgun.rb +6 -1
- data/lib/mailgun/address.rb +20 -0
- data/lib/mailgun/base.rb +45 -16
- data/lib/mailgun/client.rb +87 -0
- data/lib/mailgun/domain.rb +9 -4
- data/lib/mailgun/list/member.rb +9 -1
- data/lib/mailgun/mailgun_error.rb +54 -1
- data/lib/mailgun/route.rb +9 -4
- data/lib/mailgun/secure.rb +30 -0
- data/lib/mailgun/webhook.rb +55 -0
- data/lib/multimap/spec/enumerable_examples.rb +22 -22
- data/lib/multimap/spec/hash_examples.rb +88 -88
- data/lib/multimap/spec/multiset_spec.rb +62 -62
- data/lib/multimap/spec/nested_multimap_spec.rb +58 -58
- data/lib/multimap/spec/set_examples.rb +112 -112
- data/lib/multimap/spec/spec_helper.rb +2 -2
- data/mailgun.gemspec +3 -5
- data/spec/address_spec.rb +27 -0
- data/spec/base_spec.rb +31 -25
- data/spec/bounce_spec.rb +5 -5
- data/spec/client_spec.rb +118 -0
- data/spec/complaint_spec.rb +4 -4
- data/spec/domain_spec.rb +17 -5
- data/spec/helpers/mailgun_helper.rb +9 -0
- data/spec/list/member_spec.rb +7 -7
- data/spec/list/message_spec.rb +3 -3
- data/spec/list_spec.rb +6 -6
- data/spec/log_spec.rb +2 -2
- data/spec/mailbox_spec.rb +4 -4
- data/spec/route_spec.rb +10 -11
- data/spec/secure_spec.rb +55 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unsubscribe_spec.rb +6 -6
- data/spec/webhook_spec.rb +115 -0
- metadata +22 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f47c74dc32e3f6a7436d43f289f9af79f449156f
|
4
|
+
data.tar.gz: 554bef62dd88c32a6de42af428c882e2b4f9c122
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f0b40b7ecbeda0baea7d9069c10f4516d79b4fcc51e22f2bb98078d64a44883ee095b0b42d8945f0cfdc2a7530ff8f5bebbb3da64397c9156087087429c0c24
|
7
|
+
data.tar.gz: 34e235408386e399fe7f19f4ec6f51d52cf1d3487ceca784d89976f315ab74f7bd54b61ec4f1403f5a2928491bfc2ae1825b4c5087b5a8fc7e552e2326ab3e52
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CONTRIBUTORS.md
CHANGED
@@ -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
|
-
##
|
248
|
+
## Maintainers
|
212
249
|
|
213
|
-
|
250
|
+
* Hairihan / [@hairihan](http://github.com/hairihan)
|
214
251
|
|
215
252
|
|
216
253
|
## Authors
|
data/lib/mailgun.rb
CHANGED
@@ -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
|
data/lib/mailgun/base.rb
CHANGED
@@ -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) { "
|
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
|
-
|
71
|
-
return JSON(RestClient.send(method, url, parameters))
|
93
|
+
JSON.parse(Client.new(url).send(method, parameters))
|
72
94
|
rescue => e
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
data/lib/mailgun/domain.rb
CHANGED
@@ -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
|
data/lib/mailgun/list/member.rb
CHANGED
@@ -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
|
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
|