sendgrid-actionmailer 2.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +4 -6
- data/Appraisals +0 -8
- data/CHANGELOG.md +68 -0
- data/README.md +33 -1
- data/gemfiles/mail_2.7.gemfile +1 -1
- data/lib/sendgrid_actionmailer.rb +104 -38
- data/lib/sendgrid_actionmailer/version.rb +1 -1
- data/sendgrid-actionmailer.gemspec +2 -2
- data/spec/lib/sendgrid_actionmailer_spec.rb +299 -51
- metadata +7 -10
- data/gemfiles/mail_2.5.gemfile +0 -7
- data/gemfiles/mail_2.6.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8d75cda77ec587c85751c71dd79de21562a35e38562ae691dbd164ec86eae8bf
|
4
|
+
data.tar.gz: 8ba014c01b1e37162bb96a7c6b2c00a59c8a6ad9ad7eef126cacd1046dd03d60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c425f306373fd3a70490aacf0e55e312827bdf94b24f33d602bd3dd0335c66682f0352ed9ffe964e50c6dd4a6a99a4ec8cbcca24f1b2e7dfa6e195e63fd00be
|
7
|
+
data.tar.gz: 91bf36ef8d4e4a1fd8de5e019f94f9486ae3ea106240256c7c8a08a84c3ebceceab49c348b26936ddc6162e32eb82739646a80b8df6df393855071acb353488e
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.5
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
- 2.3.
|
4
|
+
- 2.6.5
|
5
|
+
- 2.5.7
|
6
|
+
- 2.4.9
|
7
|
+
- 2.3.8
|
8
8
|
before_install:
|
9
9
|
- gem update --system
|
10
10
|
- gem install bundler
|
11
11
|
gemfile:
|
12
|
-
- gemfiles/mail_2.5.gemfile
|
13
|
-
- gemfiles/mail_2.6.gemfile
|
14
12
|
- gemfiles/mail_2.7.gemfile
|
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,73 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 3.0.0 - 2020-3-2
|
4
|
+
|
5
|
+
### Removed
|
6
|
+
|
7
|
+
- Compatibility with mail gems before version 2.7
|
8
|
+
|
9
|
+
## 2.6.0 - 2020-1-23
|
10
|
+
|
11
|
+
### Chages
|
12
|
+
|
13
|
+
- Dont send content types with dynamic templates (#69)
|
14
|
+
|
15
|
+
## 2.5.0 - 2020-1-21
|
16
|
+
|
17
|
+
### Chages
|
18
|
+
|
19
|
+
- Add personalizations field (#60)
|
20
|
+
|
21
|
+
### Fixes
|
22
|
+
|
23
|
+
- Revert "Lazy load ActionMailer::Base" (#64)
|
24
|
+
- Yank 2.4.1
|
25
|
+
|
26
|
+
## 2.4.2 - 2020-1-21
|
27
|
+
|
28
|
+
### Fixes
|
29
|
+
|
30
|
+
- Revert "Lazy load ActionMailer::Base" (#64)
|
31
|
+
- Yank 2.4.1
|
32
|
+
|
33
|
+
## 2.4.1 - 2020-1-20
|
34
|
+
|
35
|
+
### Changed
|
36
|
+
|
37
|
+
- Update Travis CI settings to test on latest Ruby and mail gem version (#55)
|
38
|
+
- Lazy load ActionMailer::Base (#57)
|
39
|
+
|
40
|
+
## 2.4.0 - 2019-07-9
|
41
|
+
|
42
|
+
### Changed
|
43
|
+
|
44
|
+
- Compatibility with `sendgrid-ruby` v6.0.
|
45
|
+
|
46
|
+
## 2.3.0 - 2019-4-10
|
47
|
+
|
48
|
+
### Fixes
|
49
|
+
|
50
|
+
- No asm substitutions if template_id present
|
51
|
+
|
52
|
+
## 2.2.1 - 2019-1-4
|
53
|
+
|
54
|
+
### Fixes
|
55
|
+
|
56
|
+
- Fix Travis
|
57
|
+
|
58
|
+
## 2.2.0 - 2018-11-23
|
59
|
+
|
60
|
+
### Fixes
|
61
|
+
|
62
|
+
- Update Readme
|
63
|
+
|
64
|
+
## 2.1.0 - 2018-11-20
|
65
|
+
|
66
|
+
### Fixes
|
67
|
+
|
68
|
+
- Substiutions and dynamic_template_data should be compatible.
|
69
|
+
|
70
|
+
|
3
71
|
## 2.0.0 - 2018-08-15
|
4
72
|
|
5
73
|
### Changed
|
data/README.md
CHANGED
@@ -217,10 +217,42 @@ The name of the campaign.
|
|
217
217
|
|
218
218
|
### dynamic_template_data (json)
|
219
219
|
|
220
|
-
Data to provide for feeding the new dynamic templates in Sendgrid with valueable data. This also disables the following Unsubscribe links because of deprecation of substitutions in the new template implementaiton.
|
220
|
+
Data to provide for feeding the new dynamic templates in Sendgrid with valueable data. This also disables the following Unsubscribe links because of deprecation of substitutions in the new template implementaiton. Variables are available within templates using [{{handlebar syntax}}](https://sendgrid.com/docs/for-developers/sending-email/using-handlebars).
|
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.
|
data/gemfiles/mail_2.7.gemfile
CHANGED
@@ -4,6 +4,7 @@ require 'sendgrid-ruby'
|
|
4
4
|
|
5
5
|
module SendGridActionMailer
|
6
6
|
class DeliveryMethod
|
7
|
+
|
7
8
|
# TODO: use custom class to customer excpetion payload
|
8
9
|
SendgridDeliveryError = Class.new(StandardError)
|
9
10
|
|
@@ -24,17 +25,15 @@ module SendGridActionMailer
|
|
24
25
|
m.from = to_email(mail.from)
|
25
26
|
m.reply_to = to_email(mail.reply_to)
|
26
27
|
m.subject = mail.subject || ""
|
27
|
-
# https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html
|
28
|
-
m.add_personalization(to_personalizations(mail))
|
29
28
|
end
|
30
29
|
|
30
|
+
add_personalizations(sendgrid_mail, mail)
|
31
31
|
add_api_key(sendgrid_mail, mail)
|
32
32
|
add_content(sendgrid_mail, mail)
|
33
33
|
add_send_options(sendgrid_mail, mail)
|
34
34
|
add_mail_settings(sendgrid_mail, mail)
|
35
35
|
add_tracking_settings(sendgrid_mail, mail)
|
36
36
|
|
37
|
-
|
38
37
|
response = perform_send_request(sendgrid_mail)
|
39
38
|
|
40
39
|
settings[:return_response] ? response : self
|
@@ -75,20 +74,51 @@ module SendGridActionMailer
|
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
|
-
def
|
79
|
-
Personalization.new
|
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) }
|
77
|
+
def setup_personalization(mail, personalization_hash)
|
78
|
+
personalization = Personalization.new
|
83
79
|
|
80
|
+
personalization_hash = self.class.transform_keys(personalization_hash, &:to_s)
|
81
|
+
|
82
|
+
(personalization_hash['to'] || []).each do |to|
|
83
|
+
personalization.add_to Email.new(email: to['email'], name: to['name'])
|
84
|
+
end
|
85
|
+
(personalization_hash['cc'] || []).each do |cc|
|
86
|
+
personalization.add_cc Email.new(email: cc['email'], name: cc['name'])
|
87
|
+
end
|
88
|
+
(personalization_hash['bcc'] || []).each do |bcc|
|
89
|
+
personalization.add_bcc Email.new(email: bcc['email'], name: bcc['name'])
|
90
|
+
end
|
91
|
+
(personalization_hash['headers'] || []).each do |header_key, header_value|
|
92
|
+
personalization.add_header Header.new(key: header_key, value: header_value)
|
93
|
+
end
|
94
|
+
(personalization_hash['substitutions'] || {}).each do |sub_key, sub_value|
|
95
|
+
personalization.add_substitution(Substitution.new(key: sub_key, value: sub_value))
|
96
|
+
end
|
97
|
+
(personalization_hash['custom_args'] || {}).each do |arg_key, arg_value|
|
98
|
+
personalization.add_custom_arg(CustomArg.new(key: arg_key, value: arg_value))
|
99
|
+
end
|
100
|
+
if personalization_hash['send_at']
|
101
|
+
personalization.send_at = personalization_hash['send_at']
|
102
|
+
end
|
103
|
+
if personalization_hash['subject']
|
104
|
+
personalization.subject = personalization_hash['subject']
|
105
|
+
end
|
106
|
+
|
107
|
+
if mail['dynamic_template_data'] || personalization_hash['dynamic_template_data']
|
84
108
|
if mail['dynamic_template_data']
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
p.add_substitution(Substitution.new(key: "%asm_preferences_raw_url%", value: "<%asm_preferences_raw_url%>"))
|
109
|
+
data = mail['dynamic_template_data'].unparsed_value
|
110
|
+
data.merge!(personalization_hash['dynamic_template_data'] || {})
|
111
|
+
else
|
112
|
+
data = personalization_hash['dynamic_template_data']
|
90
113
|
end
|
114
|
+
personalization.add_dynamic_template_data(data)
|
115
|
+
elsif mail['template_id'].nil?
|
116
|
+
personalization.add_substitution(Substitution.new(key: "%asm_group_unsubscribe_raw_url%", value: "<%asm_group_unsubscribe_raw_url%>"))
|
117
|
+
personalization.add_substitution(Substitution.new(key: "%asm_global_unsubscribe_raw_url%", value: "<%asm_global_unsubscribe_raw_url%>"))
|
118
|
+
personalization.add_substitution(Substitution.new(key: "%asm_preferences_raw_url%", value: "<%asm_preferences_raw_url%>"))
|
91
119
|
end
|
120
|
+
|
121
|
+
return personalization
|
92
122
|
end
|
93
123
|
|
94
124
|
def to_attachment(part)
|
@@ -115,28 +145,49 @@ module SendGridActionMailer
|
|
115
145
|
def add_api_key(sendgrid_mail, mail)
|
116
146
|
self.api_key = settings.fetch(:api_key)
|
117
147
|
if mail['delivery-method-options'] && mail['delivery-method-options'].value.include?('api_key')
|
118
|
-
self.api_key =
|
148
|
+
self.api_key = mail['delivery-method-options'].unparsed_value['api_key']
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_attachments(sendgrid_mail, mail)
|
153
|
+
mail.attachments.each do |part|
|
154
|
+
sendgrid_mail.add_attachment(to_attachment(part))
|
119
155
|
end
|
120
156
|
end
|
121
157
|
|
122
158
|
def add_content(sendgrid_mail, mail)
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
159
|
+
if mail['template_id']
|
160
|
+
# We are sending a template, so we don't need to add any content outside
|
161
|
+
# of attachments
|
162
|
+
add_attachments(sendgrid_mail, mail)
|
163
|
+
else
|
164
|
+
case mail.mime_type
|
165
|
+
when 'text/plain'
|
166
|
+
sendgrid_mail.add_content(to_content(:plain, mail.body.decoded))
|
167
|
+
when 'text/html'
|
168
|
+
sendgrid_mail.add_content(to_content(:html, mail.body.decoded))
|
169
|
+
when 'multipart/alternative', 'multipart/mixed', 'multipart/related'
|
170
|
+
sendgrid_mail.add_content(to_content(:plain, mail.text_part.decoded)) if mail.text_part
|
171
|
+
sendgrid_mail.add_content(to_content(:html, mail.html_part.decoded)) if mail.html_part
|
172
|
+
|
173
|
+
add_attachments(sendgrid_mail, mail)
|
134
174
|
end
|
135
175
|
end
|
136
176
|
end
|
137
177
|
|
138
|
-
def
|
139
|
-
|
178
|
+
def add_personalizations(sendgrid_mail, mail)
|
179
|
+
if mail['personalizations']
|
180
|
+
mail['personalizations'].unparsed_value.each do |p|
|
181
|
+
sendgrid_mail.add_personalization(setup_personalization(mail, p))
|
182
|
+
end
|
183
|
+
end
|
184
|
+
if (mail.to && mail.to.any?) || (mail.cc && mail.cc.any?) || (mail.bcc && mail.bcc.any?)
|
185
|
+
personalization = setup_personalization(mail, {})
|
186
|
+
to_emails(mail.to).each { |to| personalization.add_to(to) }
|
187
|
+
to_emails(mail.cc).each { |cc| personalization.add_cc(cc) }
|
188
|
+
to_emails(mail.bcc).each { |bcc| personalization.add_bcc(bcc) }
|
189
|
+
sendgrid_mail.add_personalization(personalization)
|
190
|
+
end
|
140
191
|
end
|
141
192
|
|
142
193
|
def add_send_options(sendgrid_mail, mail)
|
@@ -144,12 +195,12 @@ module SendGridActionMailer
|
|
144
195
|
sendgrid_mail.template_id = mail['template_id'].to_s
|
145
196
|
end
|
146
197
|
if mail['sections']
|
147
|
-
|
198
|
+
mail['sections'].unparsed_value.each do |key, value|
|
148
199
|
sendgrid_mail.add_section(Section.new(key: key, value: value))
|
149
200
|
end
|
150
201
|
end
|
151
202
|
if mail['headers']
|
152
|
-
|
203
|
+
mail['headers'].unparsed_value.each do |key, value|
|
153
204
|
sendgrid_mail.add_header(Header.new(key: key, value: value))
|
154
205
|
end
|
155
206
|
end
|
@@ -159,18 +210,21 @@ module SendGridActionMailer
|
|
159
210
|
end
|
160
211
|
end
|
161
212
|
if mail['custom_args']
|
162
|
-
|
213
|
+
mail['custom_args'].unparsed_value.each do |key, value|
|
163
214
|
sendgrid_mail.add_custom_arg(CustomArg.new(key: key, value: value))
|
164
215
|
end
|
165
216
|
end
|
166
|
-
if mail['send_at']
|
217
|
+
if mail['send_at']
|
167
218
|
sendgrid_mail.send_at = mail['send_at'].value.to_i
|
168
|
-
|
219
|
+
end
|
220
|
+
if mail['batch_id']
|
221
|
+
sendgrid_mail.batch_id = mail['batch_id'].to_s
|
169
222
|
end
|
170
223
|
if mail['asm']
|
171
|
-
asm =
|
172
|
-
asm = asm.delete_if { |key, value|
|
173
|
-
|
224
|
+
asm = mail['asm'].unparsed_value
|
225
|
+
asm = asm.delete_if { |key, value|
|
226
|
+
!key.to_s.match(/(group_id)|(groups_to_display)/) }
|
227
|
+
if asm.keys.map(&:to_s).include?('group_id')
|
174
228
|
sendgrid_mail.asm = ASM.new(asm)
|
175
229
|
end
|
176
230
|
end
|
@@ -181,7 +235,7 @@ module SendGridActionMailer
|
|
181
235
|
|
182
236
|
def add_mail_settings(sendgrid_mail, mail)
|
183
237
|
if mail['mail_settings']
|
184
|
-
settings =
|
238
|
+
settings = mail['mail_settings'].unparsed_value || {}
|
185
239
|
sendgrid_mail.mail_settings = MailSettings.new.tap do |m|
|
186
240
|
if settings[:bcc]
|
187
241
|
m.bcc = BccSettings.new(settings[:bcc])
|
@@ -204,7 +258,7 @@ module SendGridActionMailer
|
|
204
258
|
|
205
259
|
def add_tracking_settings(sendgrid_mail, mail)
|
206
260
|
if mail['tracking_settings']
|
207
|
-
settings =
|
261
|
+
settings = mail['tracking_settings'].unparsed_value
|
208
262
|
sendgrid_mail.tracking_settings = TrackingSettings.new.tap do |t|
|
209
263
|
if settings[:click_tracking]
|
210
264
|
t.click_tracking = ClickTracking.new(settings[:click_tracking])
|
@@ -226,7 +280,7 @@ module SendGridActionMailer
|
|
226
280
|
result = client.mail._('send').post(request_body: email.to_json) # ლ(ಠ益ಠლ) that API
|
227
281
|
|
228
282
|
if result.status_code && result.status_code.start_with?('4')
|
229
|
-
message = JSON.parse(result.body).fetch('errors').pop.fetch('message')
|
283
|
+
message = !!(result.body) ? JSON.parse(result.body).fetch('errors').pop.fetch('message') : 'Sendgrid API Error'
|
230
284
|
full_message = "Sendgrid delivery failed with #{result.status_code} #{message}"
|
231
285
|
|
232
286
|
settings[:raise_delivery_errors] ? raise(SendgridDeliveryError, full_message) : warn(full_message)
|
@@ -234,5 +288,17 @@ module SendGridActionMailer
|
|
234
288
|
|
235
289
|
result
|
236
290
|
end
|
291
|
+
|
292
|
+
# Recursive key transformation based on Rails deep_transform_values
|
293
|
+
def self.transform_keys(object, &block)
|
294
|
+
case object
|
295
|
+
when Hash
|
296
|
+
object.map { |key, value| [yield(key), transform_keys(value, &block)] }.to_h
|
297
|
+
when Array
|
298
|
+
object.map { |e| transform_keys(e, &block) }
|
299
|
+
else
|
300
|
+
object
|
301
|
+
end
|
302
|
+
end
|
237
303
|
end
|
238
304
|
end
|
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
-
spec.add_dependency 'mail', '~> 2.
|
23
|
-
spec.add_dependency 'sendgrid-ruby', '~>
|
22
|
+
spec.add_dependency 'mail', '~> 2.7'
|
23
|
+
spec.add_dependency 'sendgrid-ruby', '~> 6.0'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'appraisal', '~> 2.1.0'
|
26
26
|
spec.add_development_dependency 'bundler'
|
@@ -3,6 +3,10 @@ require 'webmock/rspec'
|
|
3
3
|
|
4
4
|
module SendGridActionMailer
|
5
5
|
describe DeliveryMethod do
|
6
|
+
def transform_keys(object, &block)
|
7
|
+
SendGridActionMailer::DeliveryMethod.transform_keys(object, &block)
|
8
|
+
end
|
9
|
+
|
6
10
|
subject(:mailer) do
|
7
11
|
DeliveryMethod.new(api_key: 'key')
|
8
12
|
end
|
@@ -242,13 +246,51 @@ module SendGridActionMailer
|
|
242
246
|
])
|
243
247
|
end
|
244
248
|
|
245
|
-
context '
|
246
|
-
|
249
|
+
context 'template_id' do
|
250
|
+
before do
|
247
251
|
mail['template_id'] = '1'
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'sets a template_id' do
|
248
255
|
mailer.deliver!(mail)
|
249
256
|
expect(client.sent_mail['template_id']).to eq('1')
|
250
257
|
end
|
251
258
|
|
259
|
+
it 'does not set unsubscribe substitutions' do
|
260
|
+
mailer.deliver!(mail)
|
261
|
+
expect(client.sent_mail['personalizations'].first).to_not have_key('substitutions')
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'does not set send a content type' do
|
265
|
+
mailer.deliver!(mail)
|
266
|
+
expect(client.sent_mail['content']).to eq(nil)
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'does not set send a content type even if body is given' do
|
270
|
+
# This matches the default behavior of ActionMail. body must be
|
271
|
+
# specified and content_type defaults to text/plain.
|
272
|
+
mail.body = 'I heard you like pineapple.'
|
273
|
+
mail.content_type = 'text/plain'
|
274
|
+
mailer.deliver!(mail)
|
275
|
+
expect(client.sent_mail['content']).to eq(nil)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context 'without dynamic template data or a template id' do
|
280
|
+
it 'sets unsubscribe substitutions' do
|
281
|
+
mailer.deliver!(mail)
|
282
|
+
expect(client.sent_mail['personalizations'].first).to have_key('substitutions')
|
283
|
+
substitutions = client.sent_mail['personalizations'].first['substitutions']
|
284
|
+
expect(substitutions).to eq({
|
285
|
+
'%asm_group_unsubscribe_raw_url%' => '<%asm_group_unsubscribe_raw_url%>',
|
286
|
+
'%asm_global_unsubscribe_raw_url%' => '<%asm_global_unsubscribe_raw_url%>',
|
287
|
+
'%asm_preferences_raw_url%' => '<%asm_preferences_raw_url%>'
|
288
|
+
})
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context 'send options' do
|
293
|
+
|
252
294
|
it 'sets sections' do
|
253
295
|
mail['sections'] = {'%foo%' => 'bar'}
|
254
296
|
mailer.deliver!(mail)
|
@@ -283,10 +325,10 @@ module SendGridActionMailer
|
|
283
325
|
end
|
284
326
|
|
285
327
|
it 'sets asm' do
|
286
|
-
asm = {
|
328
|
+
asm = {group_id: 99, groups_to_display: [4,5,6,7,8]}
|
287
329
|
mail['asm'] = asm
|
288
330
|
mailer.deliver!(mail)
|
289
|
-
expect(client.sent_mail['asm']).to eq(asm)
|
331
|
+
expect(client.sent_mail['asm']).to eq(transform_keys(asm, &:to_s))
|
290
332
|
end
|
291
333
|
|
292
334
|
it 'sets ip_pool_name' do
|
@@ -295,109 +337,109 @@ module SendGridActionMailer
|
|
295
337
|
expect(client.sent_mail['ip_pool_name']).to eq('marketing')
|
296
338
|
end
|
297
339
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
expect(client.sent_mail['asm']).to eq({"group_id" => 99, "groups_to_display" => [4,5,6,7,8]})
|
304
|
-
end
|
305
|
-
|
306
|
-
it "should parse 1.9 hash" do
|
307
|
-
asm = { group_id: 99, groups_to_display: [4,5,6,7,8]}
|
308
|
-
mail['asm'] = asm
|
309
|
-
mailer.deliver!(mail)
|
310
|
-
expect(client.sent_mail['asm']).to eq({"group_id" => 99, "groups_to_display" => [4,5,6,7,8]})
|
311
|
-
end
|
312
|
-
|
313
|
-
it "should parse json" do
|
314
|
-
asm = {'group_id' => 99, 'groups_to_display' => [4,5,6,7,8]}
|
315
|
-
mail['asm'] = asm.to_json
|
316
|
-
mailer.deliver!(mail)
|
317
|
-
expect(client.sent_mail['asm']).to eq({"group_id" => 99, "groups_to_display" => [4,5,6,7,8]})
|
318
|
-
end
|
340
|
+
it 'should not change values inside custom args' do
|
341
|
+
custom_args = { 'text' => 'line with a => in it' }
|
342
|
+
mail['custom_args'] = custom_args
|
343
|
+
mailer.deliver!(mail)
|
344
|
+
expect(client.sent_mail['custom_args']).to eq('text' => 'line with a => in it')
|
319
345
|
end
|
320
346
|
|
321
347
|
context 'mail_settings' do
|
322
348
|
it 'sets bcc' do
|
323
|
-
bcc = {
|
349
|
+
bcc = { bcc: { enable: true, email: 'test@example.com' }}
|
324
350
|
mail['mail_settings'] = bcc
|
325
351
|
mailer.deliver!(mail)
|
326
|
-
expect(client.sent_mail['mail_settings']).to eq(bcc)
|
352
|
+
expect(client.sent_mail['mail_settings']).to eq(transform_keys(bcc, &:to_s))
|
327
353
|
end
|
328
354
|
|
329
355
|
it 'sets bypass_list_management' do
|
330
|
-
bypass = {
|
356
|
+
bypass = { bypass_list_management: { enable: true }}
|
331
357
|
mail['mail_settings'] = bypass
|
332
358
|
mailer.deliver!(mail)
|
333
|
-
expect(client.sent_mail['mail_settings']).to eq(bypass)
|
359
|
+
expect(client.sent_mail['mail_settings']).to eq(transform_keys(bypass, &:to_s))
|
334
360
|
end
|
335
361
|
|
336
362
|
it 'sets footer' do
|
337
|
-
footer = {
|
363
|
+
footer = {footer: { enable: true, text: 'Footer Text', html: '<html><body>Footer Text</body></html>'}}
|
338
364
|
mail['mail_settings'] = footer
|
339
365
|
mailer.deliver!(mail)
|
340
|
-
expect(client.sent_mail['mail_settings']).to eq(footer)
|
366
|
+
expect(client.sent_mail['mail_settings']).to eq(transform_keys(footer, &:to_s))
|
341
367
|
end
|
342
368
|
|
343
369
|
it 'sets sandbox_mode' do
|
344
|
-
sandbox = {
|
370
|
+
sandbox = {sandbox_mode: { enable: true }}
|
345
371
|
mail['mail_settings'] = sandbox
|
346
372
|
mailer.deliver!(mail)
|
347
|
-
expect(client.sent_mail['mail_settings']).to eq(sandbox)
|
373
|
+
expect(client.sent_mail['mail_settings']).to eq(transform_keys(sandbox, &:to_s))
|
348
374
|
end
|
349
375
|
|
350
376
|
it 'sets spam_check' do
|
351
|
-
spam_check = {
|
377
|
+
spam_check = {spam_check: { enable: true, threshold: 1, post_to_url: 'https://spamcatcher.sendgrid.com'}}
|
352
378
|
mail['mail_settings'] = spam_check
|
353
379
|
mailer.deliver!(mail)
|
354
|
-
expect(client.sent_mail['mail_settings']).to eq(spam_check)
|
380
|
+
expect(client.sent_mail['mail_settings']).to eq(transform_keys(spam_check, &:to_s))
|
355
381
|
end
|
356
382
|
end
|
357
383
|
|
358
384
|
context 'tracking_settings' do
|
359
385
|
it 'sets click_tracking' do
|
360
|
-
tracking = {
|
361
|
-
mail['tracking_settings'] = tracking
|
386
|
+
tracking = { click_tracking: { enable: false, enable_text: false }}
|
387
|
+
mail['tracking_settings'] = tracking.dup
|
362
388
|
mailer.deliver!(mail)
|
363
|
-
expect(client.sent_mail['tracking_settings']).to eq(tracking)
|
389
|
+
expect(client.sent_mail['tracking_settings']).to eq(transform_keys(tracking, &:to_s))
|
364
390
|
end
|
365
391
|
|
366
392
|
it 'sets open_tracking' do
|
367
|
-
tracking = {
|
393
|
+
tracking = { open_tracking: { enable: true, substitution_tag: 'Optional tag to replace with the open image in the body of the message' }}
|
368
394
|
mail['tracking_settings'] = tracking
|
369
395
|
mailer.deliver!(mail)
|
370
|
-
expect(client.sent_mail['tracking_settings']).to eq(tracking)
|
396
|
+
expect(client.sent_mail['tracking_settings']).to eq(transform_keys(tracking, &:to_s))
|
371
397
|
end
|
372
398
|
|
373
399
|
it 'sets subscription_tracking' do
|
374
|
-
tracking = {
|
400
|
+
tracking = { subscription_tracking: { enable: true, text: 'text to insert into the text/plain portion of the message', html: 'html to insert into the text/html portion of the message', substitution_tag: 'Optional tag to replace with the open image in the body of the def message' }}
|
375
401
|
mail['tracking_settings'] = tracking
|
376
402
|
mailer.deliver!(mail)
|
377
|
-
expect(client.sent_mail['tracking_settings']).to eq(tracking)
|
403
|
+
expect(client.sent_mail['tracking_settings']).to eq(transform_keys(tracking, &:to_s))
|
378
404
|
end
|
379
405
|
|
380
406
|
it 'sets ganalytics' do
|
381
|
-
tracking = {
|
407
|
+
tracking = { ganalytics: { enable: true, utm_source: 'some source', utm_medium: 'some medium', utm_term: 'some term', utm_content: 'some content', utm_campaign: 'some campaign' }}
|
382
408
|
mail['tracking_settings'] = tracking
|
383
409
|
mailer.deliver!(mail)
|
384
|
-
expect(client.sent_mail['tracking_settings']).to eq(tracking)
|
410
|
+
expect(client.sent_mail['tracking_settings']).to eq(transform_keys(tracking, &:to_s))
|
385
411
|
end
|
386
412
|
end
|
387
413
|
|
388
414
|
context 'dynamic template data' do
|
415
|
+
let(:template_data) do
|
416
|
+
{ variable_1: '1', variable_2: '2' }
|
417
|
+
end
|
418
|
+
|
419
|
+
before { mail['dynamic_template_data'] = template_data }
|
420
|
+
|
389
421
|
it 'sets dynamic_template_data' do
|
390
|
-
template_data = { variable_1: '1', variable_2: '2' }
|
391
|
-
mail['dynamic_template_data'] = template_data
|
392
422
|
mailer.deliver!(mail)
|
393
423
|
expect(client.sent_mail['personalizations'].first['dynamic_template_data']).to eq(template_data)
|
394
424
|
end
|
395
|
-
end
|
396
425
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
426
|
+
it 'does not set unsubscribe substitutions' do
|
427
|
+
mailer.deliver!(mail)
|
428
|
+
expect(client.sent_mail['personalizations'].first).to_not have_key('substitutions')
|
429
|
+
end
|
430
|
+
|
431
|
+
context 'containing what looks like hash syntax' do
|
432
|
+
let(:template_data) do
|
433
|
+
{ hint: 'Just use => instead of :' }
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'does not change values inside dynamic template data' do
|
437
|
+
mailer.deliver!(mail)
|
438
|
+
expect(
|
439
|
+
client.sent_mail['personalizations'].first['dynamic_template_data']
|
440
|
+
).to eq(template_data)
|
441
|
+
end
|
442
|
+
end
|
401
443
|
end
|
402
444
|
|
403
445
|
it 'sets dynamic template data and sandbox_mode' do
|
@@ -509,6 +551,212 @@ module SendGridActionMailer
|
|
509
551
|
expect(content['content_id'].class).to eq(String)
|
510
552
|
end
|
511
553
|
end
|
554
|
+
|
555
|
+
context 'with personalizations' do
|
556
|
+
let(:personalizations) do
|
557
|
+
[
|
558
|
+
{
|
559
|
+
'to' => [
|
560
|
+
{'email' => 'john1@example.com', 'name' => 'John 1'},
|
561
|
+
{'email' => 'john2@example.com', 'name' => 'John 2'},
|
562
|
+
]
|
563
|
+
},
|
564
|
+
{
|
565
|
+
'to' => [
|
566
|
+
{'email' => 'john3@example.com', 'name' => 'John 3'},
|
567
|
+
{'email' => 'john4@example.com'}
|
568
|
+
],
|
569
|
+
'cc' => [
|
570
|
+
{'email' => 'cc@example.com'}
|
571
|
+
],
|
572
|
+
'bcc' => [
|
573
|
+
{'email' => 'bcc@example.com'}
|
574
|
+
],
|
575
|
+
'substitutions' => {
|
576
|
+
'%fname%' => 'Bob'
|
577
|
+
},
|
578
|
+
'subject' => 'personalized subject',
|
579
|
+
'send_at' => 1443636843,
|
580
|
+
'custom_args' => {
|
581
|
+
'user_id' => '343'
|
582
|
+
},
|
583
|
+
'headers' => {
|
584
|
+
'X-Test' => true
|
585
|
+
}
|
586
|
+
}
|
587
|
+
]
|
588
|
+
end
|
589
|
+
|
590
|
+
before do
|
591
|
+
mail.to = nil
|
592
|
+
mail.cc = nil
|
593
|
+
mail.bcc = nil
|
594
|
+
mail['personalizations'] = personalizations
|
595
|
+
end
|
596
|
+
|
597
|
+
it 'sets the provided to address personalizations' do
|
598
|
+
mailer.deliver!(mail)
|
599
|
+
expect(client.sent_mail['personalizations'].length).to eq(2)
|
600
|
+
expect(client.sent_mail['personalizations'][0]['to']).to eq(personalizations[0]['to'])
|
601
|
+
expect(client.sent_mail['personalizations'][1]['to']).to eq(personalizations[1]['to'])
|
602
|
+
end
|
603
|
+
|
604
|
+
it 'sets the provided cc address personalizations' do
|
605
|
+
mailer.deliver!(mail)
|
606
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('cc')
|
607
|
+
expect(client.sent_mail['personalizations'][1]['cc']).to eq(personalizations[1]['cc'])
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'sets the provided bcc address personalizations' do
|
611
|
+
mailer.deliver!(mail)
|
612
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('bcc')
|
613
|
+
expect(client.sent_mail['personalizations'][1]['bcc']).to eq(personalizations[1]['bcc'])
|
614
|
+
end
|
615
|
+
|
616
|
+
it 'sets the provided subject personalizations' do
|
617
|
+
mailer.deliver!(mail)
|
618
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('subject')
|
619
|
+
expect(client.sent_mail['personalizations'][1]['subject']).to eq(personalizations[1]['subject'])
|
620
|
+
end
|
621
|
+
|
622
|
+
it 'sets the provided headers personalizations' do
|
623
|
+
mailer.deliver!(mail)
|
624
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('headers')
|
625
|
+
expect(client.sent_mail['personalizations'][1]['headers']).to eq(personalizations[1]['headers'])
|
626
|
+
end
|
627
|
+
|
628
|
+
it 'sets the provided custom_arg personalizations' do
|
629
|
+
mailer.deliver!(mail)
|
630
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('custom_args')
|
631
|
+
expect(client.sent_mail['personalizations'][1]['custom_args']).to eq(personalizations[1]['custom_args'])
|
632
|
+
end
|
633
|
+
|
634
|
+
it 'sets the provided send_at personalizations' do
|
635
|
+
mailer.deliver!(mail)
|
636
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('send_at')
|
637
|
+
expect(client.sent_mail['personalizations'][1]['send_at']).to eq(personalizations[1]['send_at'])
|
638
|
+
end
|
639
|
+
|
640
|
+
it 'sets the provided substitution personalizations' do
|
641
|
+
mailer.deliver!(mail)
|
642
|
+
expect(client.sent_mail['personalizations'][1]['substitutions']).to include(personalizations[1]['substitutions'])
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'adds to the unsubscribe link substitutions' do
|
646
|
+
mailer.deliver!(mail)
|
647
|
+
expect(client.sent_mail['personalizations'][0]['substitutions']).to eq({
|
648
|
+
'%asm_group_unsubscribe_raw_url%' => '<%asm_group_unsubscribe_raw_url%>',
|
649
|
+
'%asm_global_unsubscribe_raw_url%' => '<%asm_global_unsubscribe_raw_url%>',
|
650
|
+
'%asm_preferences_raw_url%' => '<%asm_preferences_raw_url%>'
|
651
|
+
})
|
652
|
+
expect(client.sent_mail['personalizations'][1]['substitutions']).to include({
|
653
|
+
'%asm_group_unsubscribe_raw_url%' => '<%asm_group_unsubscribe_raw_url%>',
|
654
|
+
'%asm_global_unsubscribe_raw_url%' => '<%asm_global_unsubscribe_raw_url%>',
|
655
|
+
'%asm_preferences_raw_url%' => '<%asm_preferences_raw_url%>'
|
656
|
+
})
|
657
|
+
end
|
658
|
+
|
659
|
+
context 'with symbols used as keys' do
|
660
|
+
let(:personalizations) do
|
661
|
+
[
|
662
|
+
{
|
663
|
+
to: [
|
664
|
+
{email: 'sally1@example.com', name: 'Sally 1'},
|
665
|
+
{email: 'sally2@example.com', name: 'Sally 2'},
|
666
|
+
]
|
667
|
+
}
|
668
|
+
]
|
669
|
+
end
|
670
|
+
|
671
|
+
it 'still works' do
|
672
|
+
mailer.deliver!(mail)
|
673
|
+
expect(client.sent_mail['personalizations'].length).to eq(1)
|
674
|
+
expected_to = personalizations[0][:to].map { |t| transform_keys(t, &:to_s) }
|
675
|
+
expect(client.sent_mail['personalizations'][0]['to']).to eq(expected_to)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
context 'dynamic template data passed into a personalizaiton' do
|
680
|
+
let(:personalization_data) do
|
681
|
+
{
|
682
|
+
'variable_1' => '1', 'variable_2' => '2'
|
683
|
+
}
|
684
|
+
end
|
685
|
+
|
686
|
+
let(:personalizations_with_dynamic_data) do
|
687
|
+
personalizations.tap do |p|
|
688
|
+
p[1]['dynamic_template_data'] = personalization_data
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
before do
|
693
|
+
mail['personalizations'] = nil
|
694
|
+
mail['personalizations'] = personalizations_with_dynamic_data
|
695
|
+
end
|
696
|
+
|
697
|
+
it 'sets the provided dynamic template data personalizations' do
|
698
|
+
mailer.deliver!(mail)
|
699
|
+
expect(client.sent_mail['personalizations'][0]).to_not have_key('dynamic_template_data')
|
700
|
+
expect(client.sent_mail['personalizations'][1]['dynamic_template_data']).to eq(personalization_data)
|
701
|
+
end
|
702
|
+
|
703
|
+
context 'dynamic template data is also set on the mail object' do
|
704
|
+
let(:mail_template_data) do
|
705
|
+
{ 'variable_3' => '1', 'variable_4' => '2' }
|
706
|
+
end
|
707
|
+
|
708
|
+
before { mail['dynamic_template_data'] = mail_template_data.dup }
|
709
|
+
|
710
|
+
it 'sets dynamic_template_data where not also provided as a personalization' do
|
711
|
+
mailer.deliver!(mail)
|
712
|
+
expect(client.sent_mail['personalizations'][0]['dynamic_template_data']).to eq(mail_template_data)
|
713
|
+
end
|
714
|
+
|
715
|
+
it 'merges the template data with a personalizations dynamic data' do
|
716
|
+
mailer.deliver!(mail)
|
717
|
+
expect(client.sent_mail['personalizations'][1]['dynamic_template_data']).to eq(
|
718
|
+
mail_template_data.merge(personalization_data)
|
719
|
+
)
|
720
|
+
end
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
context 'when to is set on mail object' do
|
725
|
+
before { mail.to = 'test@sendgrid.com' }
|
726
|
+
|
727
|
+
it 'adds that to address as a separate personalization' do
|
728
|
+
mailer.deliver!(mail)
|
729
|
+
expect(client.sent_mail['personalizations'].length).to eq(3)
|
730
|
+
expect(client.sent_mail['personalizations'][0]['to']).to eq(personalizations[0]['to'])
|
731
|
+
expect(client.sent_mail['personalizations'][1]['to']).to eq(personalizations[1]['to'])
|
732
|
+
expect(client.sent_mail['personalizations'][2]['to']).to eq([{"email"=>"test@sendgrid.com"}])
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
context 'when cc is set on mail object' do
|
737
|
+
before { mail.cc = 'test@sendgrid.com' }
|
738
|
+
|
739
|
+
it 'adds that cc address as a separate personalization' do
|
740
|
+
mailer.deliver!(mail)
|
741
|
+
expect(client.sent_mail['personalizations'].length).to eq(3)
|
742
|
+
expect(client.sent_mail['personalizations'][0]['cc']).to eq(personalizations[0]['cc'])
|
743
|
+
expect(client.sent_mail['personalizations'][1]['cc']).to eq(personalizations[1]['cc'])
|
744
|
+
expect(client.sent_mail['personalizations'][2]['cc']).to eq([{"email"=>"test@sendgrid.com"}])
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
context 'when bcc is set on mail object' do
|
749
|
+
before { mail.bcc = 'test@sendgrid.com' }
|
750
|
+
|
751
|
+
it 'adds that bcc address as a separate personalization' do
|
752
|
+
mailer.deliver!(mail)
|
753
|
+
expect(client.sent_mail['personalizations'].length).to eq(3)
|
754
|
+
expect(client.sent_mail['personalizations'][0]['bcc']).to eq(personalizations[0]['bcc'])
|
755
|
+
expect(client.sent_mail['personalizations'][1]['bcc']).to eq(personalizations[1]['bcc'])
|
756
|
+
expect(client.sent_mail['personalizations'][2]['bcc']).to eq([{"email"=>"test@sendgrid.com"}])
|
757
|
+
end
|
758
|
+
end
|
759
|
+
end
|
512
760
|
end
|
513
761
|
end
|
514
762
|
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:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eddie Zaneski
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2020-03-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mail
|
@@ -18,28 +18,28 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '2.
|
21
|
+
version: '2.7'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '2.
|
28
|
+
version: '2.7'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: sendgrid-ruby
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
35
|
+
version: '6.0'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: '6.0'
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: appraisal
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,8 +128,6 @@ files:
|
|
128
128
|
- LICENSE.txt
|
129
129
|
- README.md
|
130
130
|
- Rakefile
|
131
|
-
- gemfiles/mail_2.5.gemfile
|
132
|
-
- gemfiles/mail_2.6.gemfile
|
133
131
|
- gemfiles/mail_2.7.gemfile
|
134
132
|
- lib/sendgrid-actionmailer.rb
|
135
133
|
- lib/sendgrid_actionmailer.rb
|
@@ -157,8 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
155
|
- !ruby/object:Gem::Version
|
158
156
|
version: '0'
|
159
157
|
requirements: []
|
160
|
-
|
161
|
-
rubygems_version: 2.6.14
|
158
|
+
rubygems_version: 3.0.6
|
162
159
|
signing_key:
|
163
160
|
specification_version: 4
|
164
161
|
summary: SendGrid support for ActionMailer.
|
data/gemfiles/mail_2.5.gemfile
DELETED