mailgunner 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ A Ruby wrapper for the [Mailgun API](http://documentation.mailgun.net/api_reference.html)
2
+ =========================================================================================
3
+
4
+
5
+ Quick Start
6
+ -----------
7
+
8
+ ```ruby
9
+ require 'mailgunner'
10
+
11
+ mailgun = Mailgunner::Client.new(domain: 'samples.mailgun.org', api_key: 'key-3ax6xnjp29jd6fds4gc373sgvjxteol0')
12
+
13
+ response = mailgun.get_stats(limit: 5)
14
+
15
+ if response.ok?
16
+ # do something with response.object
17
+ else
18
+ # handle client/server error
19
+ end
20
+ ```
21
+
22
+
23
+ Alternative JSON Implementations
24
+ --------------------------------
25
+
26
+ Mailgunner::Client defaults to using the "json" library which is available
27
+ in the Ruby 1.9 standard library, and as a gem for Ruby 1.8. You can specify
28
+ an alternative implementation using the json option when constructing a client
29
+ object. For example, to use [multi_json](https://rubygems.org/gems/multi_json):
30
+
31
+ ```ruby
32
+ mailgun = Mailgunner::Client.new(:json => MultiJson)
33
+ ```
34
+
35
+
36
+ Environment Variables
37
+ ---------------------
38
+
39
+ Best practice for storing credentials for external services is to use environment
40
+ variables, as described by [12factor.net/config](http://www.12factor.net/config).
41
+
42
+ Mailgunner::Client defaults to extracting the domain and api_key values it needs
43
+ from the MAILGUN_API_KEY and MAILGUN_SMTP_LOGIN environment variables. These will
44
+ exist if you are using Mailgun on Heroku, or you can set them manually.
45
+
data/lib/mailgunner.rb ADDED
@@ -0,0 +1,300 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'cgi'
4
+ require 'uri'
5
+
6
+ module Mailgunner
7
+ class Client
8
+ attr_accessor :domain, :api_key, :json, :http
9
+
10
+ def initialize(options = {})
11
+ @domain = options.fetch(:domain) { ENV.fetch('MAILGUN_SMTP_LOGIN').split('@').last }
12
+
13
+ @api_key = options.fetch(:api_key) { ENV.fetch('MAILGUN_API_KEY') }
14
+
15
+ @json = options.fetch(:json) { JSON }
16
+
17
+ @http = Net::HTTP.new('api.mailgun.net', Net::HTTP.https_default_port)
18
+
19
+ @http.use_ssl = true
20
+ end
21
+
22
+ def send_message(attributes = {})
23
+ post("/v2/#{escape @domain}/messages", attributes)
24
+ end
25
+
26
+ def get_domains(params = {})
27
+ get('/v2/domains', params)
28
+ end
29
+
30
+ def get_domain(name)
31
+ get("/v2/domains/#{escape name}")
32
+ end
33
+
34
+ def add_domain(attributes = {})
35
+ post('/v2/domains', attributes)
36
+ end
37
+
38
+ def get_unsubscribes(params = {})
39
+ get("/v2/#{escape @domain}/unsubscribes", params)
40
+ end
41
+
42
+ def get_unsubscribe(address)
43
+ get("/v2/#{escape @domain}/unsubscribes/#{escape address}")
44
+ end
45
+
46
+ def delete_unsubscribe(address_or_id)
47
+ delete("/v2/#{escape @domain}/unsubscribes/#{escape address_or_id}")
48
+ end
49
+
50
+ def add_unsubscribe(attributes = {})
51
+ post("/v2/#{escape @domain}/unsubscribes", attributes)
52
+ end
53
+
54
+ def get_complaints(params = {})
55
+ get("/v2/#{escape @domain}/complaints", params)
56
+ end
57
+
58
+ def get_complaint(address)
59
+ get("/v2/#{escape @domain}/complaints/#{escape address}")
60
+ end
61
+
62
+ def add_complaint(attributes = {})
63
+ post("/v2/#{escape @domain}/complaints", attributes)
64
+ end
65
+
66
+ def delete_complaint(address)
67
+ delete("/v2/#{escape @domain}/complaints/#{escape address}")
68
+ end
69
+
70
+ def get_bounces(params = {})
71
+ get("/v2/#{escape @domain}/bounces", params)
72
+ end
73
+
74
+ def get_bounce(address)
75
+ get("/v2/#{escape @domain}/bounces/#{escape address}")
76
+ end
77
+
78
+ def add_bounce(attributes = {})
79
+ post("/v2/#{escape @domain}/bounces", attributes)
80
+ end
81
+
82
+ def delete_bounce(address)
83
+ delete("/v2/#{escape @domain}/bounces/#{escape address}")
84
+ end
85
+
86
+ def get_stats(params = {})
87
+ get("/v2/#{escape @domain}/stats", params)
88
+ end
89
+
90
+ def get_log(params = {})
91
+ get("/v2/#{escape @domain}/log", params)
92
+ end
93
+
94
+ def get_routes(params = {})
95
+ get('/v2/routes', params)
96
+ end
97
+
98
+ def get_route(id)
99
+ get("/v2/routes/#{escape id}")
100
+ end
101
+
102
+ def add_route(attributes = {})
103
+ post('/v2/routes', attributes)
104
+ end
105
+
106
+ def update_route(id, attributes = {})
107
+ put("/v2/routes/#{escape id}", attributes)
108
+ end
109
+
110
+ def delete_route(id)
111
+ delete("/v2/routes/#{escape id}")
112
+ end
113
+
114
+ def get_mailboxes(params = {})
115
+ get("/v2/#{escape @domain}/mailboxes", params)
116
+ end
117
+
118
+ def add_mailbox(attributes = {})
119
+ post("/v2/#{escape @domain}/mailboxes", attributes)
120
+ end
121
+
122
+ def update_mailbox(name, attributes = {})
123
+ put("/v2/#{escape @domain}/mailboxes/#{escape name}", attributes)
124
+ end
125
+
126
+ def delete_mailbox(name)
127
+ delete("/v2/#{escape @domain}/mailboxes/#{escape name}")
128
+ end
129
+
130
+ def get_campaigns(params = {})
131
+ get("/v2/#{escape @domain}/campaigns", params)
132
+ end
133
+
134
+ def get_campaign(id)
135
+ get("/v2/#{escape @domain}/campaigns/#{escape id}")
136
+ end
137
+
138
+ def add_campaign(attributes = {})
139
+ post("/v2/#{escape @domain}/campaigns", attributes)
140
+ end
141
+
142
+ def update_campaign(id, attributes = {})
143
+ put("/v2/#{escape @domain}/campaigns/#{escape id}", attributes)
144
+ end
145
+
146
+ def delete_campaign(id)
147
+ delete("/v2/#{escape @domain}/campaigns/#{escape id}")
148
+ end
149
+
150
+ def get_campaign_events(campaign_id, params = {})
151
+ get("/v2/#{escape @domain}/campaigns/#{escape campaign_id}/events", params)
152
+ end
153
+
154
+ def get_campaign_stats(campaign_id, params = {})
155
+ get("/v2/#{escape @domain}/campaigns/#{escape campaign_id}/stats", params)
156
+ end
157
+
158
+ def get_campaign_clicks(campaign_id, params = {})
159
+ get("/v2/#{escape @domain}/campaigns/#{escape campaign_id}/clicks", params)
160
+ end
161
+
162
+ def get_campaign_opens(campaign_id, params = {})
163
+ get("/v2/#{escape @domain}/campaigns/#{escape campaign_id}/opens", params)
164
+ end
165
+
166
+ def get_campaign_unsubscribes(campaign_id, params = {})
167
+ get("/v2/#{escape @domain}/campaigns/#{escape campaign_id}/unsubscribes", params)
168
+ end
169
+
170
+ def get_campaign_complaints(campaign_id, params = {})
171
+ get("/v2/#{escape @domain}/campaigns/#{escape campaign_id}/complaints", params)
172
+ end
173
+
174
+ def get_lists(params = {})
175
+ get('/v2/lists', params)
176
+ end
177
+
178
+ def get_list(address)
179
+ get("/v2/lists/#{escape address}")
180
+ end
181
+
182
+ def add_list(attributes = {})
183
+ post('/v2/lists', attributes)
184
+ end
185
+
186
+ def update_list(address, attributes = {})
187
+ put("/v2/lists/#{escape address}", attributes)
188
+ end
189
+
190
+ def delete_list(address)
191
+ delete("/v2/lists/#{escape address}")
192
+ end
193
+
194
+ def get_list_members(list_address, params = {})
195
+ get("/v2/lists/#{escape list_address}/members", params)
196
+ end
197
+
198
+ def get_list_member(list_address, member_address)
199
+ get("/v2/lists/#{escape list_address}/members/#{escape member_address}")
200
+ end
201
+
202
+ def add_list_member(list_address, member_attributes)
203
+ post("/v2/lists/#{escape list_address}/members", member_attributes)
204
+ end
205
+
206
+ def update_list_member(list_address, member_address, member_attributes)
207
+ put("/v2/lists/#{escape list_address}/members/#{escape member_address}", member_attributes)
208
+ end
209
+
210
+ def delete_list_member(list_address, member_address)
211
+ delete("/v2/lists/#{escape list_address}/members/#{escape member_address}")
212
+ end
213
+
214
+ def get_list_stats(list_address)
215
+ get("/v2/lists/#{escape list_address}/stats")
216
+ end
217
+
218
+ private
219
+
220
+ def get(path, params = {})
221
+ transmit(Net::HTTP::Get, request_uri(path, params))
222
+ end
223
+
224
+ def post(path, attributes = {})
225
+ transmit(Net::HTTP::Post, path, attributes)
226
+ end
227
+
228
+ def put(path, attributes = {})
229
+ transmit(Net::HTTP::Put, path, attributes)
230
+ end
231
+
232
+ def delete(path)
233
+ transmit(Net::HTTP::Delete, path)
234
+ end
235
+
236
+ def transmit(subclass, path, attributes = nil)
237
+ message = subclass.new(path)
238
+ message.basic_auth('api', @api_key)
239
+ message.body = URI.encode_www_form(attributes) if attributes
240
+
241
+ Response.new(@http.request(message), :json => @json)
242
+ end
243
+
244
+ def request_uri(path, params_hash)
245
+ if params_hash.empty?
246
+ path
247
+ else
248
+ tmp = []
249
+
250
+ params_hash.each do |key, values|
251
+ Array(values).each do |value|
252
+ tmp << "#{escape(key)}=#{escape(value)}"
253
+ end
254
+ end
255
+
256
+ path + '?' + tmp.join('&')
257
+ end
258
+ end
259
+
260
+ def escape(component)
261
+ CGI.escape(component.to_s)
262
+ end
263
+ end
264
+
265
+ class Response
266
+ def initialize(http_response, options = {})
267
+ @http_response = http_response
268
+
269
+ @json = options.fetch(:json) { JSON }
270
+ end
271
+
272
+ def method_missing(name, *args, &block)
273
+ @http_response.send(name, *args, &block)
274
+ end
275
+
276
+ def respond_to_missing?(name, include_private = false)
277
+ @http_response.respond_to?(name)
278
+ end
279
+
280
+ def ok?
281
+ code.to_i == 200
282
+ end
283
+
284
+ def client_error?
285
+ (400 .. 499).include?(code.to_i)
286
+ end
287
+
288
+ def server_error?
289
+ (500 .. 599).include?(code.to_i)
290
+ end
291
+
292
+ def json?
293
+ self['Content-Type'].split(';').first == 'application/json'
294
+ end
295
+
296
+ def object
297
+ @object ||= @json.load(body)
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'mailgunner'
3
+ s.version = '1.0.0'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.authors = ['Tim Craft']
6
+ s.email = ['mail@timcraft.com']
7
+ s.homepage = 'http://github.com/timcraft/mailgunner'
8
+ s.description = 'A Ruby wrapper for the Mailgun API'
9
+ s.summary = 'See description'
10
+ s.files = Dir.glob('{lib,spec}/**/*') + %w(README.md mailgunner.gemspec)
11
+ s.add_development_dependency('rake', '>= 0.9.3')
12
+ s.add_development_dependency('mocha', '~> 0.10.3')
13
+ s.require_path = 'lib'
14
+ end
@@ -0,0 +1,763 @@
1
+ require 'minitest/autorun'
2
+ require 'mailgunner'
3
+ require 'mocha'
4
+
5
+ class Net::HTTPGenericRequest
6
+ def inspect
7
+ if request_body_permitted?
8
+ "<#{self.class.name} #{path} #{body}>"
9
+ else
10
+ "<#{self.class.name} #{path}>"
11
+ end
12
+ end
13
+ end
14
+
15
+ describe 'Mailgunner::Client' do
16
+ before do
17
+ @domain = 'samples.mailgun.org'
18
+
19
+ @api_key = 'xxx'
20
+
21
+ @client = Mailgunner::Client.new(domain: @domain, api_key: @api_key)
22
+
23
+ @address = 'user@example.com'
24
+
25
+ @encoded_address = 'user%40example.com'
26
+ end
27
+
28
+ def expect(request_class, arg)
29
+ matcher = String === arg ? responds_with(:path, arg) : arg
30
+
31
+ @client.http.expects(:request).with(all_of(instance_of(request_class), matcher)).returns(stub)
32
+ end
33
+
34
+ describe 'http method' do
35
+ it 'returns a net http object that uses ssl' do
36
+ @client.http.must_be_instance_of(Net::HTTP)
37
+
38
+ @client.http.use_ssl?.must_equal(true)
39
+ end
40
+ end
41
+
42
+ describe 'domain method' do
43
+ it 'returns the value passed to the constructor' do
44
+ @client.domain.must_equal(@domain)
45
+ end
46
+
47
+ it 'defaults to the domain in the MAILGUN_SMTP_LOGIN environment variable' do
48
+ ENV['MAILGUN_SMTP_LOGIN'] = 'postmaster@samples.mailgun.org'
49
+
50
+ Mailgunner::Client.new(api_key: @api_key).domain.must_equal(@domain)
51
+ end
52
+ end
53
+
54
+ describe 'api_key method' do
55
+ it 'returns the value passed to the constructor' do
56
+ @client.api_key.must_equal(@api_key)
57
+ end
58
+
59
+ it 'defaults to the value of MAILGUN_API_KEY environment variable' do
60
+ ENV['MAILGUN_API_KEY'] = @api_key
61
+
62
+ Mailgunner::Client.new(domain: @domain).api_key.must_equal(@api_key)
63
+ end
64
+ end
65
+
66
+ describe 'json method' do
67
+ it 'returns the value passed to the constructor' do
68
+ json = stub
69
+
70
+ Mailgunner::Client.new(json: json).json.must_equal(json)
71
+ end
72
+
73
+ it 'defaults to the standard library json implementation' do
74
+ @client.json.must_equal(JSON)
75
+ end
76
+ end
77
+
78
+ describe 'send_message method' do
79
+ it 'posts to the domain messages resource and returns a response object' do
80
+ expect(Net::HTTP::Post, "/v2/#@domain/messages")
81
+
82
+ @client.send_message({}).must_be_instance_of(Mailgunner::Response)
83
+ end
84
+
85
+ it 'encodes the message attributes' do
86
+ expect(Net::HTTP::Post, responds_with(:body, "to=#@encoded_address"))
87
+
88
+ @client.add_domain({to: @address})
89
+ end
90
+
91
+ it 'encodes the message attributes as multipart form data when sending attachments' do
92
+ # TODO
93
+ end
94
+ end
95
+
96
+ describe 'get_domains method' do
97
+ it 'fetches the domains resource and returns a response object' do
98
+ expect(Net::HTTP::Get, '/v2/domains')
99
+
100
+ @client.get_domains.must_be_instance_of(Mailgunner::Response)
101
+ end
102
+ end
103
+
104
+ describe 'get_domain method' do
105
+ it 'fetches the domain resource and returns a response object' do
106
+ expect(Net::HTTP::Get, "/v2/domains/#@domain")
107
+
108
+ @client.get_domain(@domain).must_be_instance_of(Mailgunner::Response)
109
+ end
110
+ end
111
+
112
+ describe 'add_domain method' do
113
+ it 'posts to the domains resource and returns a response object' do
114
+ expect(Net::HTTP::Post, '/v2/domains')
115
+
116
+ @client.add_domain({}).must_be_instance_of(Mailgunner::Response)
117
+ end
118
+
119
+ it 'encodes the domain attributes' do
120
+ expect(Net::HTTP::Post, responds_with(:body, "name=#@domain"))
121
+
122
+ @client.add_domain({name: @domain})
123
+ end
124
+ end
125
+
126
+ describe 'get_unsubscribes method' do
127
+ it 'fetches the domain unsubscribes resource and returns a response object' do
128
+ expect(Net::HTTP::Get, "/v2/#@domain/unsubscribes")
129
+
130
+ @client.get_unsubscribes.must_be_instance_of(Mailgunner::Response)
131
+ end
132
+
133
+ it 'encodes skip and limit parameters' do
134
+ expect(Net::HTTP::Get, "/v2/#@domain/unsubscribes?skip=1&limit=2")
135
+
136
+ @client.get_unsubscribes(skip: 1, limit: 2)
137
+ end
138
+ end
139
+
140
+ describe 'get_unsubscribe method' do
141
+ it 'fetches the unsubscribe resource with the given address and returns a response object' do
142
+ expect(Net::HTTP::Get, "/v2/#@domain/unsubscribes/#@encoded_address")
143
+
144
+ @client.get_unsubscribe(@address).must_be_instance_of(Mailgunner::Response)
145
+ end
146
+ end
147
+
148
+ describe 'delete_unsubscribe method' do
149
+ it 'deletes the domain unsubscribe resource with the given address and returns a response object' do
150
+ expect(Net::HTTP::Delete, "/v2/#@domain/unsubscribes/#@encoded_address")
151
+
152
+ @client.delete_unsubscribe(@address).must_be_instance_of(Mailgunner::Response)
153
+ end
154
+ end
155
+
156
+ describe 'add_unsubscribe method' do
157
+ it 'posts to the domain unsubscribes resource and returns a response object' do
158
+ expect(Net::HTTP::Post, "/v2/#@domain/unsubscribes")
159
+
160
+ @client.add_unsubscribe({}).must_be_instance_of(Mailgunner::Response)
161
+ end
162
+
163
+ it 'encodes the unsubscribe attributes' do
164
+ expect(Net::HTTP::Post, responds_with(:body, "address=#@encoded_address"))
165
+
166
+ @client.add_unsubscribe({address: @address})
167
+ end
168
+ end
169
+
170
+ describe 'get_complaints method' do
171
+ it 'fetches the domain complaints resource and returns a response object' do
172
+ expect(Net::HTTP::Get, "/v2/#@domain/complaints")
173
+
174
+ @client.get_complaints.must_be_instance_of(Mailgunner::Response)
175
+ end
176
+
177
+ it 'encodes skip and limit parameters' do
178
+ expect(Net::HTTP::Get, "/v2/#@domain/complaints?skip=1&limit=2")
179
+
180
+ @client.get_complaints(skip: 1, limit: 2)
181
+ end
182
+ end
183
+
184
+ describe 'get_complaint method' do
185
+ it 'fetches the complaint resource with the given address and returns a response object' do
186
+ expect(Net::HTTP::Get, "/v2/#@domain/complaints/#@encoded_address")
187
+
188
+ @client.get_complaint(@address).must_be_instance_of(Mailgunner::Response)
189
+ end
190
+ end
191
+
192
+ describe 'add_complaint method' do
193
+ it 'posts to the domain complaints resource and returns a response object' do
194
+ expect(Net::HTTP::Post, "/v2/#@domain/complaints")
195
+
196
+ @client.add_complaint({}).must_be_instance_of(Mailgunner::Response)
197
+ end
198
+
199
+ it 'encodes the complaint attributes' do
200
+ expect(Net::HTTP::Post, responds_with(:body, "address=#@encoded_address"))
201
+
202
+ @client.add_complaint({address: @address})
203
+ end
204
+ end
205
+
206
+ describe 'delete_complaint method' do
207
+ it 'deletes the domain complaint resource with the given address and returns a response object' do
208
+ expect(Net::HTTP::Delete, "/v2/#@domain/complaints/#@encoded_address")
209
+
210
+ @client.delete_complaint(@address).must_be_instance_of(Mailgunner::Response)
211
+ end
212
+ end
213
+
214
+ describe 'get_bounces method' do
215
+ it 'fetches the domain bounces resource and returns a response object' do
216
+ expect(Net::HTTP::Get, "/v2/#@domain/bounces")
217
+
218
+ @client.get_bounces.must_be_instance_of(Mailgunner::Response)
219
+ end
220
+
221
+ it 'encodes skip and limit parameters' do
222
+ expect(Net::HTTP::Get, "/v2/#@domain/bounces?skip=1&limit=2")
223
+
224
+ @client.get_bounces(skip: 1, limit: 2)
225
+ end
226
+ end
227
+
228
+ describe 'get_bounce method' do
229
+ it 'fetches the bounce resource with the given address and returns a response object' do
230
+ expect(Net::HTTP::Get, "/v2/#@domain/bounces/#@encoded_address")
231
+
232
+ @client.get_bounce(@address).must_be_instance_of(Mailgunner::Response)
233
+ end
234
+ end
235
+
236
+ describe 'add_bounce method' do
237
+ it 'posts to the domain bounces resource and returns a response object' do
238
+ expect(Net::HTTP::Post, "/v2/#@domain/bounces")
239
+
240
+ @client.add_bounce({}).must_be_instance_of(Mailgunner::Response)
241
+ end
242
+
243
+ it 'encodes the bounce attributes' do
244
+ expect(Net::HTTP::Post, responds_with(:body, "address=#@encoded_address"))
245
+
246
+ @client.add_bounce({address: @address})
247
+ end
248
+ end
249
+
250
+ describe 'delete_bounce method' do
251
+ it 'deletes the domain bounce resource with the given address and returns a response object' do
252
+ expect(Net::HTTP::Delete, "/v2/#@domain/bounces/#@encoded_address")
253
+
254
+ @client.delete_bounce(@address).must_be_instance_of(Mailgunner::Response)
255
+ end
256
+ end
257
+
258
+ describe 'get_stats method' do
259
+ it 'fetches the domain stats resource and returns a response object' do
260
+ expect(Net::HTTP::Get, "/v2/#@domain/stats")
261
+
262
+ @client.get_stats.must_be_instance_of(Mailgunner::Response)
263
+ end
264
+
265
+ it 'encodes skip and limit parameters' do
266
+ expect(Net::HTTP::Get, "/v2/#@domain/stats?skip=1&limit=2")
267
+
268
+ @client.get_stats(skip: 1, limit: 2)
269
+ end
270
+
271
+ it 'encodes an event parameter with multiple values' do
272
+ expect(Net::HTTP::Get, "/v2/#@domain/stats?event=sent&event=opened")
273
+
274
+ @client.get_stats(event: %w(sent opened))
275
+ end
276
+ end
277
+
278
+ describe 'get_log method' do
279
+ it 'fetches the domain stats resource and returns a response object' do
280
+ expect(Net::HTTP::Get, "/v2/#@domain/log")
281
+
282
+ @client.get_log.must_be_instance_of(Mailgunner::Response)
283
+ end
284
+
285
+ it 'encodes skip and limit parameters' do
286
+ expect(Net::HTTP::Get, "/v2/#@domain/log?skip=1&limit=2")
287
+
288
+ @client.get_log(skip: 1, limit: 2)
289
+ end
290
+ end
291
+
292
+ describe 'get_routes method' do
293
+ it 'fetches the global routes resource and returns a response object' do
294
+ expect(Net::HTTP::Get, '/v2/routes')
295
+
296
+ @client.get_routes.must_be_instance_of(Mailgunner::Response)
297
+ end
298
+
299
+ it 'encodes skip and limit parameters' do
300
+ expect(Net::HTTP::Get, '/v2/routes?skip=1&limit=2')
301
+
302
+ @client.get_routes(skip: 1, limit: 2)
303
+ end
304
+ end
305
+
306
+ describe 'get_route method' do
307
+ it 'fetches the route resource with the given id and returns a response object' do
308
+ expect(Net::HTTP::Get, '/v2/routes/4f3bad2335335426750048c6')
309
+
310
+ @client.get_route('4f3bad2335335426750048c6').must_be_instance_of(Mailgunner::Response)
311
+ end
312
+ end
313
+
314
+ describe 'add_route method' do
315
+ it 'posts to the routes resource and returns a response object' do
316
+ expect(Net::HTTP::Post, '/v2/routes')
317
+
318
+ @client.add_route({}).must_be_instance_of(Mailgunner::Response)
319
+ end
320
+
321
+ it 'encodes the route attributes' do
322
+ expect(Net::HTTP::Post, responds_with(:body, 'description=Example+route&priority=1'))
323
+
324
+ @client.add_route({description: 'Example route', priority: 1})
325
+ end
326
+ end
327
+
328
+ describe 'update_route method' do
329
+ it 'updates the route resource with the given id and returns a response object' do
330
+ expect(Net::HTTP::Put, '/v2/routes/4f3bad2335335426750048c6')
331
+
332
+ @client.update_route('4f3bad2335335426750048c6', {}).must_be_instance_of(Mailgunner::Response)
333
+ end
334
+
335
+ it 'encodes the route attributes' do
336
+ expect(Net::HTTP::Put, responds_with(:body, 'priority=10'))
337
+
338
+ @client.update_route('4f3bad2335335426750048c6', {priority: 10})
339
+ end
340
+ end
341
+
342
+ describe 'delete_route method' do
343
+ it 'deletes the route resource with the given id and returns a response object' do
344
+ expect(Net::HTTP::Delete, '/v2/routes/4f3bad2335335426750048c6')
345
+
346
+ @client.delete_route('4f3bad2335335426750048c6').must_be_instance_of(Mailgunner::Response)
347
+ end
348
+ end
349
+
350
+ describe 'get_mailboxes method' do
351
+ it 'fetches the domain mailboxes resource and returns a response object' do
352
+ expect(Net::HTTP::Get, "/v2/#@domain/mailboxes")
353
+
354
+ @client.get_mailboxes.must_be_instance_of(Mailgunner::Response)
355
+ end
356
+
357
+ it 'encodes skip and limit parameters' do
358
+ expect(Net::HTTP::Get, "/v2/#@domain/mailboxes?skip=1&limit=2")
359
+
360
+ @client.get_mailboxes(skip: 1, limit: 2)
361
+ end
362
+ end
363
+
364
+ describe 'add_mailbox method' do
365
+ it 'posts to the domain mailboxes resource and returns a response object' do
366
+ expect(Net::HTTP::Post, "/v2/#@domain/mailboxes")
367
+
368
+ @client.add_mailbox({}).must_be_instance_of(Mailgunner::Response)
369
+ end
370
+
371
+ it 'encodes the mailbox attributes' do
372
+ expect(Net::HTTP::Post, responds_with(:body, 'mailbox=user'))
373
+
374
+ @client.add_mailbox({mailbox: 'user'})
375
+ end
376
+ end
377
+
378
+ describe 'update_mailbox method' do
379
+ it 'updates the mailbox resource and returns a response object' do
380
+ expect(Net::HTTP::Put, "/v2/#@domain/mailboxes/user")
381
+
382
+ @client.update_mailbox('user', {}).must_be_instance_of(Mailgunner::Response)
383
+ end
384
+
385
+ it 'encodes the mailbox attributes' do
386
+ expect(Net::HTTP::Put, responds_with(:body, 'password=secret'))
387
+
388
+ @client.update_mailbox('user', {password: 'secret'})
389
+ end
390
+ end
391
+
392
+ describe 'delete_mailbox method' do
393
+ it 'deletes the domain mailbox resource with the given address and returns a response object' do
394
+ expect(Net::HTTP::Delete, "/v2/#@domain/mailboxes/user")
395
+
396
+ @client.delete_mailbox('user').must_be_instance_of(Mailgunner::Response)
397
+ end
398
+ end
399
+
400
+ describe 'get_campaigns method' do
401
+ it 'fetches the domain campaigns resource and returns a response object' do
402
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns")
403
+
404
+ @client.get_campaigns.must_be_instance_of(Mailgunner::Response)
405
+ end
406
+
407
+ it 'encodes skip and limit parameters' do
408
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns?skip=1&limit=2")
409
+
410
+ @client.get_campaigns(skip: 1, limit: 2)
411
+ end
412
+ end
413
+
414
+ describe 'get_campaign method' do
415
+ it 'fetches the campaign resource with the given id and returns a response object' do
416
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id")
417
+
418
+ @client.get_campaign('id').must_be_instance_of(Mailgunner::Response)
419
+ end
420
+ end
421
+
422
+ describe 'add_campaign method' do
423
+ it 'posts to the domain campaigns resource and returns a response object' do
424
+ expect(Net::HTTP::Post, "/v2/#@domain/campaigns")
425
+
426
+ @client.add_campaign({}).must_be_instance_of(Mailgunner::Response)
427
+ end
428
+
429
+ it 'encodes the campaign attributes' do
430
+ expect(Net::HTTP::Post, responds_with(:body, 'id=id'))
431
+
432
+ @client.add_campaign({id: 'id'})
433
+ end
434
+ end
435
+
436
+ describe 'update_campaign method' do
437
+ it 'updates the campaign resource and returns a response object' do
438
+ expect(Net::HTTP::Put, "/v2/#@domain/campaigns/id")
439
+
440
+ @client.update_campaign('id', {}).must_be_instance_of(Mailgunner::Response)
441
+ end
442
+
443
+ it 'encodes the campaign attributes' do
444
+ expect(Net::HTTP::Put, responds_with(:body, 'name=Example+Campaign'))
445
+
446
+ @client.update_campaign('id', {name: 'Example Campaign'})
447
+ end
448
+ end
449
+
450
+ describe 'delete_campaign method' do
451
+ it 'deletes the domain campaign resource with the given id and returns a response object' do
452
+ expect(Net::HTTP::Delete, "/v2/#@domain/campaigns/id")
453
+
454
+ @client.delete_campaign('id').must_be_instance_of(Mailgunner::Response)
455
+ end
456
+ end
457
+
458
+ describe 'get_campaign_events method' do
459
+ it 'fetches the domain campaign events resource and returns a response object' do
460
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/events")
461
+
462
+ @client.get_campaign_events('id').must_be_instance_of(Mailgunner::Response)
463
+ end
464
+
465
+ it 'encodes the optional parameters' do
466
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/events?country=US&limit=100")
467
+
468
+ @client.get_campaign_events('id', country: 'US', limit: 100)
469
+ end
470
+ end
471
+
472
+ describe 'get_campaign_stats method' do
473
+ it 'fetches the domain campaign stats resource and returns a response object' do
474
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/stats")
475
+
476
+ @client.get_campaign_stats('id').must_be_instance_of(Mailgunner::Response)
477
+ end
478
+
479
+ it 'encodes the optional parameters' do
480
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/stats?groupby=dailyhour")
481
+
482
+ @client.get_campaign_stats('id', groupby: 'dailyhour')
483
+ end
484
+ end
485
+
486
+ describe 'get_campaign_clicks method' do
487
+ it 'fetches the domain campaign clicks resource and returns a response object' do
488
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/clicks")
489
+
490
+ @client.get_campaign_clicks('id').must_be_instance_of(Mailgunner::Response)
491
+ end
492
+
493
+ it 'encodes the optional parameters' do
494
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/clicks?groupby=month&limit=100")
495
+
496
+ @client.get_campaign_clicks('id', groupby: 'month', limit: 100)
497
+ end
498
+ end
499
+
500
+ describe 'get_campaign_opens method' do
501
+ it 'fetches the domain campaign opens resource and returns a response object' do
502
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/opens")
503
+
504
+ @client.get_campaign_opens('id').must_be_instance_of(Mailgunner::Response)
505
+ end
506
+
507
+ it 'encodes the optional parameters' do
508
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/opens?groupby=month&limit=100")
509
+
510
+ @client.get_campaign_opens('id', groupby: 'month', limit: 100)
511
+ end
512
+ end
513
+
514
+ describe 'get_campaign_unsubscribes method' do
515
+ it 'fetches the domain campaign unsubscribes resource and returns a response object' do
516
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/unsubscribes")
517
+
518
+ @client.get_campaign_unsubscribes('id').must_be_instance_of(Mailgunner::Response)
519
+ end
520
+
521
+ it 'encodes the optional parameters' do
522
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/unsubscribes?groupby=month&limit=100")
523
+
524
+ @client.get_campaign_unsubscribes('id', groupby: 'month', limit: 100)
525
+ end
526
+ end
527
+
528
+ describe 'get_campaign_complaints method' do
529
+ it 'fetches the domain campaign complaints resource and returns a response object' do
530
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/complaints")
531
+
532
+ @client.get_campaign_complaints('id').must_be_instance_of(Mailgunner::Response)
533
+ end
534
+
535
+ it 'encodes the optional parameters' do
536
+ expect(Net::HTTP::Get, "/v2/#@domain/campaigns/id/complaints?groupby=month&limit=100")
537
+
538
+ @client.get_campaign_complaints('id', groupby: 'month', limit: 100)
539
+ end
540
+ end
541
+
542
+ describe 'get_lists method' do
543
+ it 'fetches the domain lists resource and returns a response object' do
544
+ expect(Net::HTTP::Get, '/v2/lists')
545
+
546
+ @client.get_lists.must_be_instance_of(Mailgunner::Response)
547
+ end
548
+
549
+ it 'encodes skip and limit parameters' do
550
+ expect(Net::HTTP::Get, '/v2/lists?skip=1&limit=2')
551
+
552
+ @client.get_lists(skip: 1, limit: 2)
553
+ end
554
+ end
555
+
556
+ describe 'get_list method' do
557
+ it 'fetches the list resource with the given address and returns a response object' do
558
+ expect(Net::HTTP::Get, '/v2/lists/developers%40mailgun.net')
559
+
560
+ @client.get_list('developers@mailgun.net').must_be_instance_of(Mailgunner::Response)
561
+ end
562
+ end
563
+
564
+ describe 'add_list method' do
565
+ it 'posts to the domain lists resource and returns a response object' do
566
+ expect(Net::HTTP::Post, '/v2/lists')
567
+
568
+ @client.add_list({}).must_be_instance_of(Mailgunner::Response)
569
+ end
570
+
571
+ it 'encodes the list attributes' do
572
+ expect(Net::HTTP::Post, responds_with(:body, 'address=developers%40mailgun.net'))
573
+
574
+ @client.add_list({address: 'developers@mailgun.net'})
575
+ end
576
+ end
577
+
578
+ describe 'update_list method' do
579
+ it 'updates the list resource and returns a response object' do
580
+ expect(Net::HTTP::Put, '/v2/lists/developers%40mailgun.net')
581
+
582
+ @client.update_list('developers@mailgun.net', {}).must_be_instance_of(Mailgunner::Response)
583
+ end
584
+
585
+ it 'encodes the list attributes' do
586
+ expect(Net::HTTP::Put, responds_with(:body, 'name=Example+list'))
587
+
588
+ @client.update_list('developers@mailgun.net', {name: 'Example list'})
589
+ end
590
+ end
591
+
592
+ describe 'delete_list method' do
593
+ it 'deletes the domain list resource with the given address and returns a response object' do
594
+ expect(Net::HTTP::Delete, '/v2/lists/developers%40mailgun.net')
595
+
596
+ @client.delete_list('developers@mailgun.net').must_be_instance_of(Mailgunner::Response)
597
+ end
598
+ end
599
+
600
+ describe 'get_list_members method' do
601
+ it 'fetches the list members resource and returns a response object' do
602
+ expect(Net::HTTP::Get, '/v2/lists/developers%40mailgun.net/members')
603
+
604
+ @client.get_list_members('developers@mailgun.net').must_be_instance_of(Mailgunner::Response)
605
+ end
606
+
607
+ it 'encodes skip and limit parameters' do
608
+ expect(Net::HTTP::Get, '/v2/lists/developers%40mailgun.net/members?skip=1&limit=2')
609
+
610
+ @client.get_list_members('developers@mailgun.net', skip: 1, limit: 2)
611
+ end
612
+ end
613
+
614
+ describe 'get_list_member method' do
615
+ it 'fetches the list member resource with the given address and returns a response object' do
616
+ expect(Net::HTTP::Get, "/v2/lists/developers%40mailgun.net/members/#@encoded_address")
617
+
618
+ @client.get_list_member('developers@mailgun.net', @address).must_be_instance_of(Mailgunner::Response)
619
+ end
620
+ end
621
+
622
+ describe 'add_list_member method' do
623
+ it 'posts to the list members resource and returns a response object' do
624
+ expect(Net::HTTP::Post, '/v2/lists/developers%40mailgun.net/members')
625
+
626
+ @client.add_list_member('developers@mailgun.net', {}).must_be_instance_of(Mailgunner::Response)
627
+ end
628
+
629
+ it 'encodes the list attributes' do
630
+ expect(Net::HTTP::Post, responds_with(:body, "address=#@encoded_address"))
631
+
632
+ @client.add_list_member('developers@mailgun.net', {address: @address})
633
+ end
634
+ end
635
+
636
+ describe 'update_list_member method' do
637
+ it 'updates the list member resource with the given address and returns a response object' do
638
+ expect(Net::HTTP::Put, "/v2/lists/developers%40mailgun.net/members/#@encoded_address")
639
+
640
+ @client.update_list_member('developers@mailgun.net', @address, {}).must_be_instance_of(Mailgunner::Response)
641
+ end
642
+
643
+ it 'encodes the list member attributes' do
644
+ expect(Net::HTTP::Put, responds_with(:body, 'subscribed=no'))
645
+
646
+ @client.update_list_member('developers@mailgun.net', @address, {subscribed: 'no'})
647
+ end
648
+ end
649
+
650
+ describe 'delete_list_member method' do
651
+ it 'deletes the list member resource with the given address and returns a response object' do
652
+ expect(Net::HTTP::Delete, "/v2/lists/developers%40mailgun.net/members/#@encoded_address")
653
+
654
+ @client.delete_list_member('developers@mailgun.net', @address).must_be_instance_of(Mailgunner::Response)
655
+ end
656
+ end
657
+
658
+ describe 'get_list_stats method' do
659
+ it 'fetches the list stats resource and returns a response object' do
660
+ expect(Net::HTTP::Get, '/v2/lists/developers%40mailgun.net/stats')
661
+
662
+ @client.get_list_stats('developers@mailgun.net').must_be_instance_of(Mailgunner::Response)
663
+ end
664
+ end
665
+ end
666
+
667
+ describe 'Mailgunner::Response' do
668
+ before do
669
+ @http_response = mock()
670
+
671
+ @response = Mailgunner::Response.new(@http_response)
672
+ end
673
+
674
+ it 'delegates missing methods to the http response object' do
675
+ @http_response.stubs(:code).returns('200')
676
+
677
+ @response.code.must_equal('200')
678
+ end
679
+
680
+ describe 'ok query method' do
681
+ it 'returns true if the status code is 200' do
682
+ @http_response.expects(:code).returns('200')
683
+
684
+ @response.ok?.must_equal(true)
685
+ end
686
+
687
+ it 'returns false otherwise' do
688
+ @http_response.expects(:code).returns('400')
689
+
690
+ @response.ok?.must_equal(false)
691
+ end
692
+ end
693
+
694
+ describe 'client_error query method' do
695
+ it 'returns true if the status code is 4xx' do
696
+ @http_response.stubs(:code).returns(%w(400 401 402 404).sample)
697
+
698
+ @response.client_error?.must_equal(true)
699
+ end
700
+
701
+ it 'returns false otherwise' do
702
+ @http_response.stubs(:code).returns('200')
703
+
704
+ @response.client_error?.must_equal(false)
705
+ end
706
+ end
707
+
708
+ describe 'server_error query method' do
709
+ it 'returns true if the status code is 5xx' do
710
+ @http_response.stubs(:code).returns(%w(500 502 503 504).sample)
711
+
712
+ @response.server_error?.must_equal(true)
713
+ end
714
+
715
+ it 'returns false otherwise' do
716
+ @http_response.stubs(:code).returns('200')
717
+
718
+ @response.server_error?.must_equal(false)
719
+ end
720
+ end
721
+
722
+ describe 'json query method' do
723
+ it 'returns true if the response has a json content type' do
724
+ @http_response.expects(:[]).with('Content-Type').returns('application/json;charset=utf-8')
725
+
726
+ @response.json?.must_equal(true)
727
+ end
728
+
729
+ it 'returns false otherwise' do
730
+ @http_response.expects(:[]).with('Content-Type').returns('text/html')
731
+
732
+ @response.json?.must_equal(false)
733
+ end
734
+ end
735
+
736
+ describe 'object method' do
737
+ it 'decodes the response body as json and returns a hash' do
738
+ @http_response.expects(:body).returns('{"foo":"bar"}')
739
+
740
+ @response.object.must_equal({'foo' => 'bar'})
741
+ end
742
+ end
743
+ end
744
+
745
+ describe 'Mailgunner::Response initialized with an alternative json implementation' do
746
+ before do
747
+ @json = mock()
748
+
749
+ @http_response = mock()
750
+
751
+ @response = Mailgunner::Response.new(@http_response, :json => @json)
752
+ end
753
+
754
+ describe 'object method' do
755
+ it 'uses the alternative json implementation to parse the response body' do
756
+ @http_response.stubs(:body).returns(response_body = '{"foo":"bar"}')
757
+
758
+ @json.expects(:load).with(response_body)
759
+
760
+ @response.object
761
+ end
762
+ end
763
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mailgunner
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tim Craft
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.3
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: mocha
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.10.3
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.10.3
46
+ description: A Ruby wrapper for the Mailgun API
47
+ email:
48
+ - mail@timcraft.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/mailgunner.rb
54
+ - spec/mailgunner_spec.rb
55
+ - README.md
56
+ - mailgunner.gemspec
57
+ homepage: http://github.com/timcraft/mailgunner
58
+ licenses: []
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.24
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: See description
81
+ test_files: []
82
+ has_rdoc: