sendgrid-actionmailer 2.4.2 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94259db52788333029d0c8fc9160c054a0e0bef5fc40b0ff4a2f825c9a337e54
4
- data.tar.gz: eee118a0ebb96bf3c098f6c5ec7a28ec832c2b116b4060d7ef25df18ef36d063
3
+ metadata.gz: 7e7c4317fb02b1c622b8142161339d320a1a0b49e10e2f1c8cf98c9c649e432f
4
+ data.tar.gz: 33772e1a2200cd9bdd239792b1e4c3339d13e662944afb3782399eeeaad7ac5e
5
5
  SHA512:
6
- metadata.gz: 1cb7d6f1972707fa631f27512ab36cc219373ca36725b666d05dab7ea128d270f8454cb30d45b0bc4b7d2f0460ca1ae380a2af3410c585d919461b0994d51cf1
7
- data.tar.gz: f2852025eecc5f5087a7e8b41df7cae42f93b4978acf3fb4c8a613f2a3f30eefa83b300affc72234b3f398505bab759a977473ee71a4cc8766c4eb27a3762263
6
+ metadata.gz: df22bdee0b6fbd56a2827d56b4115ec1cc62454e0ca8dc8b32bdd165699df16895a328c1b679868eee145424535b8b0f2ed0447e8e6f70e4154b6c962ed643c9
7
+ data.tar.gz: 5ceb138422116c59a4dd3d76a0197a1fe4f80dbbcdaadedf5969e328bda9a4091a5bf15f268c715d0f928ff7e8b912c5ace8556b41cbefb408124a740ce48e45
data/README.md CHANGED
@@ -221,6 +221,38 @@ Data to provide for feeding the new dynamic templates in Sendgrid with valueable
221
221
 
222
222
  ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', dynamic_template_data:{ variable_1: 'foo', variable_2: 'bar'})```
223
223
 
