exact-target 0.0.4
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/CHANGELOG +4 -0
- data/LICENSE +481 -0
- data/Manifest +22 -0
- data/README.rdoc +170 -0
- data/Rakefile +40 -0
- data/exact-target.gemspec +32 -0
- data/lib/exact_target.rb +109 -0
- data/lib/exact_target/builder_ext.rb +11 -0
- data/lib/exact_target/configuration.rb +42 -0
- data/lib/exact_target/error.rb +16 -0
- data/lib/exact_target/net_https_hack.rb +8 -0
- data/lib/exact_target/request_builder.rb +284 -0
- data/lib/exact_target/response_class.erb +30 -0
- data/lib/exact_target/response_classes.rb +61 -0
- data/lib/exact_target/response_handler.rb +167 -0
- data/lib/exact_target/string_ext.rb +22 -0
- data/spec/exact_target/net_https_hack_spec.rb +8 -0
- data/spec/exact_target/response_handler_spec.rb +15 -0
- data/spec/exact_target/string_ext_spec.rb +13 -0
- data/spec/exact_target_data.yml +133 -0
- data/spec/exact_target_spec.rb +382 -0
- data/spec/spec.opts +4 -0
- data/spec/subscriber_list_spec.rb +290 -0
- metadata +95 -0
data/Manifest
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
LICENSE
|
3
|
+
README.rdoc
|
4
|
+
Rakefile
|
5
|
+
lib/exact_target.rb
|
6
|
+
lib/exact_target/builder_ext.rb
|
7
|
+
lib/exact_target/configuration.rb
|
8
|
+
lib/exact_target/error.rb
|
9
|
+
lib/exact_target/net_https_hack.rb
|
10
|
+
lib/exact_target/request_builder.rb
|
11
|
+
lib/exact_target/response_class.erb
|
12
|
+
lib/exact_target/response_classes.rb
|
13
|
+
lib/exact_target/response_handler.rb
|
14
|
+
lib/exact_target/string_ext.rb
|
15
|
+
spec/exact_target/net_https_hack_spec.rb
|
16
|
+
spec/exact_target/response_handler_spec.rb
|
17
|
+
spec/exact_target/string_ext_spec.rb
|
18
|
+
spec/exact_target_data.yml
|
19
|
+
spec/exact_target_spec.rb
|
20
|
+
spec/spec.opts
|
21
|
+
spec/subscriber_list_spec.rb
|
22
|
+
Manifest
|
data/README.rdoc
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
= ExactTarget - A Ruby interface to the ExactTarget API.
|
2
|
+
|
3
|
+
== Introduction
|
4
|
+
|
5
|
+
ExactTarget is an email marketing solution provider with an
|
6
|
+
http-based api for performing various tasks such as managing
|
7
|
+
mailing lists, managing subscribers, and queueing up email
|
8
|
+
jobs. This gem is a pure ruby library for accessing that api.
|
9
|
+
|
10
|
+
== Resources
|
11
|
+
|
12
|
+
=== Installation
|
13
|
+
|
14
|
+
gem install exact-target
|
15
|
+
|
16
|
+
=== Git Repository
|
17
|
+
|
18
|
+
http://github.com/ePublishing/exact_target
|
19
|
+
|
20
|
+
== Prerequisites
|
21
|
+
|
22
|
+
The ExactTarget gem depends on both Nokogiri and Builder. Both
|
23
|
+
should be installed automatically when them gem is installed
|
24
|
+
(if not already installed).
|
25
|
+
|
26
|
+
== Notes
|
27
|
+
|
28
|
+
Currently this is a partial implementation. None of the
|
29
|
+
tracking functionality is yet implemented.
|
30
|
+
|
31
|
+
== Usage
|
32
|
+
|
33
|
+
=== Setup/Configuration
|
34
|
+
|
35
|
+
require 'exact_target'
|
36
|
+
|
37
|
+
ExactTarget.configure do |config|
|
38
|
+
config.username = 'my_username'
|
39
|
+
config.password = 'my_password'
|
40
|
+
end
|
41
|
+
|
42
|
+
=== Account Information
|
43
|
+
|
44
|
+
# Retrieve subscriber attributes
|
45
|
+
ExactTarget.accountinfo_retrieve_attrbs
|
46
|
+
|
47
|
+
=== List Management
|
48
|
+
|
49
|
+
# Retrieve all list ids
|
50
|
+
ExactTarget.list_retrieve
|
51
|
+
|
52
|
+
# Retrieve list id for given name
|
53
|
+
ExactTarget.list_retrieve('Some List')
|
54
|
+
|
55
|
+
# Retrieve list information by list id
|
56
|
+
ExactTarget.list_retrieve(15123512)
|
57
|
+
|
58
|
+
# Create new list
|
59
|
+
ExactTarget.list_add("My Test List", :private)
|
60
|
+
|
61
|
+
# Rename a list
|
62
|
+
ExactTarget.list_edit(15123512, "My RENAMED Test List")
|
63
|
+
|
64
|
+
# Import new or updated subscribers en mass from a comma-delimited
|
65
|
+
# or tab-delimited file into an existing subscriber list.
|
66
|
+
ExactTarget.list_import(15123512, 'sometestfile.txt', ['Email Address', 'Field 2', ...])
|
67
|
+
ExactTarget.list_import([id_1, id2, ...], 'sometestfile.txt', ['Email Address', 'Field 2', ...])
|
68
|
+
|
69
|
+
# Request an update on the status of an import.
|
70
|
+
ExactTarget.list_importstatus(some_import_id)
|
71
|
+
|
72
|
+
# Retrieve the profile and preference attributes for all subscribers
|
73
|
+
# (or all subscribers with a certain status) on a specified list.
|
74
|
+
ExactTarget.list_retrieve_sub(42, 'Active')
|
75
|
+
|
76
|
+
# Delete a list and all subscribers who belong to the list.
|
77
|
+
ExactTarget.list_delete(15123512)
|
78
|
+
|
79
|
+
# Retrieve all groups in your account.
|
80
|
+
ExactTarget.list_retrievegroups
|
81
|
+
|
82
|
+
# Refresh the membership of an attribute-based (rule-based) group
|
83
|
+
# to reflect any changes to your subscribers' attribute values.
|
84
|
+
ExactTarget.list_refresh_group(3514)
|
85
|
+
|
86
|
+
# Request an update on the status of a group refresh.
|
87
|
+
ExactTarget.batch_inquire(8912)
|
88
|
+
|
89
|
+
=== Subscriber Management
|
90
|
+
|
91
|
+
# Add a subscriber to a list.
|
92
|
+
subscriber = ExactTarget::Subscriber.new.tap do |s|
|
93
|
+
s.email_address = 'test.person@company.com'
|
94
|
+
s.full_name = 'George Wills'
|
95
|
+
end
|
96
|
+
ExactTarget.subscriber_add(1234, subscriber,
|
97
|
+
:status => :active,
|
98
|
+
:update => true,
|
99
|
+
:ChannelMemberID => 5678)
|
100
|
+
|
101
|
+
# Update the attributes (including email address) and/or status of
|
102
|
+
# an existing subscriber. Can be used to reactivate a subscriber
|
103
|
+
# who was placed on the master unsubscribe list.
|
104
|
+
subscriber = ExactTarget::Subscriber.new.tap do |s|
|
105
|
+
s.email_address = 'new.email@company.com'
|
106
|
+
s.full_name = 'Frank Jones'
|
107
|
+
end
|
108
|
+
ExactTarget.subscriber_edit(63718, 'previous@email.com', subscriber,
|
109
|
+
:status => :unsub,
|
110
|
+
:reason => 'Some reason ...',
|
111
|
+
:ChannelMemberID => 5678)
|
112
|
+
|
113
|
+
# Retrieve all profile and preference attribute data entered for a
|
114
|
+
# subscriber on a specific list, or retrieve all attribute data for
|
115
|
+
# a subscriber and all lists to which the subscriber belongs.
|
116
|
+
ExactTarget.subscriber_retrieve(123456, 'someone@example.com')
|
117
|
+
ExactTarget.subscriber_retrieve(123456789)
|
118
|
+
|
119
|
+
# Delete a subscriber from your database, or remove a subscriber
|
120
|
+
# from a specified list.
|
121
|
+
ExactTarget.subscriber_delete(112233445566, 'bob@hotmail.com')
|
122
|
+
ExactTarget.subscriber_delete(112233445566)
|
123
|
+
|
124
|
+
# Place a subscriber's (or multiple subscribers') email address on
|
125
|
+
# your Master Unsubscribe list so that the email address is never
|
126
|
+
# added to any of your subscriber lists.
|
127
|
+
ExactTarget.subscriber_masterunsub 'someone@email.com', 'someone.else@email.com', ...
|
128
|
+
|
129
|
+
=== Mailing Management
|
130
|
+
|
131
|
+
# Retrieve all email IDs or filter by email name and/or date range.
|
132
|
+
ExactTarget.email_retrieve
|
133
|
+
ExactTarget.email_retrieve('Welcome to Fortune One!')
|
134
|
+
ExactTarget.email_retrieve(:start_date => Date.parse('2008-09-15'),
|
135
|
+
:end_date => Date.parse('2008-10-15'))
|
136
|
+
ExactTarget.email_retrieve('Welcome to Fortune One!',
|
137
|
+
:start_date => Date.parse('2008-09-15'),
|
138
|
+
:end_date => Date.parse('2008-10-15'))
|
139
|
+
|
140
|
+
# Create an email from HTML that you send to the ExactTarget application via an API call.
|
141
|
+
ExactTarget.email_add('Your email name', 'Your subject line', :body => 'Your HTML email body')
|
142
|
+
ExactTarget.email_add('Your email name', 'Your subject line', :file => 'Filename')
|
143
|
+
|
144
|
+
# Create the text version of an email, which will be displayed
|
145
|
+
# to any subscriber whose email client does not support HTML email.
|
146
|
+
ExactTarget.email_add_text(email_id, :body => 'Your text email body')
|
147
|
+
ExactTarget.email_add_text(email_id, :file => 'Filename')
|
148
|
+
|
149
|
+
# Retrieve the body of the HTML version of any email in your account.
|
150
|
+
ExactTarget.email_retrieve_body(email_id)
|
151
|
+
|
152
|
+
=== Job Initiation
|
153
|
+
|
154
|
+
# Kick off a mailing (test or live)
|
155
|
+
ExactTarget.job_send(email_id,
|
156
|
+
[list_id_1, list_id_2, ...],
|
157
|
+
:suppress_ids => [list_id_3, ...],
|
158
|
+
:from_name => 'John Doe',
|
159
|
+
:from_email => 'jd@nowhere.com',
|
160
|
+
:additional => 'additional information for job',
|
161
|
+
:multipart_mime => true,
|
162
|
+
:track_links => false,
|
163
|
+
:send_date => '5/3/2011',
|
164
|
+
:send_time => '17:35',
|
165
|
+
:test_send => true)
|
166
|
+
|
167
|
+
---
|
168
|
+
Author:: David McCullars <mailto:dmccullars@ePublishing.com>
|
169
|
+
Copyright:: (C) 2011 ePublishing
|
170
|
+
Licence:: GPL[http://www.gnu.org/copyleft/gpl.html]
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'echoe'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
task :default => :gem
|
7
|
+
|
8
|
+
Echoe.new("exact-target") do |s|
|
9
|
+
s.author = "David McCullars"
|
10
|
+
s.project = "exact-target"
|
11
|
+
s.email = "dmccullars@ePublishing.com"
|
12
|
+
s.url = "http://github.com/ePublishing/exact_target"
|
13
|
+
s.docs_host = "http://rdoc.info/github/ePublishing/exact_target/master/frames"
|
14
|
+
s.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|BENCH|COMPAT|exceptions|behaviors|exact-target.rb/
|
15
|
+
s.clean_pattern += ["ext/lib", "ext/include", "ext/share", "ext/libexact-target-?.??", "ext/bin", "ext/conftest.dSYM"]
|
16
|
+
s.summary = <<DONE
|
17
|
+
This is a pure-ruby implementation of the ExactTarget api.
|
18
|
+
For more information consule http://www.exacttarget.com/.
|
19
|
+
DONE
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Run all specs"
|
23
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
24
|
+
t.spec_opts = ['--options', %q("spec/spec.opts")]
|
25
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
t.rcov = true
|
27
|
+
t.rcov_opts = ['--exclude', 'spec']
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'generate API documentation to doc/rdocs/index.html'
|
31
|
+
Rake::RDocTask.new do |rd|
|
32
|
+
rd.rdoc_dir = 'doc/rdocs'
|
33
|
+
rd.main = 'README.rdoc'
|
34
|
+
rd.rdoc_files.include 'README.rdoc', 'CHANGELOG', 'lib/**/*.rb'
|
35
|
+
rd.rdoc_files.exclude '**/string_ext.rb', '**/net_https_hack.rb'
|
36
|
+
rd.options << '--inline-source'
|
37
|
+
rd.options << '--line-numbers'
|
38
|
+
rd.options << '--all'
|
39
|
+
rd.options << '--fileboxes'
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{exact-target}
|
5
|
+
s.version = "0.0.4"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["David McCullars"]
|
9
|
+
s.date = %q{2011-04-11}
|
10
|
+
s.description = %q{This is a pure-ruby implementation of the ExactTarget api.
|
11
|
+
For more information consule http://www.exacttarget.com/.
|
12
|
+
}
|
13
|
+
s.email = %q{dmccullars@ePublishing.com}
|
14
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc"]
|
15
|
+
s.files = ["CHANGELOG", "LICENSE", "README.rdoc", "Rakefile", "lib/exact_target.rb", "lib/exact_target/builder_ext.rb", "lib/exact_target/configuration.rb", "lib/exact_target/error.rb", "lib/exact_target/net_https_hack.rb", "lib/exact_target/request_builder.rb", "lib/exact_target/response_class.erb", "lib/exact_target/response_classes.rb", "lib/exact_target/response_handler.rb", "lib/exact_target/string_ext.rb", "spec/exact_target/net_https_hack_spec.rb", "spec/exact_target/response_handler_spec.rb", "spec/exact_target/string_ext_spec.rb", "spec/exact_target_data.yml", "spec/exact_target_spec.rb", "spec/spec.opts", "spec/subscriber_list_spec.rb", "Manifest", "exact-target.gemspec"]
|
16
|
+
s.homepage = %q{http://github.com/ePublishing/exact_target}
|
17
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Exact-target", "--main", "README.rdoc"]
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.rubyforge_project = %q{exact-target}
|
20
|
+
s.rubygems_version = %q{1.3.6}
|
21
|
+
s.summary = %q{This is a pure-ruby implementation of the ExactTarget api. For more information consule http://www.exacttarget.com/.}
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 3
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
else
|
29
|
+
end
|
30
|
+
else
|
31
|
+
end
|
32
|
+
end
|
data/lib/exact_target.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
require 'exact_target/net_https_hack'
|
8
|
+
require 'exact_target/builder_ext'
|
9
|
+
require 'exact_target/string_ext'
|
10
|
+
|
11
|
+
require 'exact_target/configuration'
|
12
|
+
require 'exact_target/error'
|
13
|
+
require 'exact_target/request_builder'
|
14
|
+
require 'exact_target/response_classes'
|
15
|
+
require 'exact_target/response_handler'
|
16
|
+
|
17
|
+
# The ExactTarget library is a ruby implementation of the ExactTarget
|
18
|
+
# email marketing api. It allows for list/subscriber management,
|
19
|
+
# email creation, and job initiation.
|
20
|
+
module ExactTarget
|
21
|
+
|
22
|
+
VERSION = File.read(File.expand_path '../../CHANGELOG', __FILE__)[/v([\d\.]+)\./, 1]
|
23
|
+
LOG_PREFIX = "** [ExactTarget] "
|
24
|
+
|
25
|
+
extend ExactTarget::ResponseClasses
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# The builder object is responsible for building the xml for any given request
|
29
|
+
attr_accessor :builder
|
30
|
+
|
31
|
+
# The handler object is responsible for handling the xml response and returning
|
32
|
+
# response data
|
33
|
+
attr_accessor :handler
|
34
|
+
|
35
|
+
# A ExactTarget configuration object. Must act like a hash and return sensible
|
36
|
+
# values for all ExactTarget configuration options. See ExactTarget::Configuration.
|
37
|
+
attr_accessor :configuration
|
38
|
+
|
39
|
+
def configure(username=nil, password=nil)
|
40
|
+
self.configuration ||= Configuration.new
|
41
|
+
configuration.username = username if username
|
42
|
+
configuration.password = password if password
|
43
|
+
yield(configuration) if block_given?
|
44
|
+
self.builder = RequestBuilder.new(configuration)
|
45
|
+
self.handler = ResponseHandler.new(configuration)
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def verify_configure
|
50
|
+
raise "ExactTarget must be configured before using" if configuration.nil? or !configuration.valid?
|
51
|
+
end
|
52
|
+
|
53
|
+
def log(level, message)
|
54
|
+
verify_configure
|
55
|
+
configuration.logger.send(level, message) unless configuration.logger.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def call(method, *args, &block)
|
59
|
+
verify_configure
|
60
|
+
|
61
|
+
request = builder.send(method, *args, &block)
|
62
|
+
log :debug, "#{LOG_PREFIX}REQUEST: #{request}"
|
63
|
+
|
64
|
+
response = send_to_exact_target(request)
|
65
|
+
log :debug, "#{LOG_PREFIX}RESPONSE: #{response}"
|
66
|
+
|
67
|
+
response = parse_response_xml(response)
|
68
|
+
|
69
|
+
handler.send(method, response)
|
70
|
+
end
|
71
|
+
|
72
|
+
def send_to_exact_target(request)
|
73
|
+
verify_configure
|
74
|
+
uri = URI.parse "#{configuration.base_url}?qf=xml&xml=#{URI.escape request}"
|
75
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
76
|
+
http.use_ssl = configuration.secure?
|
77
|
+
http.open_timeout = configuration.http_open_timeout
|
78
|
+
http.read_timeout = configuration.http_read_timeout
|
79
|
+
resp = http.get(uri.request_uri)
|
80
|
+
if resp.is_a?(Net::HTTPSuccess)
|
81
|
+
resp.body
|
82
|
+
else
|
83
|
+
resp.error!
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Define ExactTarget methods
|
88
|
+
(RequestBuilder.instance_methods(false) & ResponseHandler.instance_methods(false)).each do |m|
|
89
|
+
define_method(m) do |*args, &block|
|
90
|
+
call(m, *args, &block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def parse_response_xml(xml)
|
97
|
+
verify_configure
|
98
|
+
resp = Nokogiri.parse(xml)
|
99
|
+
error = resp.xpath('//error[1]').first
|
100
|
+
error_description = resp.xpath('//error_description[1]').first
|
101
|
+
if error and error_description
|
102
|
+
raise Error.new(error.text.to_i, error_description.text)
|
103
|
+
else
|
104
|
+
resp
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ExactTarget
|
2
|
+
# Used to set up and modify settings for ExactTarget
|
3
|
+
class Configuration
|
4
|
+
|
5
|
+
OPTIONS = [:base_url, :username, :password,
|
6
|
+
:http_open_timeout, :http_read_timeout].freeze
|
7
|
+
|
8
|
+
# The (optional) base URL for accessing ExactTarget (can be http or https).
|
9
|
+
# Defaults to 'https://api.dc1.exacttarget.com/integrate.aspx'
|
10
|
+
attr_accessor :base_url
|
11
|
+
|
12
|
+
# The (required) ExactTarget username for making requests
|
13
|
+
attr_accessor :username
|
14
|
+
|
15
|
+
# The (required) ExactTarget password for making requests
|
16
|
+
attr_accessor :password
|
17
|
+
|
18
|
+
# The (optional) logger for outputting request/resposne xml
|
19
|
+
attr_accessor :logger
|
20
|
+
|
21
|
+
# The (optional) HTTP open timeout in seconds (defaults to 2).
|
22
|
+
attr_accessor :http_open_timeout
|
23
|
+
|
24
|
+
# The (optional) HTTP read timeout in seconds (defaults to 5).
|
25
|
+
attr_accessor :http_read_timeout
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@base_url = 'https://api.dc1.exacttarget.com/integrate.aspx'
|
29
|
+
@http_open_timeout = 2
|
30
|
+
@http_read_timeout = 5
|
31
|
+
end
|
32
|
+
|
33
|
+
def valid?
|
34
|
+
[:base_url, :username, :password].none? { |f| send(f).nil? }
|
35
|
+
end
|
36
|
+
|
37
|
+
def secure?
|
38
|
+
!!(base_url =~ /^https:/i)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|