madmimi 1.0.14 → 1.0.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,8 @@ mimi = MadMimi.new('emailaddress', 'api_key')
15
15
 
16
16
  mimi.lists -> get all of your Mad Mimi lists returned as a hash
17
17
 
18
+ === Audience Members and Lists
19
+
18
20
  mimi.memberships('email') -> returns a hash of the lists that specific email address is subscribed to
19
21
 
20
22
  mimi.new_list('New list name') -> make a new list
@@ -29,8 +31,12 @@ mimi.remove_from_list('dave@example.com', 'Test List') -> remove this email addr
29
31
 
30
32
  mimi.suppressed_since('unix timestamp') -> get a TXT of all addresses that were suppressed since this timestamp
31
33
 
34
+ === Promotions
35
+
32
36
  mimi.promotions -> returns a hash of your promotions
33
37
 
38
+ mimi.save_promotion('promotion_name', 'raw_html', 'plain_text') -> saves a promotion (creates the promotion if it does not exist)
39
+
34
40
  mimi.mailing_stats('promotion_id', 'mailing_id') -> get stats on a specific mailing
35
41
 
36
42
  == Sending E-Mail (using the Mailer API)
@@ -84,6 +90,8 @@ If it exists and you specify raw_html, the promotion body will be replaced.
84
90
  'list_name': For all of the #send methods, if 'list_name' is provided, the recipients
85
91
  will be those for an already-existing "audience."
86
92
 
93
+ 'to_all': Set to true to send a promotion, plain_text or raw_html to all your audience members
94
+
87
95
  == Note on Patches/Pull Requests
88
96
 
89
97
  * Fork the project.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.14
1
+ 1.0.15
@@ -37,17 +37,23 @@ class MadMimi
37
37
  class MadMimiError < StandardError; end
38
38
 
39
39
  BASE_URL = 'api.madmimi.com'
40
+
40
41
  NEW_LISTS_PATH = '/audience_lists'
41
42
  AUDIENCE_MEMBERS_PATH = '/audience_members'
42
43
  AUDIENCE_LISTS_PATH = '/audience_lists/lists.xml'
43
44
  MEMBERSHIPS_PATH = '/audience_members/%email%/lists.xml'
44
45
  SUPPRESSED_SINCE_PATH = '/audience_members/suppressed_since/%timestamp%.txt'
45
46
  SUPPRESS_USER_PATH = ' /audience_members/%email%/suppress_email'
47
+ SEARCH_PATH = '/audience_members/search.xml'
48
+
46
49
  PROMOTIONS_PATH = '/promotions.xml'
50
+ PROMOTION_SAVE_PATH = '/promotions/save'
51
+
47
52
  MAILING_STATS_PATH = '/promotions/%promotion_id%/mailings/%mailing_id%.xml'
48
- SEARCH_PATH = '/audience_members/search.xml'
53
+
49
54
  MAILER_PATH = '/mailer'
50
55
  MAILER_TO_LIST_PATH = '/mailer/to_list'
56
+ MAILER_TO_ALL_PATH = '/mailer/to_all'
51
57
  MAILER_STATUS_PATH = '/mailers/status'
52
58
 
53
59
  def initialize(username, api_key)
@@ -66,6 +72,7 @@ class MadMimi
66
72
  { :username => username, :api_key => api_key }
67
73
  end
68
74
 
75
+ # Audience and lists
69
76
  def lists
70
77
  request = do_request(AUDIENCE_LISTS_PATH, :get)
71
78
  Crack::XML.parse(request)
@@ -109,49 +116,69 @@ class MadMimi
109
116
  do_request(SUPPRESS_USER_PATH.gsub('%email%', email), :post)
110
117
  end
111
118
 
119
+ def audience_search(query_string, raw = false)
120
+ request = do_request(SEARCH_PATH, :get, :raw => raw, :query => query_string)
121
+ Crack::XML.parse(request)
122
+ end
123
+
124
+ # Not the most elegant, but it works for now. :)
125
+ def add_users_to_list(list_name, arr)
126
+ arr.each do |a|
127
+ a[:add_list] = list_name
128
+ add_user(a)
129
+ end
130
+ end
131
+
132
+ # Promotions
112
133
  def promotions