224
+ ### personalizations (json)
225
+
226
+ Allows providing a customized [personalizations](https://sendgrid.com/docs/for-developers/sending-email/personalizations/) array for the v3 Mail Send endpoint. This allows customizing how an email is sent and also allows sending multiple different emails to different recipients with a single API call.
227
+
228
+ The personalizations object supports:
229
+
230
+ - "to", "cc", "bcc" - The recipients of your email.
231
+ - "subject" - The subject of your email.
232
+ - "headers" - Any headers you would like to include in your email.
233
+ - "substitutions" - Any substitutions you would like to be made for your email.
234
+ - "custom_args" - Any custom arguments you would like to include in your email.
235
+ - "send_at" - A specific time that you would like your email to be sent.
236
+ - "dynamic_template_data" - data for dynamic templates.
237
+
238
+ The following should be noted about these personalization attributes:
239
+ - to, cc, or bcc: if either to, cc, or bcc is also set when calling mail, those addresses provided to mail will be inserted as a separate personalization from the ones you provide. However, when using personalizations, you are not required to specify `to` when calling the mail function.
240
+ - dynamic_template_data specified in the mail function will be merged with any dynamic_template_data specified in the personalizations object (with the personalizations object keys having priority).
241
+ - Other fields set in the personalizations object will override any global parameters defined outside of personalizations.
242
+
243
+ Also note that substitutions will not work with dynamic templates.
244
+
245
+ Example usage:
246
+
247
+ ```
248
+ mail(subject: 'default subject', 'email body', personalizations: [
249
+ { to: { email: 'example@example.com' }},
250
+ { to: { email: 'example2@example.com' }}
251
+ ])
252
+
253
+ ```
254
+
255
+
224
256
  ### Unsubscribe Links
225
257
 
226
258
  Sendgrid unfortunately uses <% %> for their default substitution syntax, which makes it incompatible with Rails templates. Their proposed solution is to use Personalization Substitutions with the v3 Mail Send Endpoint. This gem makes that modification to make the following Rails friendly unsubscribe urls.
@@ -24,17 +24,15 @@ module SendGridActionMailer
24
24
  m.from = to_email(mail.from)
25
25
  m.reply_to = to_email(mail.reply_to)
26
26
  m.subject = mail.subject || ""
27
- # https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html
28
- m.add_personalization(to_personalizations(mail))
29
27
  end
30
28
 
29
+ add_personalizations(sendgrid_mail, mail)
31
30
  add_api_key(sendgrid_mail, mail)
32
31
  add_content(sendgrid_mail, mail)
33
32
  add_send_options(sendgrid_mail, mail)
34
33
  add_mail_settings(sendgrid_mail, mail)
35
34
  add_tracking_settings(sendgrid_mail, mail)
36
35
 
37
-
38
36
  response = perform_send_request(sendgrid_mail)
39
37
 
40
38
  settings[:return_response] ? response : self
@@ -75,20 +73,49 @@ module SendGridActionMailer
75
73
  end
76
74
  end
77
75
 
78
- def to_personalizations(mail)
79
- Personalization.new.tap do |p|
80
- to_emails(mail.to).each { |to| p.add_to(to) }
81
- to_emails(mail.cc).each { |cc| p.add_cc(cc) }
82
- to_emails(mail.bcc).each { |bcc| p.add_bcc(bcc) }
76
+ def setup_personalization(mail, personalization_hash)
77
+ p = Personalization.new
83
78
 
79
+ (personalization_hash['to'] || []).each do |to|
80
+ p.add_to Email.new(email: to['email'], name: to['name'])
81
+ end
82
+ (personalization_hash['cc'] || []).each do |cc|
83
+ p.add_cc Email.new(email: cc['email'], name: cc['name'])
84
+ end
85
+ (personalization_hash['bcc'] || []).each do |bcc|
86
+ p.add_bcc Email.new(email: bcc['email'], name: bcc['name'])
87
+ end
88
+ (personalization_hash['headers'] || []).each do |header_key, header_value|
89
+ p.add_header Header.new(key: header_key, value: header_value)
90
+ end
91
+ (personalization_hash['substitutions'] || {}).each do |sub_key, sub_value|
92
+ p.add_substitution(Substitution.new(key: sub_key, value: sub_value))
93
+ end
94
+ (personalization_hash['custom_args'] || {}).each do |arg_key, arg_value|
95
+ p.add_custom_arg(CustomArg.new(key: arg_key, value: arg_value))
96
+ end
97
+ if personalization_hash['send_at']
98
+ p.send_at = personalization_hash['send_at']
99
+ end
100
+ if personalization_hash['subject']
101
+ p.subject = personalization_hash['subject']
102
+ end
103
+
104
+ if mail['dynamic_template_data'] || personalization_hash['dynamic_template_data']
84
105
  if mail['dynamic_template_data']
85
- p.add_dynamic_template_data(json_parse(mail['dynamic_template_data'].value))
86
- elsif mail['template_id'].nil?
87
- p.add_substitution(Substitution.new(key: "%asm_group_unsubscribe_raw_url%", value: "<%asm_group_unsubscribe_raw_url%>"))
88
- p.add_substitution(Substitution.new(key: "%asm_global_unsubscribe_raw_url%", value: "<%asm_global_unsubscribe_raw_url%>"))
89
- p.add_substitution(Substitution.new(key: "%asm_preferences_raw_url%", value: "<%asm_preferences_raw_url%>"))
106
+ data = json_parse(mail['dynamic_template_data'].value, false)
107
+ data.merge!(personalization_hash['dynamic_template_data'] || {})
108
+ else
109
+ data = personalization_hash['dynamic_template_data']
90
110
  end
111
+ p.add_dynamic_template_data(data)
112
+ elsif mail['template_id'].nil?
113
+ p.add_substitution(Substitution.new(key: "%asm_group_unsubscribe_raw_url%", value: "<%asm_group_unsubscribe_raw_url%>"))
114
+ p.add_substitution(Substitution.new(key: "%asm_global_unsubscribe_raw_url%", value: "<%asm_global_unsubscribe_raw_url%>"))
115
+ p.add_substitution(Substitution.new(key: "%asm_preferences_raw_url%", value: "<%asm_preferences_raw_url%>"))
91
116
  end
117
+
118
+ p
92
119
  end
93
120
 
94
121
  def to_attachment(part)
@@ -139,6 +166,23 @@ module SendGridActionMailer
139
166
  JSON.parse(text.empty? ? '{}' : text.gsub(/:*\"*([\%a-zA-Z0-9_-]*)\"*(( *)=>\ *)/) { "\"#{$1}\":" }, symbolize_names: symbolize)
140
167
  end
141
168
 
169
+ def add_personalizations(sendgrid_mail, mail)
170
+ if (mail.to && mail.to.any?) || (mail.cc && mail.cc.any?) || (mail.bcc && mail.bcc.any?)
171
+ personalization = setup_personalization(mail, {})
172
+ to_emails(mail.to).each { |to| personalization.add_to(to) }
173
+ to_emails(mail.cc).each { |cc| personalization.add_cc(cc) }
174
+ to_emails(mail.bcc).each { |bcc| personalization.add_bcc(bcc) }
175
+ sendgrid_mail.add_personalization(personalization)
176
+ end
177
+
178
+ if mail['personalizations']
179
+ personalizations = json_parse('[' + mail['personalizations'].value + ']', false)
180
+ personalizations.each do |p|
181
+ sendgrid_mail.add_personalization(setup_personalization(mail, p))
182
+ end
183
+ end
184
+ end
185
+
142
186
  def add_send_options(sendgrid_mail, mail)
143
187
  if mail['template_id']
144
188
  sendgrid_mail.template_id = mail['template_id'].to_s
@@ -1,3 +1,3 @@
1
1
  module SendGridActionMailer
2
- VERSION = '2.4.2'.freeze
2
+ VERSION = '2.5.0'.freeze
3
3
  end
@@ -3,6 +3,14 @@ require 'webmock/rspec'
3
3
 
4
4
  module SendGridActionMailer
5
5
  describe DeliveryMethod do
6
+ def stringify_keys(hash)
7
+ result = {}
8
+ hash.each_key do |key|
9
+ result[key.to_s] = hash[key]
10
+ end
11
+ result
12
+ end
13
+
6
14
  subject(:mailer) do
7
15
  DeliveryMethod.new(api_key: 'key')
8
16
  end
@@ -242,13 +250,37 @@ module SendGridActionMailer
242
250
  ])
