sailthru 1.0.0
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.
- data/.gitignore +3 -0
- data/README.txt +27 -0
- data/VERSION +1 -0
- data/lib/sailthru/client.rb +94 -0
- data/lib/sailthru/triggermail_client.rb +351 -0
- data/sailthru.gemspec +36 -0
- metadata +67 -0
data/.gitignore
ADDED
data/README.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
= sailthru
|
2
|
+
|
3
|
+
== DESCRIPTION:
|
4
|
+
|
5
|
+
Sailthru Triggermail Client, with some added bonus features and simpler integration with your Rails stack, including YML config for keys and mailing list name.
|
6
|
+
|
7
|
+
== INSTALLATION:
|
8
|
+
|
9
|
+
$ gem install sailthru
|
10
|
+
|
11
|
+
== USAGE:
|
12
|
+
|
13
|
+
= Include in your app.
|
14
|
+
|
15
|
+
require 'sailthru/client'
|
16
|
+
|
17
|
+
= Set your configuration in RAILS_ROOT/config/sailthru.yml.
|
18
|
+
|
19
|
+
api_key: YOUR_API_KEY
|
20
|
+
secret: YOUR_SECRET
|
21
|
+
api_uri: http://api.sailthru.com
|
22
|
+
mailing_list_key: mailing_list
|
23
|
+
|
24
|
+
= Make calls to Sailthru as you would with the normal triggermail client:
|
25
|
+
|
26
|
+
client = Sailthru::Client.new
|
27
|
+
client.send(...)
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'sailthru/triggermail_client'
|
2
|
+
|
3
|
+
module Sailthru
|
4
|
+
class Client
|
5
|
+
def initialize
|
6
|
+
@config = YAML.load(File.read(Rails.root + 'config' + 'sailthru.yml'))
|
7
|
+
@client = Sailthru::TriggermailClient.new(
|
8
|
+
@config['api_key'],
|
9
|
+
@config['secret'],
|
10
|
+
@config['api_uri'] || 'http://api.sailthru.com'
|
11
|
+
)
|
12
|
+
rescue Exception => ex
|
13
|
+
raise Exception.new(
|
14
|
+
"Please create a sailthru.yml file in your root config directory, containing api_key, secret, optional api_uri and optional mailing_list_key"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Additional Helper Methods
|
19
|
+
|
20
|
+
def toggle_email_in_mailing_list(email, wants_email, vars={})
|
21
|
+
if !email.blank?
|
22
|
+
wants_email ? add_to_mailing_list(email, vars) : remove_from_mailing_list(email, vars)
|
23
|
+
end
|
24
|
+
rescue Exception => e
|
25
|
+
puts "EXCEPTION from Sailthru: #{e}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_to_mailing_list(email, vars)
|
29
|
+
return @client.set_email(email, normalize_vars(vars), {mailing_list_key => 1}, {})
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove_from_mailing_list(email, vars)
|
33
|
+
return @client.set_email(email, normalize_vars(vars), {mailing_list_key => 0}, {})
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sailthru Triggermail Client passthru methods.
|
37
|
+
|
38
|
+
def send(template_name, email, vars, options = {}, schedule_time = nil)
|
39
|
+
@client.send(template_name, email, vars, options, schedule_time)
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_send(send_id)
|
43
|
+
@client.get_send(send_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def schedule_blast(name, list, schedule_time, from_name, from_email, subject, content_html, content_text, options)
|
47
|
+
@client.schedule_blast(name, list, schedule_time, from_name, from_email, subject, content_html, content_text, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_blast(blast_id)
|
51
|
+
@client.get_blast(blast_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_email(email)
|
55
|
+
@client.get_email(email)
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_email(email, vars = {}, lists = {}, templates = {})
|
59
|
+
@client.set_email(email, vars, lists, templates)
|
60
|
+
end
|
61
|
+
|
62
|
+
def import_contacts(email, password, with_names = false)
|
63
|
+
@client.import_contacts(email, password, with_names)
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_template(template_name)
|
67
|
+
@client.get_template(template_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def save_template(template_name, template_fields)
|
71
|
+
@client.save_template(template_name, template_fields)
|
72
|
+
end
|
73
|
+
|
74
|
+
def receive_verify_post(params, request)
|
75
|
+
@client.receive_verify_post(params, request)
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
def normalize_vars(vars)
|
80
|
+
result = {:first_name => "", :last_name => ""}
|
81
|
+
result[:first_name] = vars[:first_name] if vars_has_this?(vars, :first_name)
|
82
|
+
result[:last_name] = vars[:last_name] if vars_has_this?(vars, :last_name)
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
def vars_has_this?(vars, key)
|
87
|
+
return vars.has_key?(key) && !vars[key].blank?
|
88
|
+
end
|
89
|
+
|
90
|
+
def mailing_list_key
|
91
|
+
@config['mailing_list_key'] || 'main_list'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Triggermail API Ruby Client
|
3
|
+
################################################################################
|
4
|
+
#
|
5
|
+
# A simple client library to remotely access the Triggermail REST API.
|
6
|
+
#
|
7
|
+
################################################################################
|
8
|
+
#
|
9
|
+
# Copyright (c) 2007 Sailthru, Inc.
|
10
|
+
# All rights reserved.
|
11
|
+
#
|
12
|
+
# Special thanks to the iminlikewithyou.com team for the development
|
13
|
+
# of this library.
|
14
|
+
#
|
15
|
+
# Redistribution and use in source and binary forms, with or without
|
16
|
+
# modification, are permitted provided that the following conditions
|
17
|
+
# are met:
|
18
|
+
#
|
19
|
+
# 1. Redistributions of source code must retain the above copyright
|
20
|
+
# notice, this list of conditions and the following disclaimer.
|
21
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
22
|
+
# notice, this list of conditions and the following disclaimer in the
|
23
|
+
# documentation and/or other materials provided with the distribution.
|
24
|
+
#
|
25
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
26
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
27
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
28
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
29
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
30
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
31
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
32
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
33
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
34
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
#
|
36
|
+
################################################################################
|
37
|
+
|
38
|
+
require 'net/http'
|
39
|
+
require 'uri'
|
40
|
+
require 'rubygems'
|
41
|
+
require 'json'
|
42
|
+
require 'md5'
|
43
|
+
|
44
|
+
module Sailthru
|
45
|
+
|
46
|
+
class TriggermailClientException < Exception
|
47
|
+
end
|
48
|
+
|
49
|
+
class TriggermailClient
|
50
|
+
attr_accessor :api_uri, :api_key, :secret, :version, :last_request
|
51
|
+
|
52
|
+
VERSION = '1.0'
|
53
|
+
|
54
|
+
# params:
|
55
|
+
# api_key, String
|
56
|
+
# secret, String
|
57
|
+
# api_uri, String
|
58
|
+
#
|
59
|
+
# Instantiate a new client; constructor optionally takes overrides for key/secret/uri.
|
60
|
+
def initialize(api_key, secret, api_uri)
|
61
|
+
@api_key = api_key
|
62
|
+
@secret = secret
|
63
|
+
@api_uri = api_uri
|
64
|
+
end
|
65
|
+
|
66
|
+
# params:
|
67
|
+
# template_name, String
|
68
|
+
# email, String
|
69
|
+
# replacements, Hash
|
70
|
+
# options, Hash
|
71
|
+
# replyto: override Reply-To header
|
72
|
+
# test: send as test email (subject line will be marked, will not count towards stats)
|
73
|
+
# schedule_time, String (see schedule_blast schedule_time in API docs)
|
74
|
+
# returns:
|
75
|
+
# Hash, response data from server
|
76
|
+
def send(template_name, email, vars, options = {}, schedule_time = nil)
|
77
|
+
post = {}
|
78
|
+
post[:template] = template_name
|
79
|
+
post[:email] = email
|
80
|
+
post[:vars] = vars
|
81
|
+
post[:options] = options
|
82
|
+
post[:schedule_time] = schedule_time if schedule_time
|
83
|
+
result = self.api_post(:send, post)
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# params:
|
88
|
+
# send_id, Fixnum
|
89
|
+
# returns:
|
90
|
+
# Hash, response data from server
|
91
|
+
#
|
92
|
+
# Get the status of a send.
|
93
|
+
def get_send(send_id)
|
94
|
+
self.api_get(:send, {:send_id => send_id.to_s})
|
95
|
+
end
|
96
|
+
|
97
|
+
# params:
|
98
|
+
# name, String
|
99
|
+
# list, String
|
100
|
+
# schedule_time, String
|
101
|
+
# from_name, String
|
102
|
+
# from_email, String
|
103
|
+
# subject, String
|
104
|
+
# content_html, String
|
105
|
+
# content_text, String
|
106
|
+
# options, Hash
|
107
|
+
# returns:
|
108
|
+
# Hash, response data from server
|
109
|
+
#
|
110
|
+
# Schedule a mass mail blast
|
111
|
+
def schedule_blast(name, list, schedule_time, from_name, from_email, subject, content_html, content_text, options)
|
112
|
+
post = options ? options : {}
|
113
|
+
post[:name] = name
|
114
|
+
post[:list] = list
|
115
|
+
post[:schedule_time] = schedule_time
|
116
|
+
post[:from_name] = from_name
|
117
|
+
post[:from_email] = from_email
|
118
|
+
post[:subject] = subject
|
119
|
+
post[:content_html] = content_html
|
120
|
+
post[:content_text] = content_text
|
121
|
+
self.api_post(:blast, post)
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# params:
|
126
|
+
# blast_id, Fixnum
|
127
|
+
# returns:
|
128
|
+
# Hash, response data from server
|
129
|
+
#
|
130
|
+
# Get information on a previously scheduled email blast
|
131
|
+
def get_blast(blast_id)
|
132
|
+
self.api_get(:blast, {:blast_id => blast_id.to_s})
|
133
|
+
end
|
134
|
+
|
135
|
+
# params:
|
136
|
+
# email, String
|
137
|
+
# returns:
|
138
|
+
# Hash, response data from server
|
139
|
+
#
|
140
|
+
# Return information about an email address, including replacement vars and lists.
|
141
|
+
def get_email(email)
|
142
|
+
self.api_get(:email, {:email => email})
|
143
|
+
end
|
144
|
+
|
145
|
+
# params:
|
146
|
+
# email, String
|
147
|
+
# vars, Hash
|
148
|
+
# lists, Hash mapping list name => 1 for subscribed, 0 for unsubscribed
|
149
|
+
# returns:
|
150
|
+
# Hash, response data from server
|
151
|
+
#
|
152
|
+
# Set replacement vars and/or list subscriptions for an email address.
|
153
|
+
def set_email(email, vars = {}, lists = {}, templates = {})
|
154
|
+
data = {:email => email}
|
155
|
+
data[:vars] = vars unless vars.empty?
|
156
|
+
data[:lists] = lists unless lists.empty?
|
157
|
+
data[:templates] = templates unless templates.empty?
|
158
|
+
self.api_post(:email, data)
|
159
|
+
end
|
160
|
+
|
161
|
+
# params:
|
162
|
+
# email, String
|
163
|
+
# password, String
|
164
|
+
# with_names, Boolean
|
165
|
+
# returns:
|
166
|
+
# Hash, response data from server
|
167
|
+
#
|
168
|
+
# Fetch email contacts from an address book at one of the major email providers (aol/gmail/hotmail/yahoo)
|
169
|
+
# Use the with_names parameter if you want to fetch the contact names as well as emails
|
170
|
+
def import_contacts(email, password, with_names = false)
|
171
|
+
data = { :email => email, :password => password }
|
172
|
+
data[:names] = 1 if with_names
|
173
|
+
self.api_post(:contacts, data)
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
# params:
|
178
|
+
# template_name, String
|
179
|
+
# returns:
|
180
|
+
# Hash of response data.
|
181
|
+
#
|
182
|
+
# Get a template.
|
183
|
+
def get_template(template_name)
|
184
|
+
self.api_get(:template, {:template => template_name})
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
# params:
|
189
|
+
# template_name, String
|
190
|
+
# template_fields, Hash
|
191
|
+
# returns:
|
192
|
+
# Hash containg response from the server.
|
193
|
+
#
|
194
|
+
# Save a template.
|
195
|
+
def save_template(template_name, template_fields)
|
196
|
+
data = template_fields
|
197
|
+
data[:template] = template_name
|
198
|
+
self.api_post(:template, data)
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
# params:
|
203
|
+
# params, Hash
|
204
|
+
# request, String
|
205
|
+
# returns:
|
206
|
+
# TrueClass or FalseClass, Returns true if the incoming request is an authenticated verify post.
|
207
|
+
def receive_verify_post(params, request)
|
208
|
+
if request.post?
|
209
|
+
[:action, :email, :send_id, :sig].each { |key| return false unless params.has_key?(key) }
|
210
|
+
|
211
|
+
return false unless params[:action] == :verify
|
212
|
+
|
213
|
+
sig = params[:sig]
|
214
|
+
params.delete(:sig)
|
215
|
+
return false unless sig == TriggermailClient.get_signature_hash(params, @secret)
|
216
|
+
|
217
|
+
_send = self.get_send(params[:send_id])
|
218
|
+
return false unless _send.has_key?(:email)
|
219
|
+
|
220
|
+
return false unless _send[:email] == params[:email]
|
221
|
+
|
222
|
+
return true
|
223
|
+
else
|
224
|
+
return false
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
# Perform API GET request
|
230
|
+
def api_get(action, data)
|
231
|
+
api_request(action, data, 'GET')
|
232
|
+
end
|
233
|
+
|
234
|
+
# Perform API POST request
|
235
|
+
def api_post(action, data)
|
236
|
+
api_request(action, data, 'POST')
|
237
|
+
end
|
238
|
+
|
239
|
+
# params:
|
240
|
+
# action, String
|
241
|
+
# data, Hash
|
242
|
+
# request, String "GET" or "POST"
|
243
|
+
# returns:
|
244
|
+
# Hash
|
245
|
+
#
|
246
|
+
# Perform an API request, using the shared-secret auth hash.
|
247
|
+
#
|
248
|
+
def api_request(action, data, request_type)
|
249
|
+
data[:api_key] = @api_key
|
250
|
+
data[:format] ||= 'json'
|
251
|
+
data[:sig] = Sailthru::TriggermailClient.get_signature_hash(data, @secret)
|
252
|
+
_result = self.http_request("#{@api_uri}/#{action}", data, request_type)
|
253
|
+
|
254
|
+
|
255
|
+
# NOTE: don't do the unserialize here
|
256
|
+
unserialized = JSON.parse(_result)
|
257
|
+
return unserialized ? unserialized : _result
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# params:
|
262
|
+
# uri, String
|
263
|
+
# data, Hash
|
264
|
+
# method, String "GET" or "POST"
|
265
|
+
# returns:
|
266
|
+
# String, body of response
|
267
|
+
def http_request(uri, data, method = 'POST')
|
268
|
+
data = flatten_nested_hash(data, false)
|
269
|
+
# puts data.inspect
|
270
|
+
if method == 'POST'
|
271
|
+
post_data = data
|
272
|
+
else
|
273
|
+
uri += "?" + data.map{ |key, value| "#{key}=#{value}" }.join("&")
|
274
|
+
end
|
275
|
+
|
276
|
+
req = nil
|
277
|
+
headers = {"User-Agent" => "Triggermail API Ruby Client #{VERSION}"}
|
278
|
+
|
279
|
+
_uri = URI.parse(uri)
|
280
|
+
if method == 'POST'
|
281
|
+
req = Net::HTTP::Post.new(_uri.path, headers)
|
282
|
+
req.set_form_data(data)
|
283
|
+
else
|
284
|
+
req = Net::HTTP::Get.new("#{_uri.path}?#{_uri.query}", headers)
|
285
|
+
end
|
286
|
+
|
287
|
+
@last_request = req
|
288
|
+
begin
|
289
|
+
response = Net::HTTP.start(_uri.host, _uri.port) {|http|
|
290
|
+
http.request(req)
|
291
|
+
}
|
292
|
+
rescue Exception => e
|
293
|
+
raise Sailthru::TriggermailClientException.new("Unable to open stream: #{_uri.to_s}");
|
294
|
+
end
|
295
|
+
|
296
|
+
if response.body
|
297
|
+
return response.body
|
298
|
+
else
|
299
|
+
raise Sailthru::TriggermailClientException.new("No response received from stream: #{_uri.to_s}")
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
# Flatten nested hash for GET / POST request.
|
305
|
+
def flatten_nested_hash(hash, brackets = true)
|
306
|
+
f = {}
|
307
|
+
hash.each do |key, value|
|
308
|
+
_key = brackets ? "[#{key}]" : key.to_s
|
309
|
+
if value.class == Hash
|
310
|
+
flatten_nested_hash(value).each do |k, v|
|
311
|
+
f["#{_key}#{k}"] = v
|
312
|
+
end
|
313
|
+
else
|
314
|
+
f[_key] = value
|
315
|
+
end
|
316
|
+
end
|
317
|
+
return f
|
318
|
+
end
|
319
|
+
|
320
|
+
# params:
|
321
|
+
# params, Hash
|
322
|
+
# returns:
|
323
|
+
# Array, values of each item in the Hash (and nested hashes)
|
324
|
+
#
|
325
|
+
# Extracts the values of a set of parameters, recursing into nested assoc arrays.
|
326
|
+
def self.extract_param_values(params)
|
327
|
+
values = []
|
328
|
+
params.each do |k, v|
|
329
|
+
# puts "k,v: #{k}, #{v}"
|
330
|
+
if v.class == Hash
|
331
|
+
values.concat Sailthru::TriggermailClient.extract_param_values(v)
|
332
|
+
else
|
333
|
+
values.push v
|
334
|
+
end
|
335
|
+
end
|
336
|
+
return values
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
# params:
|
341
|
+
# params, Hash
|
342
|
+
# secret, String
|
343
|
+
# returns:
|
344
|
+
# String, an MD5 hash of the secret + sorted list of parameter values for an API call.
|
345
|
+
def self.get_signature_hash(params, secret)
|
346
|
+
string = secret + self.extract_param_values(params).sort_by{|x| x.to_s}.join("")
|
347
|
+
MD5.md5(string) # debuggin
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
351
|
+
end
|
data/sailthru.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{sailthru}
|
3
|
+
s.version = "1.0.0"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Ian Enders"]
|
7
|
+
s.date = %q{2010-04-02}
|
8
|
+
s.description = %q{Sailthru triggermail client.}
|
9
|
+
s.email = %q{ian.enders@gmail.com}
|
10
|
+
s.extra_rdoc_files = [
|
11
|
+
"README.txt"
|
12
|
+
]
|
13
|
+
s.files = [
|
14
|
+
".gitignore",
|
15
|
+
"README.txt",
|
16
|
+
"VERSION",
|
17
|
+
"lib/sailthru/client.rb",
|
18
|
+
"lib/sailthru/triggermail_client.rb",
|
19
|
+
"sailthru.gemspec"
|
20
|
+
]
|
21
|
+
s.homepage = %q{http://github.com/ienders/sailthru}
|
22
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
s.rubygems_version = %q{1.3.6}
|
25
|
+
s.summary = %q{Gemified Sailthru Client Library}
|
26
|
+
|
27
|
+
if s.respond_to? :specification_version then
|
28
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
29
|
+
s.specification_version = 3
|
30
|
+
|
31
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
32
|
+
else
|
33
|
+
end
|
34
|
+
else
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sailthru
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ian Enders
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-02 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Sailthru triggermail client.
|
22
|
+
email: ian.enders@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.txt
|
29
|
+
files:
|
30
|
+
- .gitignore
|
31
|
+
- README.txt
|
32
|
+
- VERSION
|
33
|
+
- lib/sailthru/client.rb
|
34
|
+
- lib/sailthru/triggermail_client.rb
|
35
|
+
- sailthru.gemspec
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://github.com/ienders/sailthru
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --charset=UTF-8
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
segments:
|
50
|
+
- 0
|
51
|
+
version: "0"
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.6
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Gemified Sailthru Client Library
|
66
|
+
test_files: []
|
67
|
+
|