sparkpost_rails_eu 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +230 -0
- data/lib/sparkpost_rails.rb +64 -0
- data/lib/sparkpost_rails/data_options.rb +25 -0
- data/lib/sparkpost_rails/delivery_method.rb +402 -0
- data/lib/sparkpost_rails/exceptions.rb +17 -0
- data/lib/sparkpost_rails/railtie.rb +15 -0
- data/lib/sparkpost_rails/version.rb +4 -0
- data/spec/attachments_spec.rb +56 -0
- data/spec/bcc_recipients_spec.rb +102 -0
- data/spec/campaign_id_spec.rb +64 -0
- data/spec/cc_recipients_spec.rb +119 -0
- data/spec/click_tracking_spec.rb +54 -0
- data/spec/configuration_spec.rb +12 -0
- data/spec/delivery_schedule_spec.rb +46 -0
- data/spec/description_spec.rb +39 -0
- data/spec/exceptions_spec.rb +65 -0
- data/spec/from_spec.rb +24 -0
- data/spec/headers_spec.rb +33 -0
- data/spec/inline_content_spec.rb +63 -0
- data/spec/inline_css_spec.rb +49 -0
- data/spec/ip_pool_spec.rb +50 -0
- data/spec/metadata_spec.rb +44 -0
- data/spec/open_tracking_spec.rb +54 -0
- data/spec/recipient_specific_data_spec.rb +30 -0
- data/spec/recipients_list_spec.rb +34 -0
- data/spec/recipients_spec.rb +62 -0
- data/spec/reply_to_spec.rb +25 -0
- data/spec/response_spec.rb +26 -0
- data/spec/return_path_spec.rb +50 -0
- data/spec/sandbox_mode_spec.rb +53 -0
- data/spec/skip_suppression_spec.rb +27 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/subaccount_api_spec.rb +75 -0
- data/spec/substitution_data_spec.rb +40 -0
- data/spec/template_spec.rb +36 -0
- data/spec/transactional_spec.rb +50 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 389e52647f591e59d115e55cf157c1bcb65a44edaf351d027e69f6526d3d3c98
|
4
|
+
data.tar.gz: 8ca903cf8d6f5bc6b82c95d7b54844c497588e3ada33ffa512901a4b5abb7b37
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e79ba82eb5d9cd19cd8bd4b37ef86d48128c8c6b6e99239def3e889a68c38e070107d4b6855076da07a519581fbcd099628b7ff47316ed0e4144b37f1f0e797
|
7
|
+
data.tar.gz: e875f7e1ca1c8b755cd28a00f6e54fbcd55aa32ae15b83d5144f23e3937d8c24f4593fc6c8043d3f4d4e9287bc5dbbd25ab904cd1ae810bd26b35d6a858d5b88
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Kevin Kimball
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/sparkpost_rails.svg)](https://badge.fury.io/rb/sparkpost_rails)
|
2
|
+
[![Build Status](https://travis-ci.org/the-refinery/sparkpost_rails.svg?branch=master)](https://travis-ci.org/the-refinery/sparkpost_rails)
|
3
|
+
|
4
|
+
SparkPost Rails
|
5
|
+
===============
|
6
|
+
|
7
|
+
This gem provides seamless integration of SparkPost with ActionMailer. It provides a `delivery_method` based upon the SparkPost API, and makes getting setup and sending email via SparkPost in a Rails app pretty painless.
|
8
|
+
|
9
|
+
Getting Started
|
10
|
+
---------------
|
11
|
+
|
12
|
+
Add the gem to your Gemfile
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'sparkpost_rails'
|
16
|
+
```
|
17
|
+
|
18
|
+
Then run the bundle command to install it.
|
19
|
+
|
20
|
+
By default, the gem will look for your SparkPost API key in your environment, with the key `SPARKPOST_API_KEY`. You can override this setting by identifying a different key in the initializer (`config/initializers/sparkpost_rails.rb`):
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
SparkPostRails.configure do |c|
|
24
|
+
c.api_key = 'YOUR API KEY'
|
25
|
+
end
|
26
|
+
```
|
27
|
+
Note that an initializer file is not required to use this gem. If an initializer is not provided, default values will be used. See ["Additional Configuration"](#additional-configuration) below for a list of all the default settings.
|
28
|
+
|
29
|
+
In each environment configuration file from which you want to send emails via Sparkpost, (i.e. `config/environments/production.rb`) add
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
config.action_mailer.delivery_method = :sparkpost
|
33
|
+
```
|
34
|
+
|
35
|
+
Additional Configuration
|
36
|
+
------------------------
|
37
|
+
You can establish values for a number of SparkPost settings in the initializer. These values will be used for every message sent from your application. You can override these settings on individual messages.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
SparkPostRails.configure do |c|
|
41
|
+
c.sandbox = true # default: false
|
42
|
+
c.track_opens = true # default: false
|
43
|
+
c.track_clicks = true # default: false
|
44
|
+
c.return_path = 'BOUNCE-EMAIL@YOUR-DOMAIN.COM' # default: nil
|
45
|
+
c.campaign_id = 'YOUR-CAMPAIGN' # default: nil
|
46
|
+
c.transactional = true # default: false
|
47
|
+
c.ip_pool = "MY-POOL" # default: nil
|
48
|
+
c.inline_css = true # default: false
|
49
|
+
c.html_content_only = true # default: false
|
50
|
+
c.subaccount = "123" # default: nil
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
Usage
|
55
|
+
-----
|
56
|
+
When calling the `deliver!` method on the mail object returned from your mailer, `SparkPostRails` provides the response data directly back from SparkPost as a hash.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
result = MyMailer.welcome_message(user).deliver!
|
60
|
+
```
|
61
|
+
|
62
|
+
Example:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
{
|
66
|
+
"total_rejected_recipients" => 0,
|
67
|
+
"total_accepted_recipients" => 1,
|
68
|
+
"id" => "00000000000000"
|
69
|
+
}
|
70
|
+
```
|
71
|
+
|
72
|
+
If the SparkPost API reponds with an error condition, SparkPostRails will raise a `SparkPostRails::DeliveryException`, which will include all the message data returned by the API.
|
73
|
+
|
74
|
+
SparkPostRails will support multiple recipients, multilple CC, multiple BCC, ReplyTo address, file attachments, inline images, multi-part (HTML and plaintext) messages - all utilizing the standard `ActionMailer` methodologies.
|
75
|
+
|
76
|
+
Handling Errors
|
77
|
+
---------------
|
78
|
+
If you are using `ActiveJob` and wish to do something special when the SparkPost API responds with an error condition you can do so by rescuing these exceptions via `ActionMailer::DeliveryJob`. Simply add an initializer:
|
79
|
+
|
80
|
+
`config/initializers/action_mailer.rb`
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
ActionMailer::DeliveryJob.rescue_from(SparkPostRails::DeliveryException) do |exception|
|
84
|
+
# do something special with the error
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
SparkPost-Specific Features
|
89
|
+
---------------------------
|
90
|
+
|
91
|
+
### Configuration Settings
|
92
|
+
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 to the mail message in a field named `sparkpost_data`:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
data = {
|
96
|
+
track_opens: true,
|
97
|
+
track_clicks: false,
|
98
|
+
campaign_id: "My Campaign",
|
99
|
+
transactional: true,
|
100
|
+
ip_pool = "SPECIAL_POOL",
|
101
|
+
api_key = "MESSAGE_SPECIFIC_API_KEY"
|
102
|
+
subaccount = "123"
|
103
|
+
}
|
104
|
+
|
105
|
+
mail(to: to_email, subject: "Test", body: "test", sparkpost_data: data)
|
106
|
+
```
|
107
|
+
|
108
|
+
Additionally, `return_path` can be overriden on a specific email by setting that field on the mail message itself:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
mail(to: to_email, subject: "Test", body: "test", return_path: "bounces@example.com")
|
112
|
+
```
|
113
|
+
|
114
|
+
### Transmission Specific Settings
|
115
|
+
|
116
|
+
For an individual transmisison you can specifiy that SparkPost should ignore customer supression rules - if your SparkPost account allows for this feature. Simply include the flag in the `sparkpost_data` field on the message:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
data = { skip_suppression: true }
|
120
|
+
|
121
|
+
mail(to: to_email, subject: "Test", body: "test", sparkpost_data: data)
|
122
|
+
```
|
123
|
+
|
124
|
+
To schedule the generation of messages for a future date and time, specify a start time in the `date` parameter of the mail. The `date` must be in the future and less than 1 year from today. If `date` is in the past or too far in the future, no date will be passed, and no delivery schedule will be set.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
start_time = DateTime.now + 4.hours
|
128
|
+
|
129
|
+
mail(to: to_email, subject: "Test", body: "test", date: start_time)
|
130
|
+
```
|
131
|
+
|
132
|
+
You can set a `description` for a transmission via the `sparkpost_data` as well. The maximum length of the `decription` is 1024 characters - values longer than the maxium will be truncated.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
data = { description: "My Important Message" }
|
136
|
+
|
137
|
+
mail(to: to_email, subject: "Test", body: "test", sparkpost_data: data)
|
138
|
+
```
|
139
|
+
|
140
|
+
By default, content from single-part messages is sent at plain-text. If you are only intending to send HTML email, with no plain-text part, you can specify this as shown below. You can also set this in the configuration to ensure that all single-part emails are sent as HTML.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
data = { html_content_only: true }
|
144
|
+
|
145
|
+
mail(to: to_email, subject: "Test", body: "<h1>test</h1>", sparkpost_data: data)
|
146
|
+
```
|
147
|
+
|
148
|
+
### Subaccounts
|
149
|
+
|
150
|
+
SparkPostRails supports sending messages via subaccounts in two ways. The default API key set in the configuration can be overriden on a message-by-message basis with a subaccount API key.
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
data = { api_key: "SUBACCOUNT_API_KEY" }
|
154
|
+
|
155
|
+
mail(subject: "Test", body: "test", sparkpost_data: data)
|
156
|
+
```
|
157
|
+
|
158
|
+
Subaccounts can also be leveraged using the subaccount ID with the master API key.
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
data = { subaccount: "123" }
|
162
|
+
|
163
|
+
mail(subject: "Test", body: "test", sparkpost_data: data)
|
164
|
+
```
|
165
|
+
|
166
|
+
### Recipient Lists
|
167
|
+
SparkPostRails supports using SparkPost stored recipient lists. Simply add the `list_id` to the `sparkpost_data` hash on the mail message:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
data = { recipient_list_id: "MY-LIST"}
|
171
|
+
|
172
|
+
mail(subject: "Test", body: "test", sparkpost_data: data)
|
173
|
+
```
|
174
|
+
|
175
|
+
**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 not support utilizing both a recipient list and inline recipients.
|
176
|
+
|
177
|
+
|
178
|
+
### Substitution Data
|
179
|
+
You can leverage SparkPost's substitution engine through the gem as well. To supply substitution data, simply add your hash of substitution data to your `sparkpost_data` hash, with the key `substitution_data`.
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
sub_data = {
|
183
|
+
first_name: "Sam",
|
184
|
+
last_name: "Test
|
185
|
+
}
|
186
|
+
|
187
|
+
data = { substitution_data: sub_data }
|
188
|
+
|
189
|
+
mail(to: to_email, subject: "Test", body: "test", sparkpost_data: data)
|
190
|
+
```
|
191
|
+
|
192
|
+
### Recipient-Specific Data
|
193
|
+
When sending to multiple recipients, you can pass an array of data to complement each recipient. Simply pass an array called `recipients` containing an array of the additional data (e.g. `substitution_data`).
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
recipients = ['recipient1@email.com', 'recipient2@email.com']
|
197
|
+
sparkpost_data = {
|
198
|
+
recipients: [
|
199
|
+
{ substitution_data: { name: 'Recipient1' } },
|
200
|
+
{ substitution_data: { name: 'Recipient2' } }
|
201
|
+
]
|
202
|
+
}
|
203
|
+
mail(to: recipients, sparkpost_data: sparkpost_data)
|
204
|
+
```
|
205
|
+
|
206
|
+
|
207
|
+
### Using SparkPost Templates
|
208
|
+
You can leverage SparkPost's powerful templates rather than building ActionMailer views using SparkPostRails. Add your `template_id` to the `sparkpost_data` hash. By default, `ActionMailer` finds a template to use within views. A workaround to prevent this default action is to explicitly pass a block with an empty `text` part:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
data = { template_id: "MY-TEMPLATE" }
|
212
|
+
|
213
|
+
mail(to: to_email, sparkpost_data: data) do |format|
|
214
|
+
format.text { render text: "" }
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
**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 supplied. This includes `Subject`, `From`, `ReplyTo`, Attachments, and Inline Images.
|
219
|
+
|
220
|
+
###Other Mail Headers
|
221
|
+
If you need to identify custom mail headers for your messages, use the `ActionMailer` `header[]` method. The gem will pass all approprite headers through to the API. Note, per the SparkPost API documentation
|
222
|
+
|
223
|
+
> Headers such as 'Content-Type' and 'Content-Transfer-Encoding' are not allowed here as they are auto-generated upon construction of the email.
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
headers["Priority"] = "urgent"
|
227
|
+
headers["Sensitivity"] = "private"
|
228
|
+
|
229
|
+
mail(to: to_email, subject: "Test", body: "test")
|
230
|
+
```
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "sparkpost_rails/data_options"
|
2
|
+
require "sparkpost_rails/delivery_method"
|
3
|
+
require "sparkpost_rails/exceptions"
|
4
|
+
require "sparkpost_rails/railtie"
|
5
|
+
|
6
|
+
module SparkPostRails
|
7
|
+
class << self
|
8
|
+
attr_accessor :configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.configuration
|
12
|
+
@configuration ||= Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure
|
16
|
+
self.configuration ||= Configuration.new
|
17
|
+
yield(configuration)
|
18
|
+
end
|
19
|
+
|
20
|
+
class Configuration
|
21
|
+
attr_accessor :api_key
|
22
|
+
attr_accessor :sandbox
|
23
|
+
|
24
|
+
attr_accessor :track_opens
|
25
|
+
attr_accessor :track_clicks
|
26
|
+
|
27
|
+
attr_accessor :campaign_id
|
28
|
+
attr_accessor :return_path
|
29
|
+
|
30
|
+
attr_accessor :transactional
|
31
|
+
attr_accessor :ip_pool
|
32
|
+
attr_accessor :inline_css
|
33
|
+
attr_accessor :html_content_only
|
34
|
+
|
35
|
+
attr_accessor :subaccount
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
set_defaults
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_defaults
|
42
|
+
if ENV.has_key?("SPARKPOST_API_KEY")
|
43
|
+
@api_key = ENV["SPARKPOST_API_KEY"]
|
44
|
+
else
|
45
|
+
@api_key = ""
|
46
|
+
end
|
47
|
+
|
48
|
+
@sandbox = false
|
49
|
+
|
50
|
+
@track_opens = false
|
51
|
+
@track_clicks = false
|
52
|
+
|
53
|
+
@campaign_id = nil
|
54
|
+
@return_path = nil
|
55
|
+
|
56
|
+
@transactional = false
|
57
|
+
@ip_pool = nil
|
58
|
+
@inline_css = false
|
59
|
+
@html_content_only = false
|
60
|
+
|
61
|
+
@subaccount = nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SparkPostRails
|
2
|
+
module DataOptions
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
prepend InstanceMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
|
12
|
+
def mail(headers={}, &block)
|
13
|
+
headers = headers.clone
|
14
|
+
sparkpost_data = headers.delete(:sparkpost_data)
|
15
|
+
sparkpost_data ||= {}
|
16
|
+
super(headers, &block).tap do |message|
|
17
|
+
message.singleton_class.class_eval { attr_accessor "sparkpost_data" }
|
18
|
+
message.sparkpost_data = sparkpost_data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,402 @@
|
|
1
|
+
module SparkPostRails
|
2
|
+
class DeliveryMethod
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
attr_accessor :settings, :data, :response, :headers
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@settings = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def deliver!(mail)
|
12
|
+
@data = {content: {}}
|
13
|
+
|
14
|
+
sparkpost_data = find_sparkpost_data_from mail
|
15
|
+
|
16
|
+
prepare_recipients_from mail, sparkpost_data
|
17
|
+
prepare_recipients_data_from sparkpost_data
|
18
|
+
|
19
|
+
if sparkpost_data.has_key?(:template_id)
|
20
|
+
prepare_template_content_from sparkpost_data
|
21
|
+
else
|
22
|
+
prepare_from_address_from mail
|
23
|
+
prepare_reply_to_address_from mail
|
24
|
+
|
25
|
+
prepare_subject_from mail
|
26
|
+
prepare_cc_headers_from mail, sparkpost_data
|
27
|
+
prepare_inline_content_from mail, sparkpost_data
|
28
|
+
prepare_attachments_from mail
|
29
|
+
end
|
30
|
+
|
31
|
+
prepare_substitution_data_from sparkpost_data
|
32
|
+
prepare_metadata_from sparkpost_data
|
33
|
+
prepare_description_from sparkpost_data
|
34
|
+
prepare_options_from mail, sparkpost_data
|
35
|
+
prepare_additional_mail_headers_from mail
|
36
|
+
|
37
|
+
prepare_api_headers_from sparkpost_data
|
38
|
+
|
39
|
+
result = post_to_api
|
40
|
+
|
41
|
+
process_result result
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def find_sparkpost_data_from mail
|
46
|
+
mail.sparkpost_data
|
47
|
+
end
|
48
|
+
|
49
|
+
def prepare_recipients_from mail, sparkpost_data
|
50
|
+
if sparkpost_data.has_key?(:recipient_list_id)
|
51
|
+
@data[:recipients] = {list_id: sparkpost_data[:recipient_list_id]}
|
52
|
+
else
|
53
|
+
@data[:recipients] = prepare_addresses(mail.to, mail[:to].display_names)
|
54
|
+
|
55
|
+
if !mail.cc.nil?
|
56
|
+
@data[:recipients] += prepare_copy_addresses(mail.cc, mail[:cc].display_names, mail.to.first).flatten
|
57
|
+
end
|
58
|
+
|
59
|
+
if !mail.bcc.nil?
|
60
|
+
@data[:recipients] += prepare_copy_addresses(mail.bcc, mail[:bcc].display_names, mail.to.first).flatten
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepare_addresses emails, names
|
67
|
+
emails = [emails] unless emails.is_a?(Array)
|
68
|
+
header_to = emails.join(",")
|
69
|
+
emails.each_with_index.map {|email, index| prepare_address(email, index, names, header_to) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def prepare_address email, index, names, header_to
|
73
|
+
if !names[index].nil?
|
74
|
+
{ address: { email: email, name: names[index], header_to: header_to } }
|
75
|
+
else
|
76
|
+
{ address: { email: email, header_to: header_to } }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def prepare_copy_addresses emails, names, header_to
|
81
|
+
emails = [emails] unless emails.is_a?(Array)
|
82
|
+
emails.each_with_index.map {|email, index| prepare_copy_address(email, index, names, header_to) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def prepare_copy_address email, index, names, header_to
|
86
|
+
if !names[index].nil? && !header_to.nil?
|
87
|
+
{ address: { email: email, name: names[index], header_to: header_to } }
|
88
|
+
elsif !names[index].nil?
|
89
|
+
{ address: { email: email, name: names[index] } }
|
90
|
+
elsif !header_to.nil?
|
91
|
+
{ address: { email: email, header_to: header_to } }
|
92
|
+
else
|
93
|
+
{ address: { email: email } }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# See https://developers.sparkpost.com/api/#/introduction/substitutions-reference/links-and-substitution-expressions-within-substitution-values
|
98
|
+
def prepare_recipients_data_from sparkpost_data
|
99
|
+
if (recipients_data = sparkpost_data[:recipients])
|
100
|
+
@data[:recipients].each_with_index do |recipient, index|
|
101
|
+
if (recipient_data = recipients_data[index])
|
102
|
+
recipient.merge!(recipient_data)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def prepare_template_content_from sparkpost_data
|
109
|
+
@data[:content][:template_id] = sparkpost_data[:template_id]
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
def prepare_substitution_data_from sparkpost_data
|
114
|
+
if sparkpost_data[:substitution_data]
|
115
|
+
@data[:substitution_data] = sparkpost_data[:substitution_data]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def prepare_metadata_from sparkpost_data
|
120
|
+
if sparkpost_data[:metadata]
|
121
|
+
@data[:metadata] = sparkpost_data[:metadata]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def prepare_from_address_from mail
|
126
|
+
if !mail[:from].display_names.first.nil?
|
127
|
+
from = { email: mail.from.first, name: mail[:from].display_names.first }
|
128
|
+
else
|
129
|
+
from = { email: mail.from.first }
|
130
|
+
end
|
131
|
+
|
132
|
+
@data[:content][:from] = from
|
133
|
+
end
|
134
|
+
|
135
|
+
def prepare_reply_to_address_from mail
|
136
|
+
unless mail.reply_to.nil?
|
137
|
+
@data[:content][:reply_to] = mail.reply_to.first
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def prepare_subject_from mail
|
142
|
+
@data[:content][:subject] = mail.subject
|
143
|
+
end
|
144
|
+
|
145
|
+
def prepare_cc_headers_from mail, sparkpost_data
|
146
|
+
if !mail[:cc].nil? && !sparkpost_data.has_key?(:recipient_list_id)
|
147
|
+
copies = prepare_addresses(mail.cc, mail[:cc].display_names)
|
148
|
+
emails = []
|
149
|
+
|
150
|
+
copies.each do |copy|
|
151
|
+
emails << copy[:address][:email]
|
152
|
+
end
|
153
|
+
|
154
|
+
@data[:content][:headers] = { cc: emails.join(",") }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def prepare_inline_content_from mail, sparkpost_data
|
159
|
+
if mail.multipart?
|
160
|
+
if mail.html_part
|
161
|
+
@data[:content][:html] = cleanse_encoding(mail.html_part.body.to_s)
|
162
|
+
end
|
163
|
+
|
164
|
+
if mail.text_part
|
165
|
+
@data[:content][:text] = cleanse_encoding(mail.text_part.body.to_s)
|
166
|
+
end
|
167
|
+
else
|
168
|
+
if SparkPostRails.configuration.html_content_only || sparkpost_data[:html_content_only]
|
169
|
+
@data[:content][:html] = cleanse_encoding(mail.body.to_s)
|
170
|
+
else
|
171
|
+
@data[:content][:text] = cleanse_encoding(mail.body.to_s)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def cleanse_encoding content
|
177
|
+
::JSON.parse({c: content}.to_json)["c"]
|
178
|
+
end
|
179
|
+
|
180
|
+
def prepare_attachments_from mail
|
181
|
+
attachments = Array.new
|
182
|
+
inline_images = Array.new
|
183
|
+
|
184
|
+
mail.attachments.each do |attachment|
|
185
|
+
#We decode and reencode here to ensure that attachments are
|
186
|
+
#Base64 encoded without line breaks as required by the API.
|
187
|
+
attachment_data = { name: attachment.inline? ? attachment.cid : attachment.filename,
|
188
|
+
type: attachment.content_type,
|
189
|
+
data: Base64.strict_encode64(attachment.body.decoded) }
|
190
|
+
|
191
|
+
if attachment.inline?
|
192
|
+
inline_images << attachment_data
|
193
|
+
else
|
194
|
+
attachments << attachment_data
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
if attachments.count > 0
|
199
|
+
@data[:content][:attachments] = attachments
|
200
|
+
end
|
201
|
+
|
202
|
+
if inline_images.count > 0
|
203
|
+
@data[:content][:inline_images] = inline_images
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def prepare_options_from mail, sparkpost_data
|
208
|
+
@data[:options] = Hash.new
|
209
|
+
|
210
|
+
prepare_sandbox_mode_from sparkpost_data
|
211
|
+
prepare_open_tracking_from sparkpost_data
|
212
|
+
prepare_click_tracking_from sparkpost_data
|
213
|
+
prepare_campaign_id_from sparkpost_data
|
214
|
+
prepare_return_path_from mail
|
215
|
+
prepare_transactional_from sparkpost_data
|
216
|
+
prepare_skip_suppression_from sparkpost_data
|
217
|
+
prepare_ip_pool_from sparkpost_data
|
218
|
+
prepare_inline_css_from sparkpost_data
|
219
|
+
prepare_delivery_schedule_from mail
|
220
|
+
end
|
221
|
+
|
222
|
+
def prepare_sandbox_mode_from sparkpost_data
|
223
|
+
if SparkPostRails.configuration.sandbox
|
224
|
+
@data[:options][:sandbox] = true
|
225
|
+
end
|
226
|
+
|
227
|
+
if sparkpost_data.has_key?(:sandbox)
|
228
|
+
if sparkpost_data[:sandbox]
|
229
|
+
@data[:options][:sandbox] = sparkpost_data[:sandbox]
|
230
|
+
else
|
231
|
+
@data[:options].delete(:sandbox)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def prepare_open_tracking_from sparkpost_data
|
237
|
+
@data[:options][:open_tracking] = SparkPostRails.configuration.track_opens
|
238
|
+
|
239
|
+
if sparkpost_data.has_key?(:track_opens)
|
240
|
+
@data[:options][:open_tracking] = sparkpost_data[:track_opens]
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def prepare_click_tracking_from sparkpost_data
|
245
|
+
@data[:options][:click_tracking] = SparkPostRails.configuration.track_clicks
|
246
|
+
|
247
|
+
if sparkpost_data.has_key?(:track_clicks)
|
248
|
+
@data[:options][:click_tracking] = sparkpost_data[:track_clicks]
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def prepare_campaign_id_from sparkpost_data
|
253
|
+
campaign_id = SparkPostRails.configuration.campaign_id
|
254
|
+
|
255
|
+
if sparkpost_data.has_key?(:campaign_id)
|
256
|
+
campaign_id = sparkpost_data[:campaign_id]
|
257
|
+
end
|
258
|
+
|
259
|
+
if campaign_id
|
260
|
+
@data[:campaign_id] = campaign_id
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def prepare_return_path_from mail
|
265
|
+
return_path = SparkPostRails.configuration.return_path
|
266
|
+
|
267
|
+
unless mail.return_path.nil?
|
268
|
+
return_path = mail.return_path
|
269
|
+
end
|
270
|
+
|
271
|
+
if return_path
|
272
|
+
@data[:return_path] = return_path
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def prepare_transactional_from sparkpost_data
|
277
|
+
@data[:options][:transactional] = SparkPostRails.configuration.transactional
|
278
|
+
|
279
|
+
if sparkpost_data.has_key?(:transactional)
|
280
|
+
@data[:options][:transactional] = sparkpost_data[:transactional]
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
def prepare_skip_suppression_from sparkpost_data
|
286
|
+
if sparkpost_data[:skip_suppression]
|
287
|
+
@data[:options][:skip_suppression] = sparkpost_data[:skip_suppression]
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def prepare_description_from sparkpost_data
|
292
|
+
if sparkpost_data[:description]
|
293
|
+
@data[:description] = sparkpost_data[:description].truncate(1024)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def prepare_ip_pool_from sparkpost_data
|
298
|
+
ip_pool = SparkPostRails.configuration.ip_pool
|
299
|
+
|
300
|
+
if sparkpost_data.has_key?(:ip_pool)
|
301
|
+
ip_pool = sparkpost_data[:ip_pool]
|
302
|
+
end
|
303
|
+
|
304
|
+
if ip_pool
|
305
|
+
@data[:options][:ip_pool] = ip_pool
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def prepare_inline_css_from sparkpost_data
|
310
|
+
@data[:options][:inline_css] = SparkPostRails.configuration.inline_css
|
311
|
+
|
312
|
+
if sparkpost_data.has_key?(:inline_css)
|
313
|
+
@data[:options][:inline_css] = sparkpost_data[:inline_css]
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def prepare_delivery_schedule_from mail
|
318
|
+
# Format YYYY-MM-DDTHH:MM:SS+-HH:MM or "now". Example: '2015-02-11T08:00:00-04:00'. -From SparkPost API Docs
|
319
|
+
if mail.date && (mail.date > DateTime.now) && (mail.date < (DateTime.now + 1.year))
|
320
|
+
@data[:options][:start_time] = mail.date.strftime("%Y-%m-%dT%H:%M:%S%:z")
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def prepare_additional_mail_headers_from mail
|
325
|
+
valid_headers = Hash.new
|
326
|
+
|
327
|
+
invalid_names = ["sparkpost-data",
|
328
|
+
"from",
|
329
|
+
"to",
|
330
|
+
"cc",
|
331
|
+
"bcc",
|
332
|
+
"subject",
|
333
|
+
"reply-to",
|
334
|
+
"return-path",
|
335
|
+
"date",
|
336
|
+
"mime-version",
|
337
|
+
"content-type",
|
338
|
+
"content-transfer-encoding",
|
339
|
+
"text-part"]
|
340
|
+
|
341
|
+
mail.header.fields.each do |field|
|
342
|
+
unless invalid_names.include?(field.name.downcase)
|
343
|
+
valid_headers[field.name] = field.value
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
if valid_headers.count > 0
|
348
|
+
unless @data[:content].has_key?(:headers)
|
349
|
+
@data[:content][:headers] = Hash.new
|
350
|
+
end
|
351
|
+
|
352
|
+
@data[:content][:headers].merge!(valid_headers)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def prepare_api_headers_from sparkpost_data
|
357
|
+
if sparkpost_data.has_key?(:api_key)
|
358
|
+
api_key = sparkpost_data[:api_key]
|
359
|
+
else
|
360
|
+
api_key = SparkPostRails.configuration.api_key
|
361
|
+
end
|
362
|
+
|
363
|
+
@headers = {
|
364
|
+
"Authorization" => api_key,
|
365
|
+
"Content-Type" => "application/json"
|
366
|
+
}
|
367
|
+
|
368
|
+
if sparkpost_data.has_key?(:subaccount)
|
369
|
+
subaccount = sparkpost_data[:subaccount]
|
370
|
+
else
|
371
|
+
subaccount = SparkPostRails.configuration.subaccount
|
372
|
+
end
|
373
|
+
|
374
|
+
if subaccount
|
375
|
+
@headers["X-MSYS-SUBACCOUNT"] = subaccount.to_s
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def post_to_api
|
380
|
+
url = "https://api.eu.sparkpost.com/api/v1/transmissions"
|
381
|
+
|
382
|
+
uri = URI.parse(url)
|
383
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
384
|
+
http.use_ssl = true
|
385
|
+
|
386
|
+
request = Net::HTTP::Post.new(uri.path, @headers)
|
387
|
+
request.body = JSON.generate(@data)
|
388
|
+
http.request(request)
|
389
|
+
end
|
390
|
+
|
391
|
+
def process_result result
|
392
|
+
result_data = JSON.parse(result.body)
|
393
|
+
|
394
|
+
if result_data["errors"]
|
395
|
+
@response = result_data["errors"]
|
396
|
+
raise SparkPostRails::DeliveryException, @response
|
397
|
+
else
|
398
|
+
@response = result_data["results"]
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|