243
251
  end
244
252
 
245
- context 'send options' do
246
- it 'sets a template_id' do
253
+ context 'template_id' do
254
+ before do
247
255
  mail['template_id'] = '1'
256
+ end
257
+
258
+ it 'sets a template_id' do
248
259
  mailer.deliver!(mail)
249
260
  expect(client.sent_mail['template_id']).to eq('1')
250
261
  end
251
262
 
263
+ it 'does not set unsubscribe substitutions' do
264
+ mailer.deliver!(mail)
265
+ expect(client.sent_mail['personalizations'].first).to_not have_key('substitutions')
266
+ end
267
+ end
268
+
269
+ context 'without dynamic template data or a template id' do
270
+ it 'sets unsubscribe substitutions' do
271
+ mailer.deliver!(mail)
272
+ expect(client.sent_mail['personalizations'].first).to have_key('substitutions')
273
+ substitutions = client.sent_mail['personalizations'].first['substitutions']
274
+ expect(substitutions).to eq({
275
+ '%asm_group_unsubscribe_raw_url%' => '<%asm_group_unsubscribe_raw_url%>',
276
+ '%asm_global_unsubscribe_raw_url%' => '<%asm_global_unsubscribe_raw_url%>',
277
+ '%asm_preferences_raw_url%' => '<%asm_preferences_raw_url%>'
278
+ })
279
+ end
280
+ end
281
+
282
+ context 'send options' do
283
+
252
284
  it 'sets sections' do
253
285
  mail['sections'] = {'%foo%' => 'bar'}
254
286
  mailer.deliver!(mail)
@@ -386,11 +418,20 @@ module SendGridActionMailer
386
418
  end
387
419
 
388
420
  context 'dynamic template data' do
421
+ let(:template_data) do
422
+ { variable_1: '1', variable_2: '2' }
423
+ end
424
+
425
+ before { mail['dynamic_template_data'] = template_data }
426
+
389
427
  it 'sets dynamic_template_data' do
390
- template_data = { variable_1: '1', variable_2: '2' }
391
- mail['dynamic_template_data'] = template_data
392
428
  mailer.deliver!(mail)
393
- expect(client.sent_mail['personalizations'].first['dynamic_template_data']).to eq(template_data)
429
+ expect(client.sent_mail['personalizations'].first['dynamic_template_data']).to eq({'variable_1' => '1', 'variable_2' => '2'})
430
+ end
431
+
432
+ it 'does not set unsubscribe substitutions' do
433
+ mailer.deliver!(mail)
434
+ expect(client.sent_mail['personalizations'].first).to_not have_key('substitutions')
394
435
  end
395
436
  end
396
437
 
@@ -509,6 +550,211 @@ module SendGridActionMailer
509
550
  expect(content['content_id'].class).to eq(String)
510
551
  end
511
552
  end
