sparkpost_rails 1.0.1 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 368eabc1112630441a50e7b6c9b2024905900755
4
- data.tar.gz: ed9358eb97aa57d35579b23825d537570b1563de
3
+ metadata.gz: 6daae188c29ed7eb15c6a8dbd0c5617755f0e5b3
4
+ data.tar.gz: 23751028cb6b932d786b812a894656da1b4221e9
5
5
  SHA512:
6
- metadata.gz: 032d4a48dfd4946223695f197872e1abd4e111f85431017a443bbb620352a1f369a9296dfa9b0bc42047587ff474818326e67988ef776fda170ea8080b18f8c4
7
- data.tar.gz: ef0a2aaa4f7ab3fdf4a8962195658c0265886ef7c682e2a6f29f5a517695ef29ee480e65868080d831822ec816d179fa17f59e52d4a6837c332067ac5d24d50b
6
+ metadata.gz: 970b8a2255cf43de5c63164715993edca7a55deb0a0eb75c47da3079c0938e1132e482a88c9244df73852a4894ba0d94e848d41f9287f0265ec065b8c799570a
7
+ data.tar.gz: 63fcc3276a23701abdf75bdd14be5000425e5369a78d3dd9c9f1e2d166209e535f1f66df25278e3caf836265e622727d7bc9b5b6dddc6c7c4212b84ceb0419a7
data/README.md CHANGED
@@ -1,17 +1,25 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/sparkpost_rails.svg)](https://badge.fury.io/rb/sparkpost_rails)
2
2
  [![Build Status](https://travis-ci.org/the-refinery/sparkpost_rails.svg?branch=master)](https://travis-ci.org/the-refinery/sparkpost_rails)
3
3
 
4
- # SparkPost Rails
4
+ SparkPost Rails
5
+ ===============
5
6
 
6
- In `Gemfile` add
7
+ This gem provides seamless integration of SparkPost with ActionMailer. It provides a delivery_method based upon the SparkPost API, and
8
+ makes getting setup and sending email via SparkPost in a Rails app pretty painless.
9
+
10
+ Getting Started
11
+ ---------------
12
+
13
+ Add the gem to your Gemfile
7
14
 
8
15
  ```
9
16
  gem 'sparkpost_rails'
10
17
  ```
11
18
 
12
- By default, the gem will look for your SparkPost API key in your environment, with the key
13
- 'SPARKPOST_API_KEY'. You can override this setting by identifying a different key in the initializer
14
- (`config/initializers/sparkpost_rails.rb`):
19
+ Then run the bundle command to install it.
20
+
21
+ By default, the gem will look for your SparkPost API key in your environment, with the key 'SPARKPOST_API_KEY'. You can override this
22
+ setting by identifying a different key in the initializer (`config/initializers/sparkpost_rails.rb`):
15
23
 
16
24
  ```
17
25
  SparkPostRails.configure do |c|
@@ -19,11 +27,20 @@ SparkPostRails.configure do |c|
19
27
  end
20
28
  ```
21
29
 
22
- Additionally, the following configuration options are available to be set in your initializer
23
- ( `config/initializers/sparkpost_rails.rb`):
30
+ In each environment configuration file from which you want to send emails via Sparkpost, (i.e. `config/environments/production.rb`) add
31
+
32
+ ```
33
+ config.action_mailer.delivery_method = :sparkpost
34
+ ```
35
+
36
+ Additional Configuration
37
+ ------------------------
38
+ You can establish values for a number of SparkPost settings in the initializer. These values will be used for every message sent
39
+ from your application. You can override these settings on individual messages.
24
40
 
25
41
  ```
26
42
  SparkPostRails.configure do |c|
43
+ c.sandbox = true
27
44
  c.track_opens = true
28
45
  c.track_clicks = true
29
46
  c.return_path = 'BOUNCE-EMAIL@YOUR-DOMAIN.COM'
@@ -34,31 +51,99 @@ end
34
51
  The default values for these optional configuration settings are:
35
52
 
36
53
  ```
54
+ sandbox = false
37
55
  track_opens = false
38
56
  track_clicks = false
39
57
  return_path = nil
40
58
  campaign_id = nil
41
59
  ```
42
60
 
43
- In `config/environments/production.rb` add
61
+ Usage
62
+ -----
63
+ When calling the deliver! method on the mail object returned from your mailer, SparkPostRails provides the response data directly back
64
+ from SparkPost as a hash.
44
65
 
45
66
  ```
46
- config.action_mailer.delivery_method = :sparkpost
67
+ result = MyMailer.welcome_message(user).deliver!
68
+ ```
69
+
70
+ Example:
71
+
72
+ ```
73
+ {"total_rejected_recipients"=>0, "total_accepted_recipients"=>1, "id"=>"00000000000000"}
47
74
  ```
48
75
 
49
- The deliver! method returns the response data from the SparkPost API call as a hash:
76
+ If the SparkPost API reponds with an error condition, SparkPostRails will raise a SparkPostRails::DeliveryException, which will include all the message
77
+ data returned by the API.
78
+
79
+ SparkPostRails will support multiple recipients, multilple CC, multiple BCC, ReplyTo address, file attachments, inline images, multi-part (HTML and plaintext) messages -
80
+ all utilizing the standard ActionMailer methodologies.
81
+
82
+
83
+ SparkPost Specific Features
84
+ ---------------------------
85
+
86
+ ### Configuration Settings
87
+ You can specifiy values for any or all of the configuration settings listed above on an individual message. Simply add a hash of these values
88
+ to the mail message in a field named "sparkpost_data":
50
89
 
51
90
  ```
52
- response = UserMailer.welcome_email(user).deliver_now!
91
+ data = { track_opens: true,
92
+ track_clicks: false,
93
+ campaign_id: "My Campaign"}
94
+
95
+ mail(to: to_email, subject: "Test", body: "test", sparkpost_data: data)
53
96
  ```
54
97
 
55
- Example:
98
+ Additionally, return_path can be overriden on a specific email by setting that field on the mail message itself:
56
99
 
57
100
  ```
58
- {"total_rejected_recipients"=>0, "total_accepted_recipients"=>1, "id"=>"00000000000000"}
101
+ mail(to: to_email, subject: "Test", body: "test", return_path: "bounces@example.com")
59
102
  ```
60
103
 
61
- # Update Note!
104
+
105
+ ### Recipient Lists
106
+ SparkPostRails supports using SparkPost stored recipient lists. Simply add the list_id to the sparkpost_data hash on the mail message:
107
+
108
+ ```
109
+ data = { list_id: "MY-LIST"}
110
+
111
+ mail(subject: "Test", body: "test", sparkpost_data: data)
112
+ ```
113
+
114
+ **NOTE**: If you supply a recipient list id, all To:, CC:, and BCC: data specified on the mail message will be ignored. The SparkPost API does
115
+ not support utilizing both a recipient list and inline recipients.
116
+
117
+
118
+ ### Substitution Data
119
+ You can leverage SparkPost's substitution engine through the gem as well. To supply substitution data, simply add your hash of substitution data
120
+ to your sparkpost_data hash, with the key :substitution_data.
121
+
122
+ ```
123
+ sub_data = {first_name: "Sam",
124
+ last_name: "Test}
125
+
126
+ data = { substitution_data: sub_data }
127
+
128
+ mail(to: to_email, subject: "Test", body: "test", sparkpost_data: data)
129
+ ```
130
+
131
+ ### Using SparkPost Templates
132
+ If you would rather leverage SparkPost's powerful templates rather than building ActionMailer views, SparkPostRails can support that as well. Simply
133
+ add your template id to the sparkpost_data hash:
134
+
135
+ ```
136
+ data = { template_id: "MY-TEMPLATE" }
137
+
138
+ mail(to: to_email, sparkpost_data: data)
139
+ ```
140
+
141
+ **NOTE**: All inline-content that may exist in your mail message will be ignored, as the SparkPost API does not accept that data when a template id is
142
+ supplied. This includes Subject, From, ReplyTo, Attachments, and Inline Images.
143
+
144
+
145
+ Update Note!
146
+ ============
62
147
 
63
148
  If you have been using Version 0.0.5 or earlier of this gem, when you upgrade, you'll need to
64
149
  change your initalizer as follows:
@@ -14,20 +14,31 @@ module SparkPostRails
14
14
 
15
15
  class Configuration
16
16
  attr_accessor :api_key
17
+ attr_accessor :sandbox
18
+
17
19
  attr_accessor :track_opens
18
20
  attr_accessor :track_clicks
21
+
19
22
  attr_accessor :campaign_id
20
23
  attr_accessor :return_path
21
24
 
25
+
22
26
  def initialize
27
+ set_defaults
28
+ end
29
+
30
+ def set_defaults
23
31
  if ENV.has_key?("SPARKPOST_API_KEY")
24
32
  @api_key = ENV["SPARKPOST_API_KEY"]
25
33
  else
26
34
  @api_key = ""
27
35
  end
28
36
 
37
+ @sandbox = false
38
+
29
39
  @track_opens = false
30
40
  @track_clicks = false
41
+
31
42
  @campaign_id = nil
32
43
  @return_path = nil
33
44
  end
@@ -11,14 +11,24 @@ module SparkPostRails
11
11
  def deliver!(mail)
12
12
  @data = {content: {}}
13
13
 
14
- prepare_recipients_from mail
15
- prepare_from_address_from mail
16
- prepare_reply_to_address_from mail
14
+ sparkpost_data = find_sparkpost_data_from mail
17
15
 
18
- prepare_subject_from mail
19
- prepare_content_from mail
16
+ prepare_recipients_from mail, sparkpost_data
20
17
 
21
- prepare_options
18
+ if sparkpost_data.has_key?(:template_id)
19
+ prepare_template_content_from sparkpost_data
20
+ else
21
+ prepare_from_address_from mail
22
+ prepare_reply_to_address_from mail
23
+
24
+ prepare_subject_from mail
25
+ prepare_cc_headers_from mail, sparkpost_data
26
+ prepare_inline_content_from mail
27
+ prepare_attachments_from mail
28
+ end
29
+
30
+ prepare_substitution_data_from sparkpost_data
31
+ prepare_options_from mail, sparkpost_data
22
32
  prepare_headers
23
33
 
24
34
  result = post_to_api
@@ -27,8 +37,29 @@ module SparkPostRails
27
37
  end
28
38
 
29
39
  private
30
- def prepare_recipients_from mail
31
- @data[:recipients] = prepare_addresses(mail.to, mail[:to].display_names)
40
+ def find_sparkpost_data_from mail
41
+ if mail[:sparkpost_data]
42
+ eval(mail[:sparkpost_data].value)
43
+ else
44
+ Hash.new
45
+ end
46
+ end
47
+
48
+ def prepare_recipients_from mail, sparkpost_data
49
+ if sparkpost_data.has_key?(:recipient_list_id)
50
+ @data[:recipients] = {list_id: sparkpost_data[:recipient_list_id]}
51
+ else
52
+ @data[:recipients] = prepare_addresses(mail.to, mail[:to].display_names)
53
+
54
+ if !mail.cc.nil?
55
+ @data[:recipients] += prepare_copy_addresses(mail.cc, mail[:cc].display_names, mail.to.first).flatten
56
+ end
57
+
58
+ if !mail.bcc.nil?
59
+ @data[:recipients] += prepare_copy_addresses(mail.bcc, mail[:bcc].display_names, mail.to.first).flatten
60
+ end
61
+ end
62
+
32
63
  end
33
64
 
34
65
  def prepare_addresses emails, names
@@ -44,6 +75,34 @@ module SparkPostRails
44
75
  end
45
76
  end
46
77
 
78
+ def prepare_copy_addresses emails, names, header_to
79
+ emails = [emails] unless emails.is_a?(Array)
80
+ emails.each_with_index.map {|email, index| prepare_copy_address(email, index, names, header_to) }
81
+ end
82
+
83
+ def prepare_copy_address email, index, names, header_to
84
+ if !names[index].nil? && !header_to.nil?
85
+ { address: { email: email, name: names[index], header_to: header_to } }
86
+ elsif !names[index].nil?
87
+ { address: { email: email, name: names[index] } }
88
+ elsif !header_to.nil?
89
+ { address: { email: email, header_to: header_to } }
90
+ else
91
+ { address: { email: email } }
92
+ end
93
+ end
94
+
95
+ def prepare_template_content_from sparkpost_data
96
+ @data[:content][:template_id] = sparkpost_data[:template_id]
97
+
98
+ end
99
+
100
+ def prepare_substitution_data_from sparkpost_data
101
+ if sparkpost_data[:substitution_data]
102
+ @data[:substitution_data] = sparkpost_data[:substitution_data]
103
+ end
104
+ end
105
+
47
106
  def prepare_from_address_from mail
48
107
  if !mail[:from].display_names.first.nil?
49
108
  from = { email: mail.from.first, name: mail[:from].display_names.first }
@@ -64,10 +123,29 @@ module SparkPostRails
64
123
  @data[:content][:subject] = mail.subject
65
124
  end
66
125
 
67
- def prepare_content_from mail
126
+ def prepare_cc_headers_from mail, sparkpost_data
127
+ if !mail[:cc].nil? && !sparkpost_data.has_key?(:recipient_list_id)
128
+ copies = prepare_addresses(mail.cc, mail[:cc].display_names)
129
+ emails = []
130
+
131
+ copies.each do |copy|
132
+ emails << copy[:address][:email]
133
+ end
134
+
135
+ @data[:content][:headers] = { cc: emails }
136
+ end
137
+ end
138
+
139
+
140
+ def prepare_inline_content_from mail
68
141
  if mail.multipart?
69
- @data[:content][:html] = cleanse_encoding(mail.html_part.body.to_s)
70
- @data[:content][:text] = cleanse_encoding(mail.text_part.body.to_s)
142
+ if mail.html_part
143
+ @data[:content][:html] = cleanse_encoding(mail.html_part.body.to_s)
144
+ end
145
+
146
+ if mail.text_part
147
+ @data[:content][:text] = cleanse_encoding(mail.text_part.body.to_s)
148
+ end
71
149
  else
72
150
  @data[:content][:text] = cleanse_encoding(mail.body.to_s)
73
151
  end
@@ -77,18 +155,95 @@ module SparkPostRails
77
155
  ::JSON.parse({c: content}.to_json)["c"]
78
156
  end
79
157
 
80
- def prepare_options
81
- @data[:options] = {
82
- :open_tracking => SparkPostRails.configuration.track_opens,
83
- :click_tracking => SparkPostRails.configuration.track_clicks
84
- }
158
+ def prepare_attachments_from mail
159
+ attachments = Array.new
160
+ inline_images = Array.new
161
+
162
+ mail.attachments.each do |attachment|
163
+ #We decode and reencode here to ensure that attachments are
164
+ #Base64 encoded without line breaks as required by the API.
165
+ attachment_data = { name: attachment.filename,
166
+ type: attachment.content_type,
167
+ data: Base64.encode64(attachment.body.decoded).gsub("\n","") }
168
+
169
+ if attachment.inline?
170
+ inline_images << attachment_data
171
+ else
172
+ attachments << attachment_data
173
+ end
174
+ end
175
+
176
+ if attachments.count > 0
177
+ @data[:content][:attachments] = attachments
178
+ end
179
+
180
+ if inline_images.count > 0
181
+ @data[:content][:inline_images] = inline_images
182
+ end
183
+ end
184
+
185
+ def prepare_options_from mail, sparkpost_data
186
+ @data[:options] = Hash.new
187
+
188
+ prepare_sandbox_mode_from sparkpost_data
189
+ prepare_open_tracking_from sparkpost_data
190
+ prepare_click_tracking_from sparkpost_data
191
+ prepare_campaign_id_from sparkpost_data
192
+ prepare_return_path_from mail
193
+
194
+ end
195
+
196
+ def prepare_sandbox_mode_from sparkpost_data
197
+ if SparkPostRails.configuration.sandbox
198
+ @data[:options][:sandbox] = true
199
+ end
200
+
201
+ if sparkpost_data.has_key?(:sandbox)
202
+ if sparkpost_data[:sandbox]
203
+ @data[:options][:sandbox] = sparkpost_data[:sandbox]
204
+ else
205
+ @data[:options].delete(:sandbox)
206
+ end
207
+ end
208
+ end
209
+
210
+ def prepare_open_tracking_from sparkpost_data
211
+ @data[:options][:open_tracking] = SparkPostRails.configuration.track_opens
212
+
213
+ if sparkpost_data.has_key?(:track_opens)
214
+ @data[:options][:open_tracking] = sparkpost_data[:track_opens]
215
+ end
216
+ end
217
+
218
+ def prepare_click_tracking_from sparkpost_data
219
+ @data[:options][:click_tracking] = SparkPostRails.configuration.track_clicks
220
+
221
+ if sparkpost_data.has_key?(:track_clicks)
222
+ @data[:options][:click_tracking] = sparkpost_data[:track_clicks]
223
+ end
224
+ end
225
+
226
+ def prepare_campaign_id_from sparkpost_data
227
+ campaign_id = SparkPostRails.configuration.campaign_id
228
+
229
+ if sparkpost_data.has_key?(:campaign_id)
230
+ campaign_id = sparkpost_data[:campaign_id]
231
+ end
232
+
233
+ if campaign_id
234
+ @data[:campaign_id] = campaign_id
235
+ end
236
+ end
237
+
238
+ def prepare_return_path_from mail
239
+ return_path = SparkPostRails.configuration.return_path
85
240
 
86
- unless SparkPostRails.configuration.campaign_id.nil?
87
- @data[:campaign_id] = SparkPostRails.configuration.campaign_id
241
+ unless mail.return_path.nil?
242
+ return_path = mail.return_path
88
243
  end
89
244
 
90
- unless SparkPostRails.configuration.return_path.nil?
91
- @data[:return_path] = SparkPostRails.configuration.return_path
245
+ if return_path
246
+ @data[:return_path] = return_path
92
247
  end
93
248
  end
94
249
 
@@ -1,4 +1,4 @@
1
1
  module SparkPostRails
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
4
4
 
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe SparkPostRails::DeliveryMethod do
4
+
5
+ before(:each) do
6
+ @delivery_method = SparkPostRails::DeliveryMethod.new
7
+ end
8
+
9
+ context "No Attachments" do
10
+ it "does not include attachment elements in the data" do
11
+ test_email = Mailer.test_email
12
+ @delivery_method.deliver!(test_email)
13
+
14
+ expect(@delivery_method.data[:content].has_key?(:attachments)).to eq(false)
15
+ expect(@delivery_method.data[:content].has_key?(:inline_images)).to eq(false)
16
+ end
17
+ end
18
+
19
+ context "Standard Attachments" do
20
+ it "accepts a single attachment" do
21
+ test_email = Mailer.test_email attachments: 1
22
+ @delivery_method.deliver!(test_email)
23
+
24
+ expect(@delivery_method.data[:content][:attachments]).to eq([{:name=>"file_0.txt", :type=>"text/plain; filename=file_0.txt", :data=>"VGhpcyBpcyBmaWxlIDA="}])
25
+ end
26
+
27
+ it "accepts multiple attachments" do
28
+ test_email = Mailer.test_email attachments: 2
29
+ @delivery_method.deliver!(test_email)
30
+
31
+ expect(@delivery_method.data[:content][:attachments]).to eq([{:name=>"file_0.txt", :type=>"text/plain; filename=file_0.txt", :data=>"VGhpcyBpcyBmaWxlIDA="}, {:name=>"file_1.txt", :type=>"text/plain; filename=file_1.txt", :data=>"VGhpcyBpcyBmaWxlIDE="}])
32
+ end
33
+
34
+ it "accepts a single image attachment" do
35
+ test_email = Mailer.test_email images: 1
36
+ @delivery_method.deliver!(test_email)
37
+
38
+ expect(@delivery_method.data[:content][:attachments]).to eq([{:name=>"image_0.png", :type=>"image/png; filename=image_0.png", :data=>"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"}])
39
+ end
40
+ end
41
+
42
+ context "Inline Attachments" do
43
+ it "accepts an inline attachment" do
44
+ test_email = Mailer.test_email inline_attachments: 1
45
+ @delivery_method.deliver!(test_email)
46
+
47
+ expect(@delivery_method.data[:content][:inline_images]).to eq([{:name=>"image_0.png", :type=>"image/png; filename=image_0.png", :data=>"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"}])
48
+ end
49
+
50
+ end
51
+
52
+ end