sparkpost_rails_eu 1.5.1
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 +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
@@ -0,0 +1,17 @@
|
|
1
|
+
module SparkPostRails
|
2
|
+
class DeliveryException < StandardError
|
3
|
+
attr_reader :service_message, :service_description, :service_code
|
4
|
+
|
5
|
+
def initialize(message)
|
6
|
+
errors = [*message].first
|
7
|
+
|
8
|
+
if errors.is_a?(Hash)
|
9
|
+
@service_message = errors['message']
|
10
|
+
@service_description = errors['description']
|
11
|
+
@service_code = errors['code']
|
12
|
+
end
|
13
|
+
|
14
|
+
super(message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SparkPostRails
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer "sparkpost_rails.add_delivery_method" do
|
4
|
+
ActiveSupport.on_load :action_mailer do
|
5
|
+
ActionMailer::Base.add_delivery_method :sparkpost, SparkPostRails::DeliveryMethod, return_response: true
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
initializer "sparkpost_rails.extend_with_data_options" do
|
10
|
+
ActiveSupport.on_load :action_mailer do
|
11
|
+
ActionMailer::Base.send :include, SparkPostRails::DataOptions
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,56 @@
|
|
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
|
+
images = @delivery_method.data[:content][:inline_images]
|
48
|
+
expect(images.length).to eq(1)
|
49
|
+
image = images[0]
|
50
|
+
expect(image).to include(:name, :type=>"image/png; filename=image_0.png", :data=>"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")
|
51
|
+
expect(image[:name]).to match(/.*@.*/)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,102 @@
|
|
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 "BCC Recipients" do
|
10
|
+
|
11
|
+
context "single bcc recipient, no cc recipients" do
|
12
|
+
it "handles email only" do
|
13
|
+
test_email = Mailer.test_email bcc: "bcc@example.com"
|
14
|
+
@delivery_method.deliver!(test_email)
|
15
|
+
|
16
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", header_to: anything}}),
|
17
|
+
{address: {email: "bcc@example.com", header_to: "to@example.com"}}])
|
18
|
+
expect(@delivery_method.data[:content]).not_to include(:headers)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "handles name and email" do
|
22
|
+
test_email = Mailer.test_email to: "Joe Test <to1@example.com>, Sam Test <to2@example.com>", bcc: "Brock Test <bcc@example.com>"
|
23
|
+
@delivery_method.deliver!(test_email)
|
24
|
+
|
25
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", name: "Joe Test", header_to: anything}}),
|
26
|
+
a_hash_including({address: {email: "to2@example.com", name: "Sam Test", header_to: anything}}),
|
27
|
+
{address: {email: "bcc@example.com", name: "Brock Test", header_to: "to1@example.com"}}])
|
28
|
+
expect(@delivery_method.data[:content]).not_to include(:headers)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "multiple bcc recipients, no cc recipientsa" do
|
33
|
+
it "handles email only" do
|
34
|
+
test_email = Mailer.test_email bcc: "bcc1@example.com, bcc2@example.com"
|
35
|
+
@delivery_method.deliver!(test_email)
|
36
|
+
|
37
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", header_to: anything}}),
|
38
|
+
{address: {email: "bcc1@example.com", header_to: "to@example.com"}},
|
39
|
+
{address: {email: "bcc2@example.com", header_to: "to@example.com"}}])
|
40
|
+
|
41
|
+
expect(@delivery_method.data[:content]).not_to include(:headers)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "handles name and email" do
|
45
|
+
test_email = Mailer.test_email to: "Joe Test <to@example.com>", bcc: "Brock Test <bcc1@example.com>, Brack Test <bcc2@example.com>"
|
46
|
+
@delivery_method.deliver!(test_email)
|
47
|
+
|
48
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", name: "Joe Test", header_to: anything}}),
|
49
|
+
{address: {email: "bcc1@example.com", name: "Brock Test", header_to: "to@example.com"}},
|
50
|
+
{address: {email: "bcc2@example.com", name: "Brack Test", header_to: "to@example.com"}}])
|
51
|
+
expect(@delivery_method.data[:content]).not_to include(:headers)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "handles mix of email only and name/email" do
|
55
|
+
test_email = Mailer.test_email to: "Joe Test <to@example.com>", bcc: "Brock Test <bcc1@example.com>, bcc2@example.com"
|
56
|
+
@delivery_method.deliver!(test_email)
|
57
|
+
|
58
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", name: "Joe Test", header_to: anything}}),
|
59
|
+
{address: {email: "bcc1@example.com", name: "Brock Test", header_to: "to@example.com"}},
|
60
|
+
{address: {email: "bcc2@example.com", header_to: "to@example.com"}}])
|
61
|
+
expect(@delivery_method.data[:content]).not_to include(:headers)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "bcc and cc recipients" do
|
66
|
+
it "handles email only" do
|
67
|
+
test_email = Mailer.test_email to: "to1@example.com, to2@example.com", cc: "cc@example.com", bcc: "bcc@example.com"
|
68
|
+
@delivery_method.deliver!(test_email)
|
69
|
+
|
70
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", header_to: anything}}),
|
71
|
+
a_hash_including({address: {email: "to2@example.com", header_to: anything}}),
|
72
|
+
{address: {email: "cc@example.com", header_to: "to1@example.com"}},
|
73
|
+
{address: {email: "bcc@example.com", header_to: "to1@example.com"}}])
|
74
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc@example.com"})
|
75
|
+
end
|
76
|
+
|
77
|
+
it "handles name and email" do
|
78
|
+
test_email = Mailer.test_email to: "Joe Test <to1@example.com>, Sam Test <to2@example.com>", cc: "Carl Test <cc@example.com>", bcc: "Brock Test <bcc@example.com>"
|
79
|
+
@delivery_method.deliver!(test_email)
|
80
|
+
|
81
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", name: "Joe Test", header_to: anything}}),
|
82
|
+
a_hash_including({address: {email: "to2@example.com", name: "Sam Test", header_to: anything}}),
|
83
|
+
{address: {email: "cc@example.com", name: "Carl Test", header_to: "to1@example.com"}},
|
84
|
+
{address: {email: "bcc@example.com", name: "Brock Test", header_to: "to1@example.com"}}])
|
85
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc@example.com"})
|
86
|
+
end
|
87
|
+
|
88
|
+
it "handles mix of email only and name/email" do
|
89
|
+
test_email = Mailer.test_email to: "Joe Test <to1@example.com>, to2@example.com", cc: "cc1@example.com, Chris Test <cc2@example.com>", bcc: "Brock Test <bcc1@example.com>, bcc2@example.com"
|
90
|
+
@delivery_method.deliver!(test_email)
|
91
|
+
|
92
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", name: "Joe Test", header_to: anything}}),
|
93
|
+
a_hash_including({address: {email: "to2@example.com", header_to: anything}}),
|
94
|
+
{address: {email: "cc1@example.com", header_to: "to1@example.com"}},
|
95
|
+
{address: {email: "cc2@example.com", name: "Chris Test", header_to: "to1@example.com"}},
|
96
|
+
{address: {email: "bcc1@example.com", name: "Brock Test", header_to: "to1@example.com"}},
|
97
|
+
{address: {email: "bcc2@example.com", header_to: "to1@example.com"}}])
|
98
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SparkPostRails::DeliveryMethod do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
SparkPostRails.configuration.set_defaults
|
7
|
+
@delivery_method = SparkPostRails::DeliveryMethod.new
|
8
|
+
end
|
9
|
+
|
10
|
+
context "Campaign ID" do
|
11
|
+
it "handles campaign id in the configuration" do
|
12
|
+
SparkPostRails.configure do |c|
|
13
|
+
c.campaign_id = "ABCD1234"
|
14
|
+
end
|
15
|
+
|
16
|
+
test_email = Mailer.test_email
|
17
|
+
@delivery_method.deliver!(test_email)
|
18
|
+
|
19
|
+
expect(@delivery_method.data[:campaign_id]).to eq("ABCD1234")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "handles campaign id on an individual message" do
|
23
|
+
test_email = Mailer.test_email sparkpost_data: {campaign_id: "My Campaign"}
|
24
|
+
|
25
|
+
@delivery_method.deliver!(test_email)
|
26
|
+
|
27
|
+
expect(@delivery_method.data[:campaign_id]).to eq("My Campaign")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "handles the value on an individual message overriding configuration" do
|
31
|
+
SparkPostRails.configure do |c|
|
32
|
+
c.campaign_id = "ABCD1234"
|
33
|
+
end
|
34
|
+
|
35
|
+
test_email = Mailer.test_email sparkpost_data: {campaign_id: "My Campaign"}
|
36
|
+
|
37
|
+
@delivery_method.deliver!(test_email)
|
38
|
+
|
39
|
+
expect(@delivery_method.data[:campaign_id]).to eq("My Campaign")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "handles the value on an individual message of nil overriding configuration" do
|
43
|
+
SparkPostRails.configure do |c|
|
44
|
+
c.campaign_id = "ABCD1234"
|
45
|
+
end
|
46
|
+
|
47
|
+
test_email = Mailer.test_email sparkpost_data: {campaign_id: nil}
|
48
|
+
|
49
|
+
@delivery_method.deliver!(test_email)
|
50
|
+
|
51
|
+
expect(@delivery_method.data.has_key?(:campaign_id)).to eq(false)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "handles a default setting of none" do
|
55
|
+
test_email = Mailer.test_email
|
56
|
+
@delivery_method.deliver!(test_email)
|
57
|
+
|
58
|
+
expect(@delivery_method.data.has_key?(:campaign_id)).to eq(false)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
@@ -0,0 +1,119 @@
|
|
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 "CC Recipients" do
|
10
|
+
context "single to recipient and single cc recipient" do
|
11
|
+
it "handles email only" do
|
12
|
+
test_email = Mailer.test_email cc: "cc@example.com"
|
13
|
+
@delivery_method.deliver!(test_email)
|
14
|
+
|
15
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", header_to: anything}}),
|
16
|
+
{address: {email: "cc@example.com", header_to: "to@example.com"}}])
|
17
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc@example.com"})
|
18
|
+
end
|
19
|
+
|
20
|
+
it "handles name and email" do
|
21
|
+
test_email = Mailer.test_email to: "Joe Test <to@example.com>", cc: "Carl Test <cc@example.com>"
|
22
|
+
@delivery_method.deliver!(test_email)
|
23
|
+
|
24
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", name: "Joe Test", header_to: anything}}),
|
25
|
+
{address: {email: "cc@example.com", name: "Carl Test", header_to: "to@example.com"}}])
|
26
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc@example.com"})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "single to recipient and multiple cc recipients" do
|
31
|
+
it "handles email only" do
|
32
|
+
test_email = Mailer.test_email cc: "cc1@example.com, cc2@example.com"
|
33
|
+
@delivery_method.deliver!(test_email)
|
34
|
+
|
35
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", header_to: anything}}),
|
36
|
+
{address: {email: "cc1@example.com", header_to: "to@example.com"}},
|
37
|
+
{address: {email: "cc2@example.com", header_to: "to@example.com"}}])
|
38
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
39
|
+
end
|
40
|
+
|
41
|
+
it "handles name and email" do
|
42
|
+
test_email = Mailer.test_email to: "Joe Test <to@example.com>", cc: "Carl Test <cc1@example.com>, Chris Test <cc2@example.com>"
|
43
|
+
@delivery_method.deliver!(test_email)
|
44
|
+
|
45
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", name: "Joe Test", header_to: anything}}),
|
46
|
+
{address: {email: "cc1@example.com", name: "Carl Test", header_to: "to@example.com"}},
|
47
|
+
{address: {email: "cc2@example.com", name: "Chris Test", header_to: "to@example.com"}}])
|
48
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
49
|
+
end
|
50
|
+
|
51
|
+
it "handles mix of email only and name/email" do
|
52
|
+
test_email = Mailer.test_email to: "Joe Test <to@example.com>", cc: "Carl Test <cc1@example.com>, cc2@example.com"
|
53
|
+
@delivery_method.deliver!(test_email)
|
54
|
+
|
55
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to@example.com", name: "Joe Test", header_to: anything}}),
|
56
|
+
{address: {email: "cc1@example.com", name: "Carl Test", header_to: "to@example.com"}},
|
57
|
+
{address: {email: "cc2@example.com", header_to: "to@example.com"}}])
|
58
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "multiple to recipients with single cc recipient" do
|
63
|
+
it "handles email only" do
|
64
|
+
test_email = Mailer.test_email to: "to1@example.com, to2@example.com", cc: "cc@example.com"
|
65
|
+
@delivery_method.deliver!(test_email)
|
66
|
+
|
67
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", header_to: anything}}),
|
68
|
+
a_hash_including({address: {email: "to2@example.com", header_to: anything}}),
|
69
|
+
{address: {email: "cc@example.com", header_to: "to1@example.com"}}])
|
70
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc@example.com"})
|
71
|
+
end
|
72
|
+
|
73
|
+
it "handles name and email" do
|
74
|
+
test_email = Mailer.test_email to: "Joe Test <to1@example.com>, Sam Test <to2@example.com>", cc: "Carl Test <cc@example.com>"
|
75
|
+
@delivery_method.deliver!(test_email)
|
76
|
+
|
77
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", name: "Joe Test", header_to: anything}}),
|
78
|
+
a_hash_including({address: {email: "to2@example.com", name: "Sam Test", header_to: anything}}),
|
79
|
+
{address: {email: "cc@example.com", name: "Carl Test", header_to: "to1@example.com"}}])
|
80
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc@example.com"})
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "multiple to recipients with multiple cc recipients" do
|
85
|
+
it "handles email only" do
|
86
|
+
test_email = Mailer.test_email to: "to1@example.com, to2@example.com", cc: "cc1@example.com, cc2@example.com"
|
87
|
+
@delivery_method.deliver!(test_email)
|
88
|
+
|
89
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", header_to: anything}}),
|
90
|
+
a_hash_including({address: {email: "to2@example.com", header_to: anything}}),
|
91
|
+
{address: {email: "cc1@example.com", header_to: "to1@example.com"}},
|
92
|
+
{address: {email: "cc2@example.com", header_to: "to1@example.com"}}])
|
93
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
94
|
+
end
|
95
|
+
|
96
|
+
it "handles name and email" do
|
97
|
+
test_email = Mailer.test_email to: "Joe Test <to1@example.com>, Sam Test <to2@example.com>", cc: "Carl Test <cc1@example.com>, Chris Test <cc2@example.com>"
|
98
|
+
@delivery_method.deliver!(test_email)
|
99
|
+
|
100
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", name: "Joe Test", header_to: anything}}),
|
101
|
+
a_hash_including({address: {email: "to2@example.com", name: "Sam Test", header_to: anything}}),
|
102
|
+
{address: {email: "cc1@example.com", name: "Carl Test", header_to: "to1@example.com"}},
|
103
|
+
{address: {email: "cc2@example.com", name: "Chris Test", header_to: "to1@example.com"}}])
|
104
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
105
|
+
end
|
106
|
+
|
107
|
+
it "handles mix of email only and name/email for to recipients" do
|
108
|
+
test_email = Mailer.test_email to: "Joe Test <to1@example.com>, to2@example.com", cc: "cc1@example.com, Chris Test <cc2@example.com>"
|
109
|
+
@delivery_method.deliver!(test_email)
|
110
|
+
|
111
|
+
expect(@delivery_method.data[:recipients]).to match([a_hash_including({address: {email: "to1@example.com", name: "Joe Test", header_to: anything}}),
|
112
|
+
a_hash_including({address: {email: "to2@example.com", header_to: anything}}),
|
113
|
+
{address: {email: "cc1@example.com", header_to: "to1@example.com"}},
|
114
|
+
{address: {email: "cc2@example.com", name: "Chris Test", header_to: "to1@example.com"}}])
|
115
|
+
expect(@delivery_method.data[:content][:headers]).to eq({cc: "cc1@example.com,cc2@example.com"})
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SparkPostRails::DeliveryMethod do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
SparkPostRails.configuration.set_defaults
|
7
|
+
@delivery_method = SparkPostRails::DeliveryMethod.new
|
8
|
+
end
|
9
|
+
|
10
|
+
context "Click Tracking" do
|
11
|
+
it "handles click tracking enabled in the configuration" do
|
12
|
+
SparkPostRails.configure do |c|
|
13
|
+
c.track_clicks = true
|
14
|
+
end
|
15
|
+
|
16
|
+
test_email = Mailer.test_email
|
17
|
+
|
18
|
+
@delivery_method.deliver!(test_email)
|
19
|
+
|
20
|
+
expect(@delivery_method.data[:options][:click_tracking]).to eq(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "handles click tracking enabled on an individual message" do
|
24
|
+
test_email = Mailer.test_email sparkpost_data: {track_clicks: true}
|
25
|
+
|
26
|
+
@delivery_method.deliver!(test_email)
|
27
|
+
|
28
|
+
expect(@delivery_method.data[:options][:click_tracking]).to eq(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "handles the value on an individual message overriding configuration" do
|
32
|
+
SparkPostRails.configure do |c|
|
33
|
+
c.track_clicks = true
|
34
|
+
end
|
35
|
+
|
36
|
+
test_email = Mailer.test_email sparkpost_data: {track_clicks: false}
|
37
|
+
|
38
|
+
@delivery_method.deliver!(test_email)
|
39
|
+
|
40
|
+
expect(@delivery_method.data[:options][:click_tracking]).to eq(false)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "handles a default setting of 'false'" do
|
44
|
+
test_email = Mailer.test_email
|
45
|
+
|
46
|
+
@delivery_method.deliver!(test_email)
|
47
|
+
|
48
|
+
expect(@delivery_method.data[:options][:click_tracking]).to eq(false)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "SparkPostRails configuration" do
|
4
|
+
let(:delivery_method) { SparkPostRails::DeliveryMethod.new }
|
5
|
+
|
6
|
+
describe "#configuration" do
|
7
|
+
it "creates a new configuration + defaults if #configure is never called", skip_configure: true do
|
8
|
+
config = SparkPostRails.configuration
|
9
|
+
expect(config).to_not be_nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|