113
134
  request = do_request(PROMOTIONS_PATH, :get)
114
135
  Crack::XML.parse(request)
115
136
  end
116
-
137
+
138
+ def save_promotion(promotion_name, raw_html, plain_text = nil)
139
+ options = { :promotion_name => promotion_name }
140
+
141
+ unless raw_html.nil?
142
+ check_for_tracking_beacon raw_html
143
+ check_for_opt_out raw_html
144
+ options[:raw_html] = raw_html
145
+ end
146
+
147
+ unless plain_text.nil?
148
+ check_for_opt_out plain_text
149
+ options[:raw_plain_text] = plain_text
150
+ end
151
+
152
+ do_request PROMOTION_SAVE_PATH, :post, options
153
+ end
154
+
155
+ # Stats
117
156
  def mailing_stats(promotion_id, mailing_id)
118
157
  path = MAILING_STATS_PATH.gsub('%promotion_id%', promotion_id).gsub('%mailing_id%', mailing_id)
119
158
  request = do_request(path, :get)
120
159
  Crack::XML.parse(request)
121
160
  end
122
161
 
123
- def audience_search(query_string, raw = false)
124
- request = do_request(SEARCH_PATH, :get, :raw => raw, :query => query_string)
125
- Crack::XML.parse(request)
126
- end
127
-
162
+ # Mailer API
128
163
  def send_mail(opt, yaml_body)
129
164
  options = opt.dup
130
165
  options[:body] = yaml_body.to_yaml
131
- if !options[:list_name].nil?
132
- do_request(MAILER_TO_LIST_PATH, :post, options, true)
166
+ if !options[:list_name].nil? || options[:to_all]
167
+ do_request(options[:to_all] ? MAILER_TO_ALL_PATH : MAILER_TO_LIST_PATH, :post, options, true)
133
168
  else
134
169
  do_request(MAILER_PATH, :post, options, true)
135
170
  end
136
171
  end
137
172
 
138
- # Not the most elegant, but it works for now. :)
139
- def add_users_to_list(list_name, arr)
140
- arr.each do |a|
141
- a[:add_list] = list_name
142
- add_user(a)
143
- end
144
- end
145
-
146
173
  def send_html(opt, html)
147
174
  options = opt.dup
148
175
  if html.include?('[[tracking_beacon]]') || html.include?('[[peek_image]]')
149
176
  options[:raw_html] = html
150
- if !options[:list_name].nil?
177
+ if !options[:list_name].nil? || options[:to_all]
151
178
  unless html.include?('[[unsubscribe]]') || html.include?('[[opt_out]]')
152
179
  raise MadMimiError, "When specifying list_name, include the [[unsubscribe]] or [[opt_out]] macro in your HTML before sending."
153
180
  end
154
- do_request(MAILER_TO_LIST_PATH, :post, options, true)
181
+ do_request(options[:to_all] ? MAILER_TO_ALL_PATH : MAILER_TO_LIST_PATH, :post, options, true)
155
182
  else
156
183
  do_request(MAILER_PATH, :post, options, true)
157
184
  end
@@ -163,9 +190,9 @@ class MadMimi
163
190
  def send_plaintext(opt, plaintext)
164
191
  options = opt.dup
165
192
  options[:raw_plain_text] = plaintext
166
- if !options[:list_name].nil?
193
+ if !options[:list_name].nil? || options[:to_all]
167
194
  if plaintext.include?('[[unsubscribe]]') || plaintext.include?('[[opt_out]]')
168
- do_request(MAILER_TO_LIST_PATH, :post, options, true)
195
+ do_request(options[:to_all] ? MAILER_TO_ALL_PATH : MAILER_TO_LIST_PATH, :post, options, true)
169
196
  else
170
197
  raise MadMimiError, "You'll need to include either the [[unsubscribe]] or [[opt_out]] macro in your text before sending."