553
+
554
+ context 'with personalizations' do
555
+ let(:personalizations) do
556
+ [
557
+ {
558
+ 'to' => [
559
+ {'email' => 'john1@example.com', 'name' => 'John 1'},
560
+ {'email' => 'john2@example.com', 'name' => 'John 2'},
561
+ ]
562
+ },
563
+ {
564
+ 'to' => [
565
+ {'email' => 'john3@example.com', 'name' => 'John 3'},
566
+ {'email' => 'john4@example.com'}
567
+ ],
568
+ 'cc' => [
569
+ {'email' => 'cc@example.com'}
570
+ ],
571
+ 'bcc' => [
572
+ {'email' => 'bcc@example.com'}
573
+ ],
574
+ 'substitutions' => {
575
+ '%fname%' => 'Bob'
576
+ },
577
+ 'subject' => 'personalized subject',
578
+ 'send_at' => 1443636843,
579
+ 'custom_args' => {
580
+ 'user_id' => '343'
581
+ },
582
+ 'headers' => {
583
+ 'X-Test' => true
584
+ }
585
+ }
586
+ ]
587
+ end
588
+
589
+ before do
590
+ mail.to = nil
591
+ mail.cc = nil
592
+ mail.bcc = nil
593
+ mail['personalizations'] = personalizations
594
+ end
595
+
596
+ it 'sets the provided to address personalizations' do
597
+ mailer.deliver!(mail)
598
+ expect(client.sent_mail['personalizations'].length).to eq(2)
599
+ expect(client.sent_mail['personalizations'][0]['to']).to eq(personalizations[0]['to'])
600
+ expect(client.sent_mail['personalizations'][1]['to']).to eq(personalizations[1]['to'])
601
+ end
602
+
603
+ it 'sets the provided cc address personalizations' do
604
+ mailer.deliver!(mail)
605
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('cc')
606
+ expect(client.sent_mail['personalizations'][1]['cc']).to eq(personalizations[1]['cc'])
607
+ end
608
+
609
+ it 'sets the provided bcc address personalizations' do
610
+ mailer.deliver!(mail)
611
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('bcc')
612
+ expect(client.sent_mail['personalizations'][1]['bcc']).to eq(personalizations[1]['bcc'])
613
+ end
614
+
615
+ it 'sets the provided subject personalizations' do
616
+ mailer.deliver!(mail)
617
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('subject')
618
+ expect(client.sent_mail['personalizations'][1]['subject']).to eq(personalizations[1]['subject'])
619
+ end
620
+
621
+ it 'sets the provided headers personalizations' do
622
+ mailer.deliver!(mail)
623
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('headers')
624
+ expect(client.sent_mail['personalizations'][1]['headers']).to eq(personalizations[1]['headers'])
625
+ end
626
+
627
+ it 'sets the provided custom_arg personalizations' do
628
+ mailer.deliver!(mail)
629
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('custom_args')
630
+ expect(client.sent_mail['personalizations'][1]['custom_args']).to eq(personalizations[1]['custom_args'])
631
+ end
632
+
633
+ it 'sets the provided send_at personalizations' do
634
+ mailer.deliver!(mail)
635
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('send_at')
636
+ expect(client.sent_mail['personalizations'][1]['send_at']).to eq(personalizations[1]['send_at'])
637
+ end
638
+
639
+ it 'sets the provided substitution personalizations' do
640
+ mailer.deliver!(mail)
641
+ expect(client.sent_mail['personalizations'][1]['substitutions']).to include(personalizations[1]['substitutions'])
642
+ end
643
+
644
+ it 'adds to the unsubscribe link substitutions' do
645
+ mailer.deliver!(mail)
646
+ expect(client.sent_mail['personalizations'][0]['substitutions']).to eq({
647
+ '%asm_group_unsubscribe_raw_url%' => '<%asm_group_unsubscribe_raw_url%>',
648
+ '%asm_global_unsubscribe_raw_url%' => '<%asm_global_unsubscribe_raw_url%>',
649
+ '%asm_preferences_raw_url%' => '<%asm_preferences_raw_url%>'
650
+ })
651
+ expect(client.sent_mail['personalizations'][1]['substitutions']).to include({
652
+ '%asm_group_unsubscribe_raw_url%' => '<%asm_group_unsubscribe_raw_url%>',
653
+ '%asm_global_unsubscribe_raw_url%' => '<%asm_global_unsubscribe_raw_url%>',
654
+ '%asm_preferences_raw_url%' => '<%asm_preferences_raw_url%>'
655
+ })
656
+ end
657
+
658
+ context 'with symbols used as keys' do
659
+ let(:personalizations) do
660
+ [
661
+ {
662
+ to: [
663
+ { email: 'john1@example.com', name: 'John 1'}
664
+ ]
665
+ }
666
+ ]
667
+ end
668
+
669
+ it 'still works' do
670
+ mailer.deliver!(mail)
671
+ expect(client.sent_mail['personalizations'].length).to eq(1)
672
+ expected_to = personalizations[0][:to].map { |t| stringify_keys(t) }
673
+ expect(client.sent_mail['personalizations'][0]['to']).to eq(expected_to)
674
+ end
675
+ end
676
+
677
+ context 'dynamic template data passed into a personalizaiton' do
678
+ let(:personalization_data) do
679
+ {
680
+ 'variable_1' => '1', 'variable_2' => '2'
681
+ }
682
+ end
683
+
684
+ let(:personalizations_with_dynamic_data) do
685
+ personalizations.tap do |p|
686
+ p[1]['dynamic_template_data'] = personalization_data
687
+ end
688
+ end
689
+
690
+ before do
691
+ mail['personalizations'] = nil
692
+ mail['personalizations'] = personalizations_with_dynamic_data
693
+ end
694
+
695
+ it 'sets the provided dynamic template data personalizations' do
696
+ mailer.deliver!(mail)
697
+ expect(client.sent_mail['personalizations'][0]).to_not have_key('dynamic_template_data')
698
+ expect(client.sent_mail['personalizations'][1]['dynamic_template_data']).to eq(personalization_data)
699
+ end
700
+
701
+ context 'dynamic template data is also set on the mail object' do
702
+ let(:mail_template_data) do
703
+ { 'variable_3' => '1', 'variable_4' => '2' }
704
+ end
705
+
706
+ before { mail['dynamic_template_data'] = mail_template_data }
707
+
708
+ it 'sets dynamic_template_data where not also provided as a personalization' do
709
+ mailer.deliver!(mail)
710
+ expect(client.sent_mail['personalizations'][0]['dynamic_template_data']).to eq(mail_template_data)
711
+ end
712
+
713
+ it 'merges the template data with a personalizations dynamic data' do
714
+ mailer.deliver!(mail)
715
+ expect(client.sent_mail['personalizations'][1]['dynamic_template_data']).to eq(
716
+ mail_template_data.merge(personalization_data)
717
+ )
718
+ end
719
+ end
720
+ end
721
+
722
+ context 'when to is set on mail object' do
723
+ before { mail.to = 'test@sendgrid.com' }
724
+
725
+ it 'adds that to address as a separate personalization' do
726
+ mailer.deliver!(mail)
727
+ expect(client.sent_mail['personalizations'].length).to eq(3)
728
+ expect(client.sent_mail['personalizations'][0]['to']).to eq([{"email"=>"test@sendgrid.com"}])
729
+ expect(client.sent_mail['personalizations'][1]['to']).to eq(personalizations[0]['to'])
730
+ expect(client.sent_mail['personalizations'][2]['to']).to eq(personalizations[1]['to'])
731
+ end
732
+ end
733
+
734
+ context 'when cc is set on mail object' do
735
+ before { mail.cc = 'test@sendgrid.com' }
736
+
737
+ it 'adds that cc address as a separate personalization' do
738
+ mailer.deliver!(mail)
739
+ expect(client.sent_mail['personalizations'].length).to eq(3)
740
+ expect(client.sent_mail['personalizations'][0]['cc']).to eq([{"email"=>"test@sendgrid.com"}])
741
+ expect(client.sent_mail['personalizations'][1]['cc']).to eq(personalizations[0]['cc'])
742
+ expect(client.sent_mail['personalizations'][2]['cc']).to eq(personalizations[1]['cc'])
743
+ end
744
+ end
745
+
746
+ context 'when bcc is set on mail object' do
747
+ before { mail.bcc = 'test@sendgrid.com' }
748
+
749
+ it 'adds that bcc address as a separate personalization' do
750
+ mailer.deliver!(mail)
751
+ expect(client.sent_mail['personalizations'].length).to eq(3)
752
+ expect(client.sent_mail['personalizations'][0]['bcc']).to eq([{"email"=>"test@sendgrid.com"}])
753
+ expect(client.sent_mail['personalizations'][1]['bcc']).to eq(personalizations[0]['bcc'])
754
+ expect(client.sent_mail['personalizations'][2]['bcc']).to eq(personalizations[1]['bcc'])
755
+ end
756
+ end
757
+ end
512
758
  end
513
759
  end
514
760
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sendgrid-actionmailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.2
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eddie Zaneski