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

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