171
198
  end
@@ -235,4 +262,18 @@ class MadMimi
235
262
  end
236
263
  end
237
264
  end
265
+
266
+ def check_for_tracking_beacon(content)
267
+ unless content.include?('[[tracking_beacon]]') || content.include?('[[peek_image]]')
268
+ raise MadMimiError, "You'll need to include either the [[tracking_beacon]] or [[peek_image]] macro in your HTML before sending."
269
+ end
270
+ true
271
+ end
272
+
273
+ def check_for_opt_out(content)
274
+ unless content.include?('[[opt_out]]') || content.include?('[[unsubscribe]]')
275
+ raise MadMimiError, "When specifying list_name or sending to all, include the [[unsubscribe]] or [[opt_out]] macro in your HTML before sending."
276
+ end
277
+ true
278
+ end
238
279
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{madmimi}
8
- s.version = "1.0.14"
8
+ s.version = "1.0.15"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nicholas Young", "Marc Heiligers"]
12
- s.date = %q{2011-03-18}
12
+ s.date = %q{2011-03-21}
13
13
  s.description = %q{Send emails, track statistics, and manage your subscriber base with ease.}
14
14
  s.email = %q{nicholas@madmimi.com}
15
15
  s.extra_rdoc_files = [
@@ -33,7 +33,7 @@ def stub_get(url, options = {})
33
33
  FakeWeb.register_uri(:get, madmimi_url(url, https), options)
34
34
  end
35
35
 
36
- def stub_post(url, filename = nil, status = nil)
36
+ def stub_post(url, options)
37
37
  https = options.delete(:https)
38
38
 
39
39
  filename = options.delete(:filename)
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require "#{File.dirname(__FILE__)}/helper"
2
2
 
3
3
  class TestMadmimi < Test::Unit::TestCase
4
4
  context "An API call" do
@@ -24,6 +24,36 @@ class TestMadmimi < Test::Unit::TestCase
24
24
  flunk "No users found." unless response.kind_of?(Hash) || !response.empty?
25
25
  end
26
26
 
27
+ should "save a raw html promotion" do
28
+ response_body = 'Saved test_promotion (1)'
29
+ stub_post('/promotions/save', { :body => response_body })
30
+ response = @mimi.save_promotion('test_promotion', '<html><body>Hi there!<br>[[unsubscribe]][[tracking_beacon]]</body></html>')
31
+ assert_equal response_body, response
32
+ end
33
+
34
+ should "save a text promotion" do
35
+ response_body = 'Saved test_promotion (1)'
36
+ stub_post('/promotions/save', { :body => response_body })
37
+ response = @mimi.save_promotion('test_promotion', nil, "Hi there!\n\n[[unsubscribe]]")
38
+ assert_equal response_body, response
39
+ end
40
+
41
+ should "raise exception on saving a raw html promotion without the required macros" do
42
+ assert_raises MadMimi::MadMimiError do
43
+ @mimi.save_promotion('test_promotion', '<html><body>Hi there!<br>[[tracking_beacon]]</body></html>')
44
+ end
45
+
46
+ assert_raises MadMimi::MadMimiError do
47
+ @mimi.save_promotion('test_promotion', '<html><body>Hi there!<br>[[unsubscribe]]</body></html>')
48
+ end
49
+ end
50
+
51
+ should "raise exception on saving a plain text promotion without the required macro" do
52
+ assert_raises MadMimi::MadMimiError do
53
+ @mimi.save_promotion('test_promotion', 'Hi there')
54
+ end
55
+ end
56
+
27
57
  should "get a transactional mailing status" do
28
58
  stub_get('/mailers/status/1234', { :https => true, :body => "sent" })
29
59
  response = @mimi.status(1234)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madmimi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 14
10
- version: 1.0.14
9
+ - 15
10
+ version: 1.0.15
11
11
  platform: ruby
12
12
  authors:
13
13
  - Nicholas Young
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-03-18 00:00:00 +02:00
19
+ date: 2011-03-21 00:00:00 +02:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency