eliasbaixas-sendgrid_toolkit 1.0.5

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.
@@ -0,0 +1,278 @@
1
+ SendgridToolkit
2
+ ===============
3
+
4
+ SendgridToolkit is a Ruby wrapper for the Sendgrid Web API
5
+
6
+ Supported Modules
7
+ -----------------
8
+
9
+ SendgridToolkit provides a class for interacting with each of the following Sendgrid API modules:
10
+
11
+ - Bounces
12
+ - InvalidEmails
13
+ - SpamReports
14
+ - Statistics
15
+ - Unsubscribes
16
+
17
+ Consuming the Sendgrid API is as simple as instantiating a class and making the call:
18
+
19
+ unsubscribes = SendgridToolkit::Unsubscribes.new("username", "api_key")
20
+ unsubscribes.add :email => "email@to.unsubscribe"
21
+
22
+ Two lines, and voila!
23
+
24
+ Common actions are documented below under each module. For more details, visit the [Sendgrid Web API Documentation][2]
25
+
26
+ Contributing
27
+ ------------
28
+
29
+ When submitting patches, please be sure you include rspec tests!
30
+
31
+ Big thanks to [James Brennan][1] for refactoring old code and writing the Bounces, InvalidEmails and SpamReports modules.
32
+
33
+ Bounces Module
34
+ --------------
35
+ The bounces module provides access to all of your bounces.
36
+
37
+ - - -
38
+
39
+ Instantiate the Bounces object:
40
+
41
+ bounces = SendgridToolkit::Bounces.new(api_user, api_key)
42
+
43
+ - - -
44
+
45
+ Retrieve bounces:
46
+
47
+ all_bounces = bounces.retrieve
48
+
49
+ `all_bounces` will be an array of hashes, each of which contains the following keys:
50
+
51
+ - `email`: the recipient's email address
52
+ - `status`: the status of email
53
+ - `reason`: the reason for the bounce, as specified by the recipient's email server
54
+
55
+ - - -
56
+
57
+ Get the timestamp of each bounce:
58
+
59
+ all_bounces = bounces.retrieve_with_timestamps
60
+
61
+ Each hash in `all_bounces` will now contain a `created` key, which holds a Ruby Time object.
62
+
63
+ - - -
64
+
65
+ If you believe an email address will no longer bounce and would like Sendgrid to deliver future emails to that address, you may delete the Bounce entry:
66
+
67
+ bounces.delete :email => "email@address.of.bounce.to.delete"
68
+
69
+ InvalidEmails Module
70
+ --------------------
71
+
72
+ The InvalidEmails module provides access to all of your email addresses.
73
+
74
+ - - -
75
+
76
+ Instantiate the InvalidEmails object:
77
+
78
+ invalid_emails_obj = SendgridToolkit::InvalidEmails.new(api_user, api_key)
79
+
80
+ - - -
81
+
82
+ Retrieve invalid emails:
83
+
84
+ invalid_emails = invalid_emails_obj.retrieve
85
+
86
+ `invalid_emails` will be an array of hashes, each of which contains the following keys:
87
+
88
+ - `email`: the recipient's email address
89
+ - `reason`: the reason the email address is believed to be invalid
90
+
91
+ - - -
92
+
93
+ Get the timestamp that each email was determined to be invalid:
94
+
95
+ invalid_emails = invalid_emails_obj.retrieve_with_timestamps
96
+
97
+ Each hash in `invalid_emails` will now contain a `created` key, which holds a Ruby Time object.
98
+
99
+ - - -
100
+
101
+ If you believe a once-invalid email address is now valid and would like Sendgrid to deliver future emails to that address, you may delete the InvalidEmail entry:
102
+
103
+ invalid_emails.delete :email => "email@address.of.invalid.to.delete"
104
+
105
+ SpamReports Module
106
+ ------------------
107
+
108
+ The SpamReports module provides access to all email addresses that have reported you for spam.
109
+
110
+ - - -
111
+
112
+ Instantiate the SpamReports object:
113
+
114
+ spam_reports_obj = SendgridToolkit::SpamReports.new(api_user, api_key)
115
+
116
+ - - -
117
+
118
+ Retrieve spam reports:
119
+
120
+ spam_reports = spam_reports_obj.retrieve
121
+
122
+ `spam_reports` will be an array of hashes, each of which contains an `email` key, indicating the email address that reported you for spam.
123
+
124
+ - - -
125
+
126
+ Get the timestamp of each spam report:
127
+
128
+ spam_reports = spam_reports_obj.retrieve_with_timestamps
129
+
130
+ Each hash in `spam_reports` will now contain a `created` key, which holds a Ruby Time object.
131
+
132
+ - - -
133
+
134
+ If you believe a user will no longer consider your content to be spam, you may delete the SpamReport entry:
135
+
136
+ spam_reports.delete :email => "email@address.that.called.you.a.spammer"
137
+
138
+ Statistics Module
139
+ -----------------
140
+ The statistics module provides access to all of your email statistics.
141
+
142
+ - - -
143
+
144
+ Instantiate the Statistics object:
145
+
146
+ statistics = SendgridToolkit::Statistics.new(api_user, api_key)
147
+
148
+ - - -
149
+
150
+ Retrieve statistics:
151
+
152
+ stats = statistics.retrieve
153
+
154
+ `stats` will be an array of hashes, each of which contains the following keys:
155
+
156
+ - `date`: The date to which the statistics in this hash refer to
157
+ - `requests`: The number of emails you sent
158
+ - `bounces`: The number of users who opened your email but did not click on your links
159
+ - `clicks`: The number of users who clicked on a link in your email
160
+ - `opens`: The number of users who opened your email
161
+ - `spamreports`: The number of users who have reported your emails as spam
162
+
163
+ `stats` may also contain some keys that Sendgrid does not officially document, such as: `delivered`, `invalid_email`, `repeat_bounces`,`+repeat_spamreports`, `repeat_unsubscribes` and `unsubscribes`
164
+
165
+ - - -
166
+
167
+ To narrow your retrieval to the past 5 days:
168
+
169
+ stats = statistics.retrieve :days => 5
170
+
171
+ To narrow your retrieval to emails within the last month but before one week ago:
172
+
173
+ stats = statistics.retrieve :start_date => 1.month.ago, :end_date => 1.week.ago
174
+
175
+ To narrow your search to a particular category (applicable only if you use this Sendgrid feature):
176
+
177
+ stats = statistics.retrieve :category => "NameOfYourCategory"
178
+
179
+ Note: You may combine a category query with other options, i.e.:
180
+
181
+ stats = statistics.retrieve :category => "NameOfYourCategory", :days => 5
182
+
183
+ - - -
184
+
185
+ Receive your all-time statistics:
186
+
187
+ stats = statistics.retrieve_aggregate
188
+
189
+ `stats` will be a single hash containing all of the aforementioned keys except `date`.
190
+
191
+ - - -
192
+
193
+ If you use Sendgrid's category feature, you can list your categories:
194
+
195
+ cats = statistics.list_categories
196
+
197
+ `cats` is an array of hashes, each of which has a `category` key that holds the name of a category.
198
+
199
+ Unsubscribes Module
200
+ -------------------
201
+ The unsubscribes module manages your list of unsubscribed email addresses.
202
+
203
+ - - -
204
+
205
+ Instantiate the Unsubscribes object:
206
+
207
+ unsubscribes = SendgridToolkit::Unsubscribes.new(api_user, api_key)
208
+
209
+ - - -
210
+
211
+ List everybody who has unsubscribed from your emails with:
212
+
213
+ listing = unsubscribes.retrieve
214
+ `listing` will be an array of hashes, each of which has an `email` key.
215
+
216
+ - - -
217
+
218
+ Get the timestamp when each user unsubscribed:
219
+
220
+ listing = unsubscribes.retrieve_with_timestamps
221
+
222
+ Each hash in `listing` will now contain a `created` key, which holds a Ruby Time object.
223
+
224
+ - - -
225
+
226
+ Unsubscribe a user from your sendgrid email:
227
+
228
+ unsubscribes.add :email => "email@to.unsubscribe"
229
+
230
+ SendgridToolkit will throw `UnsubscribeEmailAlreadyExists` if the email you specified is already on the list
231
+
232
+ - - -
233
+
234
+ Remove a user from your unsubscribe list:
235
+
236
+ unsubscribes.delete :email => "email@that_is.unsubscribed"
237
+
238
+ SendgridToolkit will throw `UnsubscribeEmailDoesNotExist` if the email you specified is not on the list
239
+
240
+
241
+ A note about authentication
242
+ ---------------------------
243
+
244
+ Each class is initialized with `api_user` and `api_key` parameters. `api_user` is your sendgrid account email address, and `api_key` is your sendgrid password.
245
+
246
+ If you don't supply `api_user` or `api_key`, SendgridToolkit will look for the `SMTP_USERNAME` or `SMTP_PASSWORD` environment variables. If they are not found, SendgridToolkit will throw `NoAPIKeySpecified` or `NoAPIUserSpecified`, depending on what you omitted.
247
+
248
+ If authentication fails during an API request, SendgridToolkit throws `AuthenticationFailed`.
249
+
250
+
251
+ In Case You're Curious...
252
+ -------------------------
253
+
254
+ API requests are made and responses are received in JSON. All requests are made as POSTs unless noted otherwise (Sendgrid's examples are via GET, but they support POST)
255
+
256
+ Each class takes a final options parameter in the form of a hash. You may use this parameter to pass additional options to the Sendgrid API. For example, let's say you are using the unsubscribes function:
257
+
258
+ unsubscribes = SendgridToolkit::Unsubscribes.new(api_user, api_key)
259
+ listing = unsubscribes.retrieve
260
+
261
+ If Sendgrid were to add a `only_verified` option to this API call, you could call:
262
+
263
+ listing = unsubscribes.retrieve :only_verified => true
264
+
265
+ to make use of it.
266
+
267
+ Testing
268
+ -------
269
+
270
+ In addition to unit tests, SendgridToolkit comes with a limited suite of "webconnect" tests that will actually hit Sendgrid's servers and perform various actions for purposes of real-world testing. In order to use these tests, you must:
271
+
272
+ 1. Create a test account with sendgrid and store the credentials in `TEST_SMTP_USERNAME` and `TEST_SMTP_PASSWORD` environment variables. This is so that actions are performed on a test account and not your real Sendgrid account. If you forget, don't worry -- the tests will fail but they will **not** fall back on the account that uses `SMTP_USERNAME` and `SMTP_PASSWORD`.
273
+ 2. Change "xit" it "it" on the tests you wish to run.
274
+
275
+ Running "spec spec" out of the box will run the standard suite of tests (all network access is stubbed out).
276
+
277
+ [1]: http://github.com/jamesBrennan
278
+ [2]: http://wiki.sendgrid.com/doku.php?id=web_api
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = "sendgrid_toolkit"
8
+ gemspec.summary = "A Ruby wrapper and utility library for communicating with the Sendgrid API"
9
+ gemspec.description = "A Ruby wrapper and utility library for communicating with the Sendgrid API"
10
+ gemspec.email = "robby@freerobby.com"
11
+ gemspec.homepage = "http://github.com/freerobby/sendgrid_toolkit"
12
+ gemspec.authors = ["Robby Grossman"]
13
+
14
+ gemspec.add_dependency "httparty"
15
+ # Development dependencies: fakeweb, rake, jeweler, rspec
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler must be installed. Use 'sudo gem install jeweler'."
20
+ end
21
+
22
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each {|ext| load ext}
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.5
@@ -0,0 +1,14 @@
1
+ require 'httparty'
2
+
3
+ require 'sendgrid_toolkit/abstract_sendgrid_client'
4
+ require 'sendgrid_toolkit/common'
5
+ require 'sendgrid_toolkit/sendgrid_error'
6
+ require 'sendgrid_toolkit/statistics'
7
+ require 'sendgrid_toolkit/unsubscribes'
8
+ require 'sendgrid_toolkit/spam_reports'
9
+ require 'sendgrid_toolkit/bounces'
10
+ require 'sendgrid_toolkit/invalid_emails'
11
+
12
+ module SendgridToolkit
13
+ BASE_URI = "sendgrid.com/api"
14
+ end
@@ -0,0 +1,38 @@
1
+ module SendgridToolkit
2
+ class AbstractSendgridClient
3
+
4
+ def initialize(api_user = nil, api_key = nil)
5
+ @api_user = (api_user.nil?) ? ENV['SMTP_USERNAME'] : api_user
6
+ @api_key = (api_key.nil?) ? ENV['SMTP_PASSWORD'] : api_key
7
+
8
+ raise SendgridToolkit::NoAPIUserSpecified if @api_user.blank?
9
+ raise SendgridToolkit::NoAPIKeySpecified if @api_key.blank?
10
+ end
11
+
12
+ protected
13
+
14
+ def api_post(module_name, action_name, opts = {})
15
+ response = HTTParty.post("https://#{BASE_URI}/#{module_name}.#{action_name}.json?", :query => get_credentials.merge(opts), :format => :json)
16
+ if response.code > 401
17
+ raise(SendgridToolkit::SendgridServerError, "The sengrid server returned an error. #{response.inspect}")
18
+ elsif has_error?(response) and
19
+ response['error'].respond_to?(:has_key?) and
20
+ response['error'].has_key?('code') and
21
+ response['error']['code'].to_i == 401
22
+ raise SendgridToolkit::AuthenticationFailed
23
+ elsif has_error?(response)
24
+ raise(SendgridToolkit::APIError, response['error'])
25
+ end
26
+ response
27
+ end
28
+
29
+ def get_credentials
30
+ {:api_user => @api_user, :api_key => @api_key}
31
+ end
32
+
33
+ private
34
+ def has_error?(response)
35
+ response.kind_of?(Hash) && response.has_key?('error')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ module SendgridToolkit
2
+
3
+ class Bounces < AbstractSendgridClient
4
+ include SendgridToolkit::Common
5
+ end
6
+
7
+ end
@@ -0,0 +1,43 @@
1
+ module SendgridToolkit
2
+
3
+ module Common
4
+
5
+ def retrieve(options = {})
6
+ response = api_post(module_name, 'get', options)
7
+ response
8
+ end
9
+
10
+ def retrieve_with_timestamps(options = {})
11
+ options.merge! :date => 1
12
+ response = retrieve options
13
+ if response.is_a? Array
14
+ response.each do |message|
15
+ parse_message_time message
16
+ end
17
+ else
18
+ parse_message_time response
19
+ end
20
+ response
21
+ end
22
+
23
+ def delete(options = {})
24
+ response = api_post(module_name, 'delete', options)
25
+ if !response["message"].nil?
26
+ raise EmailDoesNotExist if response['message'].include?('does not exist')
27
+ end
28
+ response
29
+ end
30
+
31
+ def module_name
32
+ self.class.to_s.split("::").last.downcase
33
+ end
34
+
35
+ private
36
+
37
+ def parse_message_time(message)
38
+ message['created'] = Time.parse(message['created']) if message.has_key?('created')
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,7 @@
1
+ module SendgridToolkit
2
+
3
+ class InvalidEmails < AbstractSendgridClient
4
+ include SendgridToolkit::Common
5
+ end
6
+
7
+ end
@@ -0,0 +1,10 @@
1
+ module SendgridToolkit
2
+ class AuthenticationFailed < StandardError; end
3
+ class NoAPIKeySpecified < StandardError; end
4
+ class NoAPIUserSpecified < StandardError; end
5
+ class UnsubscribeEmailAlreadyExists < StandardError; end
6
+ class UnsubscribeEmailDoesNotExist < StandardError; end
7
+ class EmailDoesNotExist < StandardError; end
8
+ class SendgridServerError < StandardError; end
9
+ class APIError < StandardError; end
10
+ end
@@ -0,0 +1,7 @@
1
+ module SendgridToolkit
2
+
3
+ class SpamReports < AbstractSendgridClient
4
+ include SendgridToolkit::Common
5
+ end
6
+
7
+ end
@@ -0,0 +1,31 @@
1
+ module SendgridToolkit
2
+ class Statistics < AbstractSendgridClient
3
+ def retrieve(options = {})
4
+ response = api_post('stats', 'get', options)
5
+ response
6
+ end
7
+
8
+ def retrieve_aggregate(options = {})
9
+ options.merge! :aggregate => 1
10
+ response = retrieve options
11
+ if Hash === response.parsed_response
12
+ to_ints(response.parsed_response)
13
+ elsif Array === response.parsed_response
14
+ response.parsed_response.each {|o| to_ints(o) }
15
+ end
16
+ response
17
+ end
18
+
19
+ def to_ints(resp)
20
+ %w(bounces clicks delivered invalid_email opens repeat_bounces repeat_spamreports repeat_unsubscribes requests spamreports unsubscribes).each do |int_field|
21
+ resp[int_field] = resp[int_field].to_i if resp.has_key?(int_field)
22
+ end
23
+ end
24
+
25
+ def list_categories(options = {})
26
+ options.merge! :list => true
27
+ response = retrieve options
28
+ response
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module SendgridToolkit
2
+ class Unsubscribes < AbstractSendgridClient
3
+ def add(options = {})
4
+ response = api_post('unsubscribes', 'add', options)
5
+ raise UnsubscribeEmailAlreadyExists if response['message'].include?('already exists')
6
+ response
7
+ end
8
+
9
+ def delete(options = {})
10
+ response = api_post('unsubscribes', 'delete', options)
11
+ raise UnsubscribeEmailDoesNotExist if response['message'].include?('does not exist')
12
+ response
13
+ end
14
+
15
+ def retrieve(options = {})
16
+ response = api_post('unsubscribes', 'get', options)
17
+ response
18
+ end
19
+
20
+ def retrieve_with_timestamps(options = {})
21
+ options.merge! :date => 1
22
+ response = retrieve options
23
+ response.each do |unsubscribe|
24
+ unsubscribe['created'] = Time.parse(unsubscribe['created']) if unsubscribe.has_key?('created')
25
+ end
26
+ response
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,60 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{eliasbaixas-sendgrid_toolkit}
8
+ s.version = "1.0.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Robby Grossman}]
12
+ s.date = %q{2011-09-19}
13
+ s.description = %q{A Ruby wrapper and utility library for communicating with the Sendgrid API}
14
+ s.email = %q{robby@freerobby.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ "README.md",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "lib/sendgrid_toolkit.rb",
23
+ "lib/sendgrid_toolkit/abstract_sendgrid_client.rb",
24
+ "lib/sendgrid_toolkit/bounces.rb",
25
+ "lib/sendgrid_toolkit/common.rb",
26
+ "lib/sendgrid_toolkit/invalid_emails.rb",
27
+ "lib/sendgrid_toolkit/sendgrid_error.rb",
28
+ "lib/sendgrid_toolkit/spam_reports.rb",
29
+ "lib/sendgrid_toolkit/statistics.rb",
30
+ "lib/sendgrid_toolkit/unsubscribes.rb",
31
+ "sendgrid_toolkit.gemspec",
32
+ "spec/helper.rb",
33
+ "spec/lib/sendgrid_toolkit/abstract_sendgrid_client_spec.rb",
34
+ "spec/lib/sendgrid_toolkit/bounces_spec.rb",
35
+ "spec/lib/sendgrid_toolkit/common_spec.rb",
36
+ "spec/lib/sendgrid_toolkit/invalid_emails_spec.rb",
37
+ "spec/lib/sendgrid_toolkit/spam_reports_spec.rb",
38
+ "spec/lib/sendgrid_toolkit/statistics_spec.rb",
39
+ "spec/lib/sendgrid_toolkit/unsubscribes_spec.rb",
40
+ "spec/lib/sendgrid_toolkit_spec.rb",
41
+ "spec/webconnect/sendgrid_toolkit_spec.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/freerobby/sendgrid_toolkit}
44
+ s.require_paths = [%q{lib}]
45
+ s.rubygems_version = %q{1.8.6}
46
+ s.summary = %q{A Ruby wrapper and utility library for communicating with the Sendgrid API}
47
+
48
+ if s.respond_to? :specification_version then
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
+ s.add_runtime_dependency(%q<httparty>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<httparty>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<httparty>, [">= 0"])
58
+ end
59
+ end
60
+
@@ -0,0 +1,13 @@
1
+ require 'fakeweb'
2
+ require 'sendgrid_toolkit'
3
+ require 'spec'
4
+
5
+ FakeWeb.allow_net_connect = false
6
+
7
+ def backup_env
8
+ @env_backup = Hash.new
9
+ ENV.keys.each {|key| @env_backup[key] = ENV[key]}
10
+ end
11
+ def restore_env
12
+ @env_backup.keys.each {|key| ENV[key] = @env_backup[key]}
13
+ end
@@ -0,0 +1,69 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::AbstractSendgridClient do
4
+ before do
5
+ backup_env
6
+ end
7
+ after do
8
+ restore_env
9
+ end
10
+
11
+ describe "#api_post" do
12
+ it "throws error when authentication fails" do
13
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/profile\.get\.json\?|, :body => '{"error":{"code":401,"message":"Permission denied, wrong credentials"}}')
14
+ @obj = SendgridToolkit::AbstractSendgridClient.new("fakeuser", "fakepass")
15
+ lambda {
16
+ @obj.send(:api_post, "profile", "get", {})
17
+ }.should raise_error SendgridToolkit::AuthenticationFailed
18
+ end
19
+ it "thows error when sendgrid response is a server error" do
20
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/profile\.get\.json\?|, :body => 'A server error occured', :status => ['500', 'Internal Server Error'])
21
+ @obj = SendgridToolkit::AbstractSendgridClient.new("someuser", "somepass")
22
+ lambda {
23
+ @obj.send(:api_post, "profile", "get", {})
24
+ }.should raise_error SendgridToolkit::SendgridServerError
25
+ end
26
+ it "thows error when sendgrid response is an API error" do
27
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/stats\.get\.json\?|, :body => '{"error": "error in end_date: end date is in the future"}', :status => ['400', 'Bad Request'])
28
+ @obj = SendgridToolkit::AbstractSendgridClient.new("someuser", "somepass")
29
+ lambda {
30
+ @obj.send(:api_post, "stats", "get", {})
31
+ }.should raise_error SendgridToolkit::APIError
32
+ end
33
+ end
34
+
35
+ describe "#initialize" do
36
+ it "stores api credentials when passed in" do
37
+ ENV['SMTP_USERNAME'] = "env_username"
38
+ ENV['SMTP_PASSWORD'] = "env_apikey"
39
+
40
+ @obj = SendgridToolkit::AbstractSendgridClient.new("username", "apikey")
41
+ @obj.instance_variable_get("@api_user").should == "username"
42
+ @obj.instance_variable_get("@api_key").should == "apikey"
43
+ end
44
+ it "resorts to environment variables when no credentials specified" do
45
+ ENV['SMTP_USERNAME'] = "env_username"
46
+ ENV['SMTP_PASSWORD'] = "env_apikey"
47
+
48
+ @obj = SendgridToolkit::AbstractSendgridClient.new()
49
+ @obj.instance_variable_get("@api_user").should == "env_username"
50
+ @obj.instance_variable_get("@api_key").should == "env_apikey"
51
+ end
52
+ it "throws error when no credentials are found" do
53
+ ENV['SMTP_USERNAME'] = nil
54
+ ENV['SMTP_PASSWORD'] = nil
55
+
56
+ lambda {
57
+ @obj = SendgridToolkit::AbstractSendgridClient.new()
58
+ }.should raise_error SendgridToolkit::NoAPIUserSpecified
59
+
60
+ lambda {
61
+ @obj = SendgridToolkit::AbstractSendgridClient.new(nil, "password")
62
+ }.should raise_error SendgridToolkit::NoAPIUserSpecified
63
+
64
+ lambda {
65
+ @obj = SendgridToolkit::AbstractSendgridClient.new("user", nil)
66
+ }.should raise_error SendgridToolkit::NoAPIKeySpecified
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::Bounces do
4
+ before do
5
+ FakeWeb.clean_registry
6
+ @obj = SendgridToolkit::Bounces.new("fakeuser", "fakepass")
7
+ end
8
+
9
+ describe "#retrieve" do
10
+ it "returns array of bounced emails" do
11
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/bounces\.get\.json\?|, :body => '[{"email":"email1@domain.com","status":"5.1.1","reason":"host [127.0.0.1] said: 550 5.1.1 unknown or illegal user: email1@domain.com"},{"email":"email2@domain2.com","status":"5.1.1","reason":"host [127.0.0.1] said: 550 5.1.1 unknown or illegal user: email2@domain2.com"}]')
12
+ bounces = @obj.retrieve
13
+ bounces[0]['email'].should == "email1@domain.com"
14
+ bounces[0]['status'].should == "5.1.1"
15
+ bounces[0]['reason'].should == "host [127.0.0.1] said: 550 5.1.1 unknown or illegal user: email1@domain.com"
16
+ end
17
+ end
18
+
19
+ describe "#retrieve_with_timestamps" do
20
+ it "parses timestamps" do
21
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/bounces\.get\.json\?.*date=1|, :body => '[{"email":"email1@domain.com","status":"5.1.1","reason":"host [127.0.0.1] said: 550 5.1.1 unknown or illegal user: email1@domain.com","created":"2009-06-01 19:41:39"},{"email":"email2@domain2.com","status":"5.1.1","reason":"host [127.0.0.1] said: 550 5.1.1 unknown or illegal user: email2@domain2.com","created":"2009-06-12 19:41:39"}]')
22
+ bounces = @obj.retrieve_with_timestamps
23
+ 0.upto(1) do |index|
24
+ bounces[index]['created'].kind_of?(Time).should == true
25
+ end
26
+ bounces[0]['created'].asctime.should == "Mon Jun 1 19:41:39 2009"
27
+ bounces[1]['created'].asctime.should == "Fri Jun 12 19:41:39 2009"
28
+ end
29
+ end
30
+
31
+ describe "#delete" do
32
+ it "raises no errors on success" do
33
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/bounces\.delete\.json\?.*email=.+|, :body => '{"message":"success"}')
34
+ lambda {
35
+ @obj.delete :email => "user@domain.com"
36
+ }.should_not raise_error
37
+ end
38
+ it "raises error when email address does not exist" do
39
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/bounces\.delete\.json\?.*email=.+|, :body => '{"message":"Email does not exist"}')
40
+ lambda {
41
+ @obj.delete :email => "user@domain.com"
42
+ }.should raise_error SendgridToolkit::EmailDoesNotExist
43
+ end
44
+ it "does not choke if response does not have a 'message' field" do
45
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/bounces\.delete\.json\?.*email=.+|, :body => 'An internal server error occurred. Please try again later.')
46
+ lambda {
47
+ @obj.delete :email => "user@domain.com"
48
+ }.should_not raise_error
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::Common do
4
+
5
+ before do
6
+ class FakeClass < SendgridToolkit::AbstractSendgridClient
7
+ include SendgridToolkit::Common
8
+ end
9
+ @fake_class = FakeClass.new
10
+ end
11
+
12
+ it "creates a module_name method that returns the class name downcased" do
13
+ @fake_class.module_name.should == "fakeclass"
14
+ end
15
+
16
+ it "does not choke if response does not have a 'message' field" do
17
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/fakeclass\.delete\.json\?.*email=.+|, :body => 'An internal server error occurred. Please try again later.')
18
+ lambda {
19
+ @fake_class.delete :email => "user@domain.com"
20
+ }.should_not raise_error
21
+ end
22
+
23
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::InvalidEmails do
4
+ before do
5
+ FakeWeb.clean_registry
6
+ @obj = SendgridToolkit::InvalidEmails.new("fakeuser", "fakepass")
7
+ end
8
+
9
+ describe "#retrieve" do
10
+ it "returns array of invalid emails" do
11
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/invalidemails\.get\.json\?|, :body => '[{"email":"isaac@hotmail.comm","reason":"Mail domain mentioned in email address is unknown"},{"email":"isaac@hotmail","reason":"Bad Syntax"},{"email":"isaac@example.com","reason":"Known bad domain"}]')
12
+ invalid_emails = @obj.retrieve
13
+ invalid_emails[0]['email'].should == "isaac@hotmail.comm"
14
+ invalid_emails[0]['reason'].should == "Mail domain mentioned in email address is unknown"
15
+ invalid_emails[1]['email'].should == "isaac@hotmail"
16
+ invalid_emails[1]['reason'].should == "Bad Syntax"
17
+ invalid_emails[2]['email'].should == "isaac@example.com"
18
+ invalid_emails[2]['reason'].should == "Known bad domain"
19
+ end
20
+ end
21
+
22
+ describe "#retrieve_with_timestamps" do
23
+ it "parses timestamps" do
24
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/invalidemails\.get\.json\?.*date=1|, :body => '[{"email":"isaac@hotmail.comm","reason":"Mail domain mentioned in email address is unknown","created":"2009-06-01 19:41:39"},{"email":"isaac@hotmail","reason":"Bad Syntax","created":"2009-06-12 19:41:39"},{"email":"isaac@example.com","reason":"Known bad domain","created":"2009-06-13 09:40:01"}]')
25
+ invalid_emails = @obj.retrieve_with_timestamps
26
+ 0.upto(2) do |index|
27
+ invalid_emails[index]['created'].kind_of?(Time).should == true
28
+ end
29
+ invalid_emails[0]['created'].asctime.should == "Mon Jun 1 19:41:39 2009"
30
+ invalid_emails[1]['created'].asctime.should == "Fri Jun 12 19:41:39 2009"
31
+ invalid_emails[2]['created'].asctime.should == "Sat Jun 13 09:40:01 2009"
32
+ end
33
+ end
34
+
35
+ describe "#delete" do
36
+ it "raises no errors on success" do
37
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/invalidemails\.delete\.json\?.*email=.+|, :body => '{"message":"success"}')
38
+ lambda {
39
+ @obj.delete :email => "user@domain.com"
40
+ }.should_not raise_error
41
+ end
42
+ it "raises error when email address does not exist" do
43
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/invalidemails\.delete\.json\?.*email=.+|, :body => '{"message":"Email does not exist"}')
44
+ lambda {
45
+ @obj.delete :email => "user@domain.com"
46
+ }.should raise_error SendgridToolkit::EmailDoesNotExist
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::SpamReports do
4
+ before do
5
+ FakeWeb.clean_registry
6
+ @obj = SendgridToolkit::SpamReports.new("fakeuser", "fakepass")
7
+ end
8
+
9
+ describe "#retrieve" do
10
+ it "returns array of bounced emails" do
11
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/spamreports\.get\.json\?|, :body => '[{"email":"email1@domain.com"},{"email":"email2@domain2.com"}]')
12
+ bounces = @obj.retrieve
13
+ bounces[0]['email'].should == "email1@domain.com"
14
+ bounces[1]['email'].should == "email2@domain2.com"
15
+ end
16
+ end
17
+
18
+ describe "#retrieve_with_timestamps" do
19
+ it "parses timestamps" do
20
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/spamreports\.get\.json\?.*date=1|, :body => '[{"email":"email1@domain.com","created":"2009-06-01 19:41:39"},{"email":"email2@domain2.com","created":"2009-06-12 19:41:39"}]')
21
+ bounces = @obj.retrieve_with_timestamps
22
+ 0.upto(1) do |index|
23
+ bounces[index]['created'].kind_of?(Time).should == true
24
+ end
25
+ bounces[0]['created'].asctime.should == "Mon Jun 1 19:41:39 2009"
26
+ bounces[1]['created'].asctime.should == "Fri Jun 12 19:41:39 2009"
27
+ end
28
+ end
29
+
30
+ describe "#delete" do
31
+ it "raises no errors on success" do
32
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/spamreports\.delete\.json\?.*email=.+|, :body => '{"message":"success"}')
33
+ lambda {
34
+ @obj.delete :email => "user@domain.com"
35
+ }.should_not raise_error
36
+ end
37
+ it "raises error when email address does not exist" do
38
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/spamreports\.delete\.json\?.*email=.+|, :body => '{"message":"Email does not exist"}')
39
+ lambda {
40
+ @obj.delete :email => "user@domain.com"
41
+ }.should raise_error SendgridToolkit::EmailDoesNotExist
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,41 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::Statistics do
4
+ before do
5
+ FakeWeb.clean_registry
6
+ @obj = SendgridToolkit::Statistics.new("fakeuser", "fakepass")
7
+ end
8
+
9
+ describe "#retrieve" do
10
+ it "parses daily totals" do
11
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/stats\.get\.json\?|, :body => '[{"date":"2009-06-20","requests":12342,"bounces":12,"clicks":10223,"opens":9992,"spamreports":5},{"date":"2009-06-21","requests":32342,"bounces":10,"clicks":14323,"opens":10995,"spamreports":7},{"date":"2009-06-22","requests":52342,"bounces":11,"clicks":19223,"opens":12992,"spamreports":2}]')
12
+ stats = @obj.retrieve
13
+ stats.each do |stat|
14
+ %w(bounces clicks delivered invalid_email opens repeat_bounces repeat_spamreports repeat_unsubscribes requests spamreports unsubscribes).each do |int|
15
+ stat[int].kind_of?(Integer).should == true if stat.has_key?(int) # We support all fields presently returned, but we are only testing what sendgrid officially documents
16
+ end
17
+ stat['date'].kind_of?(Date).should == true
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "#retrieve_aggregate" do
23
+ it "parses aggregate statistics" do
24
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/stats\.get\.json\?.*aggregate=1|, :body => '{"requests":12342,"bounces":12,"clicks":10223,"opens":9992,"spamreports":5}')
25
+ stats = @obj.retrieve_aggregate
26
+ %w(bounces clicks delivered invalid_email opens repeat_bounces repeat_spamreports repeat_unsubscribes requests spamreports unsubscribes).each do |int|
27
+ stats[int].kind_of?(Integer).should == true if stats.has_key?(int) # We support all fields presently returned, but we are only testing what sendgrid officially documents
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#list_categories" do
33
+ it "parses categories list" do
34
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/stats\.get\.json\?.*list=true|, :body => '[{"category":"categoryA"},{"category":"categoryB"},{"category":"categoryC"}]')
35
+ cats = @obj.list_categories
36
+ cats[0]['category'].should == 'categoryA'
37
+ cats[1]['category'].should == 'categoryB'
38
+ cats[2]['category'].should == 'categoryC'
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../helper")
2
+
3
+ describe SendgridToolkit::Unsubscribes do
4
+ before do
5
+ FakeWeb.clean_registry
6
+ @obj = SendgridToolkit::Unsubscribes.new("fakeuser", "fakepass")
7
+ end
8
+
9
+ describe "#retrieve" do
10
+ it "returns array of unsubscribed email addresses" do
11
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/unsubscribes\.get\.json\?|, :body => '[{"email":"user@domain.com"},{"email":"user2@domain2.com"},{"email":"user3@domain2.com"}]')
12
+ emails = @obj.retrieve
13
+ emails[0]['email'].should == "user@domain.com"
14
+ emails[1]['email'].should == "user2@domain2.com"
15
+ emails[2]['email'].should == "user3@domain2.com"
16
+ end
17
+ end
18
+ describe "#retrieve_with_timestamps" do
19
+ it "parses timestamps" do
20
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/unsubscribes\.get\.json\?.*date=1|, :body => '[{"email":"user@domain.com","created":"2010-03-03 11:00:00"},{"email":"user2@domain2.com","created":"2010-03-04 21:00:00"},{"email":"user3@domain2.com","created":"2010-03-05 23:00:00"}]')
21
+ emails = @obj.retrieve_with_timestamps
22
+ 0.upto(2) do |index|
23
+ emails[index]['created'].kind_of?(Time).should == true
24
+ end
25
+ emails[0]['created'].asctime.should == "Wed Mar 3 11:00:00 2010"
26
+ emails[1]['created'].asctime.should == "Thu Mar 4 21:00:00 2010"
27
+ emails[2]['created'].asctime.should == "Fri Mar 5 23:00:00 2010"
28
+ end
29
+ end
30
+
31
+ describe "#add" do
32
+ it "raises no errors on success" do
33
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/unsubscribes\.add\.json\?.*email=.+|, :body => '{"message":"success"}')
34
+ lambda {
35
+ @obj.add :email => "user@domain.com"
36
+ }.should_not raise_error
37
+ end
38
+ it "raises error when email already exists" do
39
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/unsubscribes\.add\.json\?.*email=.+|, :body => '{"message":"Unsubscribe email address already exists"}')
40
+ lambda {
41
+ @obj.add :email => "user@domain.com"
42
+ }.should raise_error SendgridToolkit::UnsubscribeEmailAlreadyExists
43
+ end
44
+ end
45
+
46
+ describe "#delete" do
47
+ it "raises no errors on success" do
48
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/unsubscribes\.delete\.json\?.*email=.+|, :body => '{"message":"success"}')
49
+ lambda {
50
+ @obj.delete :email => "user@domain.com"
51
+ }.should_not raise_error
52
+ end
53
+ it "raises error when email address does not exist" do
54
+ FakeWeb.register_uri(:post, %r|https://sendgrid\.com/api/unsubscribes\.delete\.json\?.*email=.+|, :body => '{"message":"Email does not exist"}')
55
+ lambda {
56
+ @obj.delete :email => "user@domain.com"
57
+ }.should raise_error SendgridToolkit::UnsubscribeEmailDoesNotExist
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe SendgridToolkit do
4
+ end
@@ -0,0 +1,74 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ FakeWeb.allow_net_connect = true
4
+
5
+ describe SendgridToolkit do
6
+ before :all do
7
+ FakeWeb.clean_registry
8
+ FakeWeb.allow_net_connect = true
9
+ end
10
+ after :all do
11
+ FakeWeb.allow_net_connect = false
12
+ end
13
+
14
+ before do
15
+ backup_env
16
+
17
+ # Don't let SendgridToolkit fall back to SMTP_USERNAME and SMTP_PASSWORD
18
+ ENV['SMTP_USERNAME'] = ENV['TEST_SMTP_USERNAME'].blank? ? "fakeuser" : ENV['TEST_SMTP_USERNAME']
19
+ ENV['SMTP_PASSWORD'] = ENV['TEST_SMTP_PASSWORD'].blank? ? "fakepass" : ENV['TEST_SMTP_PASSWORD']
20
+ end
21
+ after do
22
+ restore_env
23
+ end
24
+
25
+ describe "abstract_sendgrid_client i/o" do
26
+ xit "throws authentication error when authentication fails" do
27
+ @obj = SendgridToolkit::AbstractSendgridClient.new("fakeuser", "fakepass")
28
+ lambda {
29
+ @obj.send(:api_post, "profile", "get", {})
30
+ }.should raise_error SendgridToolkit::AuthenticationFailed
31
+ end
32
+ end
33
+
34
+ describe "statistics i/o" do
35
+ before do
36
+ @obj = SendgridToolkit::Statistics.new
37
+ end
38
+ xit "retrieves statistics by day" do
39
+ stats = @obj.retrieve
40
+ stats.count.should > 0
41
+ day_stats = stats.first
42
+ %w(date requests bounces clicks opens spamreports).each do |k|
43
+ day_stats.has_key?(k).should == true
44
+ end
45
+ end
46
+ xit "retrieves aggregate statistics" do
47
+ stats = @obj.retrieve_aggregate
48
+ %w(requests bounces clicks opens spamreports).each do |k|
49
+ stats.has_key?(k).should == true
50
+ end
51
+ end
52
+ end
53
+
54
+ describe "unsubscribes i/o" do
55
+ before do
56
+ @obj = SendgridToolkit::Unsubscribes.new
57
+ unsubscribes = @obj.retrieve
58
+ unsubscribes.each do |u|
59
+ @obj.delete u['email']
60
+ end
61
+ end
62
+ xit "adds, retrieves and deletes email addresses properly" do
63
+ @obj.add "user@domain.com"
64
+ @obj.add "user2@domain.com"
65
+ unsubs = @obj.retrieve_with_timestamps
66
+ emails = unsubs.map {|h| h['email']}
67
+ emails.include?('user@domain.com').should == true
68
+ emails.include?('user2@domain.com').should == true
69
+ @obj.delete 'user@domain.com'
70
+ @obj.delete 'user2@domain.com'
71
+ @obj.retrieve.count.should == 0
72
+ end
73
+ end
74
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eliasbaixas-sendgrid_toolkit
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 5
10
+ version: 1.0.5
11
+ platform: ruby
12
+ authors:
13
+ - Robby Grossman
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-19 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: httparty
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: A Ruby wrapper and utility library for communicating with the Sendgrid API
35
+ email: robby@freerobby.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.md
42
+ files:
43
+ - README.md
44
+ - Rakefile
45
+ - VERSION
46
+ - lib/sendgrid_toolkit.rb
47
+ - lib/sendgrid_toolkit/abstract_sendgrid_client.rb
48
+ - lib/sendgrid_toolkit/bounces.rb
49
+ - lib/sendgrid_toolkit/common.rb
50
+ - lib/sendgrid_toolkit/invalid_emails.rb
51
+ - lib/sendgrid_toolkit/sendgrid_error.rb
52
+ - lib/sendgrid_toolkit/spam_reports.rb
53
+ - lib/sendgrid_toolkit/statistics.rb
54
+ - lib/sendgrid_toolkit/unsubscribes.rb
55
+ - sendgrid_toolkit.gemspec
56
+ - spec/helper.rb
57
+ - spec/lib/sendgrid_toolkit/abstract_sendgrid_client_spec.rb
58
+ - spec/lib/sendgrid_toolkit/bounces_spec.rb
59
+ - spec/lib/sendgrid_toolkit/common_spec.rb
60
+ - spec/lib/sendgrid_toolkit/invalid_emails_spec.rb
61
+ - spec/lib/sendgrid_toolkit/spam_reports_spec.rb
62
+ - spec/lib/sendgrid_toolkit/statistics_spec.rb
63
+ - spec/lib/sendgrid_toolkit/unsubscribes_spec.rb
64
+ - spec/lib/sendgrid_toolkit_spec.rb
65
+ - spec/webconnect/sendgrid_toolkit_spec.rb
66
+ homepage: http://github.com/freerobby/sendgrid_toolkit
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options: []
71
+
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.10
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A Ruby wrapper and utility library for communicating with the Sendgrid API
99
+ test_files: []
100
+