sendgrid-ruby 5.3.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE +3 -1
- data/CHANGELOG.md +25 -0
- data/CODE_OF_CONDUCT.md +11 -11
- data/CONTRIBUTING.md +17 -22
- data/LICENSE.txt +1 -1
- data/README.md +25 -12
- data/Rakefile +1 -1
- data/TROUBLESHOOTING.md +21 -15
- data/UPGRADE.md +5 -0
- data/USAGE.md +1103 -1101
- data/USE_CASES.md +248 -18
- data/examples/helpers/mail/example.rb +7 -7
- data/examples/ips/ips.rb +13 -0
- data/examples/mail/mail.rb +2 -2
- data/examples/scopes/scopes.rb +49 -3
- data/examples/{whitelabel/whitelabel.rb → senderauthentication/senderauthentication.rb} +27 -27
- data/examples/suppression/suppression.rb +10 -10
- data/lib/sendgrid-ruby.rb +2 -0
- data/lib/sendgrid/client.rb +12 -9
- data/lib/sendgrid/helpers/inbound/README.md +22 -5
- data/lib/sendgrid/helpers/inbound/app.rb +13 -1
- data/lib/sendgrid/helpers/inbound/public/index.html +1 -1
- data/lib/sendgrid/helpers/inbound/sample_data/default_data.txt +2 -2
- data/lib/sendgrid/helpers/inbound/sample_data/raw_data.txt +2 -2
- data/lib/sendgrid/helpers/inbound/sample_data/raw_data_with_attachments.txt +2 -2
- data/lib/sendgrid/helpers/inbound/send.rb +2 -2
- data/lib/sendgrid/helpers/ip_management/ip_management.rb +17 -0
- data/lib/sendgrid/helpers/mail/README.md +1 -1
- data/lib/sendgrid/helpers/mail/attachment.rb +24 -1
- data/lib/sendgrid/helpers/mail/category.rb +0 -8
- data/lib/sendgrid/helpers/mail/content.rb +3 -16
- data/lib/sendgrid/helpers/mail/email.rb +3 -16
- data/lib/sendgrid/helpers/mail/mail.rb +8 -40
- data/lib/sendgrid/helpers/permissions/scope.rb +28 -0
- data/lib/sendgrid/helpers/permissions/scopes.yml +309 -0
- data/lib/sendgrid/helpers/settings/README.md +1 -1
- data/lib/sendgrid/helpers/stats/stats_response.rb +1 -1
- data/lib/sendgrid/version.rb +1 -1
- data/mail_helper_v3.md +9 -9
- data/sendgrid-ruby.gemspec +3 -3
- data/spec/sendgrid/helpers/ip_management/ip_management_spec.rb +12 -0
- data/test/sendgrid/helpers/mail/test_attachment.rb +35 -0
- data/test/sendgrid/helpers/mail/test_mail.rb +29 -21
- data/test/sendgrid/permissions/test_scopes.rb +38 -0
- data/test/sendgrid/test_sendgrid-ruby.rb +15 -7
- metadata +17 -6
@@ -5,7 +5,7 @@ sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
|
|
5
5
|
|
6
6
|
|
7
7
|
##################################################
|
8
|
-
# Create a domain
|
8
|
+
# Create a domain authentication. #
|
9
9
|
# POST /whitelabel/domains #
|
10
10
|
|
11
11
|
data = JSON.parse('{
|
@@ -26,7 +26,7 @@ puts response.body
|
|
26
26
|
puts response.headers
|
27
27
|
|
28
28
|
##################################################
|
29
|
-
# List all domain
|
29
|
+
# List all domain authentications. #
|
30
30
|
# GET /whitelabel/domains #
|
31
31
|
|
32
32
|
params = JSON.parse('{"username": "test_string", "domain": "test_string", "exclude_subusers": "true", "limit": 1, "offset": 1}')
|
@@ -36,7 +36,7 @@ puts response.body
|
|
36
36
|
puts response.headers
|
37
37
|
|
38
38
|
##################################################
|
39
|
-
# Get the default domain
|
39
|
+
# Get the default domain authentication. #
|
40
40
|
# GET /whitelabel/domains/default #
|
41
41
|
|
42
42
|
response = sg.client.whitelabel.domains.default.get()
|
@@ -45,7 +45,7 @@ puts response.body
|
|
45
45
|
puts response.headers
|
46
46
|
|
47
47
|
##################################################
|
48
|
-
# List the domain
|
48
|
+
# List the domain authentication associated with the given user. #
|
49
49
|
# GET /whitelabel/domains/subuser #
|
50
50
|
|
51
51
|
response = sg.client.whitelabel.domains.subuser.get()
|
@@ -54,7 +54,7 @@ puts response.body
|
|
54
54
|
puts response.headers
|
55
55
|
|
56
56
|
##################################################
|
57
|
-
# Disassociate a domain
|
57
|
+
# Disassociate a domain authentication from a given user. #
|
58
58
|
# DELETE /whitelabel/domains/subuser #
|
59
59
|
|
60
60
|
response = sg.client.whitelabel.domains.subuser.delete()
|
@@ -63,7 +63,7 @@ puts response.body
|
|
63
63
|
puts response.headers
|
64
64
|
|
65
65
|
##################################################
|
66
|
-
# Update a domain
|
66
|
+
# Update a domain authentication. #
|
67
67
|
# PATCH /whitelabel/domains/{domain_id} #
|
68
68
|
|
69
69
|
data = JSON.parse('{
|
@@ -77,7 +77,7 @@ puts response.body
|
|
77
77
|
puts response.headers
|
78
78
|
|
79
79
|
##################################################
|
80
|
-
# Retrieve a domain
|
80
|
+
# Retrieve a domain authentication. #
|
81
81
|
# GET /whitelabel/domains/{domain_id} #
|
82
82
|
|
83
83
|
domain_id = "test_url_param"
|
@@ -87,7 +87,7 @@ puts response.body
|
|
87
87
|
puts response.headers
|
88
88
|
|
89
89
|
##################################################
|
90
|
-
# Delete a domain
|
90
|
+
# Delete a domain authentication. #
|
91
91
|
# DELETE /whitelabel/domains/{domain_id} #
|
92
92
|
|
93
93
|
domain_id = "test_url_param"
|
@@ -97,7 +97,7 @@ puts response.body
|
|
97
97
|
puts response.headers
|
98
98
|
|
99
99
|
##################################################
|
100
|
-
# Associate a domain
|
100
|
+
# Associate a domain authentication with a given user. #
|
101
101
|
# POST /whitelabel/domains/{domain_id}/subuser #
|
102
102
|
|
103
103
|
data = JSON.parse('{
|
@@ -110,7 +110,7 @@ puts response.body
|
|
110
110
|
puts response.headers
|
111
111
|
|
112
112
|
##################################################
|
113
|
-
# Add an IP to a domain
|
113
|
+
# Add an IP to a domain authentication. #
|
114
114
|
# POST /whitelabel/domains/{id}/ips #
|
115
115
|
|
116
116
|
data = JSON.parse('{
|
@@ -123,7 +123,7 @@ puts response.body
|
|
123
123
|
puts response.headers
|
124
124
|
|
125
125
|
##################################################
|
126
|
-
# Remove an IP from a domain
|
126
|
+
# Remove an IP from a domain authentication. #
|
127
127
|
# DELETE /whitelabel/domains/{id}/ips/{ip} #
|
128
128
|
|
129
129
|
id = "test_url_param"
|
@@ -134,7 +134,7 @@ puts response.body
|
|
134
134
|
puts response.headers
|
135
135
|
|
136
136
|
##################################################
|
137
|
-
# Validate a domain
|
137
|
+
# Validate a domain authentication. #
|
138
138
|
# POST /whitelabel/domains/{id}/validate #
|
139
139
|
|
140
140
|
id = "test_url_param"
|
@@ -144,7 +144,7 @@ puts response.body
|
|
144
144
|
puts response.headers
|
145
145
|
|
146
146
|
##################################################
|
147
|
-
# Create
|
147
|
+
# Create a reverse DNS record #
|
148
148
|
# POST /whitelabel/ips #
|
149
149
|
|
150
150
|
data = JSON.parse('{
|
@@ -158,7 +158,7 @@ puts response.body
|
|
158
158
|
puts response.headers
|
159
159
|
|
160
160
|
##################################################
|
161
|
-
# Retrieve
|
161
|
+
# Retrieve a reverse DNS record #
|
162
162
|
# GET /whitelabel/ips #
|
163
163
|
|
164
164
|
params = JSON.parse('{"ip": "test_string", "limit": 1, "offset": 1}')
|
@@ -168,7 +168,7 @@ puts response.body
|
|
168
168
|
puts response.headers
|
169
169
|
|
170
170
|
##################################################
|
171
|
-
# Retrieve
|
171
|
+
# Retrieve a reverse DNS record #
|
172
172
|
# GET /whitelabel/ips/{id} #
|
173
173
|
|
174
174
|
id = "test_url_param"
|
@@ -178,7 +178,7 @@ puts response.body
|
|
178
178
|
puts response.headers
|
179
179
|
|
180
180
|
##################################################
|
181
|
-
# Delete
|
181
|
+
# Delete a reverse DNS record #
|
182
182
|
# DELETE /whitelabel/ips/{id} #
|
183
183
|
|
184
184
|
id = "test_url_param"
|
@@ -188,7 +188,7 @@ puts response.body
|
|
188
188
|
puts response.headers
|
189
189
|
|
190
190
|
##################################################
|
191
|
-
# Validate
|
191
|
+
# Validate a reverse DNS record #
|
192
192
|
# POST /whitelabel/ips/{id}/validate #
|
193
193
|
|
194
194
|
id = "test_url_param"
|
@@ -198,7 +198,7 @@ puts response.body
|
|
198
198
|
puts response.headers
|
199
199
|
|
200
200
|
##################################################
|
201
|
-
# Create a Link
|
201
|
+
# Create a Branded Link #
|
202
202
|
# POST /whitelabel/links #
|
203
203
|
|
204
204
|
data = JSON.parse('{
|
@@ -213,7 +213,7 @@ puts response.body
|
|
213
213
|
puts response.headers
|
214
214
|
|
215
215
|
##################################################
|
216
|
-
# Retrieve all link
|
216
|
+
# Retrieve all link brandings #
|
217
217
|
# GET /whitelabel/links #
|
218
218
|
|
219
219
|
params = JSON.parse('{"limit": 1}')
|
@@ -223,7 +223,7 @@ puts response.body
|
|
223
223
|
puts response.headers
|
224
224
|
|
225
225
|
##################################################
|
226
|
-
# Retrieve a Default Link
|
226
|
+
# Retrieve a Default Link Branding #
|
227
227
|
# GET /whitelabel/links/default #
|
228
228
|
|
229
229
|
params = JSON.parse('{"domain": "test_string"}')
|
@@ -233,7 +233,7 @@ puts response.body
|
|
233
233
|
puts response.headers
|
234
234
|
|
235
235
|
##################################################
|
236
|
-
# Retrieve Associated Link
|
236
|
+
# Retrieve Associated Link Branding #
|
237
237
|
# GET /whitelabel/links/subuser #
|
238
238
|
|
239
239
|
params = JSON.parse('{"username": "test_string"}')
|
@@ -243,7 +243,7 @@ puts response.body
|
|
243
243
|
puts response.headers
|
244
244
|
|
245
245
|
##################################################
|
246
|
-
# Disassociate a Link
|
246
|
+
# Disassociate a Link Branding #
|
247
247
|
# DELETE /whitelabel/links/subuser #
|
248
248
|
|
249
249
|
params = JSON.parse('{"username": "test_string"}')
|
@@ -253,7 +253,7 @@ puts response.body
|
|
253
253
|
puts response.headers
|
254
254
|
|
255
255
|
##################################################
|
256
|
-
# Update a Link
|
256
|
+
# Update a Link Branding #
|
257
257
|
# PATCH /whitelabel/links/{id} #
|
258
258
|
|
259
259
|
data = JSON.parse('{
|
@@ -266,7 +266,7 @@ puts response.body
|
|
266
266
|
puts response.headers
|
267
267
|
|
268
268
|
##################################################
|
269
|
-
# Retrieve a Link
|
269
|
+
# Retrieve a Link Branding #
|
270
270
|
# GET /whitelabel/links/{id} #
|
271
271
|
|
272
272
|
id = "test_url_param"
|
@@ -276,7 +276,7 @@ puts response.body
|
|
276
276
|
puts response.headers
|
277
277
|
|
278
278
|
##################################################
|
279
|
-
# Delete a Link
|
279
|
+
# Delete a Link Branding #
|
280
280
|
# DELETE /whitelabel/links/{id} #
|
281
281
|
|
282
282
|
id = "test_url_param"
|
@@ -286,7 +286,7 @@ puts response.body
|
|
286
286
|
puts response.headers
|
287
287
|
|
288
288
|
##################################################
|
289
|
-
# Validate a Link
|
289
|
+
# Validate a Link Branding #
|
290
290
|
# POST /whitelabel/links/{id}/validate #
|
291
291
|
|
292
292
|
id = "test_url_param"
|
@@ -296,7 +296,7 @@ puts response.body
|
|
296
296
|
puts response.headers
|
297
297
|
|
298
298
|
##################################################
|
299
|
-
# Associate a Link
|
299
|
+
# Associate a Link Branding #
|
300
300
|
# POST /whitelabel/links/{link_id}/subuser #
|
301
301
|
|
302
302
|
data = JSON.parse('{
|
@@ -19,9 +19,9 @@ puts response.headers
|
|
19
19
|
# DELETE /suppression/blocks #
|
20
20
|
|
21
21
|
data = JSON.parse('{
|
22
|
-
"delete_all": false,
|
22
|
+
"delete_all": false,
|
23
23
|
"emails": [
|
24
|
-
"example1@example.com",
|
24
|
+
"example1@example.com",
|
25
25
|
"example2@example.com"
|
26
26
|
]
|
27
27
|
}')
|
@@ -65,9 +65,9 @@ puts response.headers
|
|
65
65
|
# DELETE /suppression/bounces #
|
66
66
|
|
67
67
|
data = JSON.parse('{
|
68
|
-
"delete_all": true,
|
68
|
+
"delete_all": true,
|
69
69
|
"emails": [
|
70
|
-
"example@example.com",
|
70
|
+
"example@example.com",
|
71
71
|
"example2@example.com"
|
72
72
|
]
|
73
73
|
}')
|
@@ -112,9 +112,9 @@ puts response.headers
|
|
112
112
|
# DELETE /suppression/invalid_emails #
|
113
113
|
|
114
114
|
data = JSON.parse('{
|
115
|
-
"delete_all": false,
|
115
|
+
"delete_all": false,
|
116
116
|
"emails": [
|
117
|
-
"example1@example.com",
|
117
|
+
"example1@example.com",
|
118
118
|
"example2@example.com"
|
119
119
|
]
|
120
120
|
}')
|
@@ -148,7 +148,7 @@ puts response.headers
|
|
148
148
|
# GET /suppression/spam_report/{email} #
|
149
149
|
|
150
150
|
email = "test_url_param"
|
151
|
-
response = sg.client.suppression.
|
151
|
+
response = sg.client.suppression.spam_reports._(email).get()
|
152
152
|
puts response.status_code
|
153
153
|
puts response.body
|
154
154
|
puts response.headers
|
@@ -158,7 +158,7 @@ puts response.headers
|
|
158
158
|
# DELETE /suppression/spam_report/{email} #
|
159
159
|
|
160
160
|
email = "test_url_param"
|
161
|
-
response = sg.client.suppression.
|
161
|
+
response = sg.client.suppression.spam_reports._(email).delete()
|
162
162
|
puts response.status_code
|
163
163
|
puts response.body
|
164
164
|
puts response.headers
|
@@ -178,9 +178,9 @@ puts response.headers
|
|
178
178
|
# DELETE /suppression/spam_reports #
|
179
179
|
|
180
180
|
data = JSON.parse('{
|
181
|
-
"delete_all": false,
|
181
|
+
"delete_all": false,
|
182
182
|
"emails": [
|
183
|
-
"example1@example.com",
|
183
|
+
"example1@example.com",
|
184
184
|
"example2@example.com"
|
185
185
|
]
|
186
186
|
}')
|
data/lib/sendgrid-ruby.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'sendgrid/client'
|
2
2
|
require_relative 'sendgrid/version'
|
3
|
+
require_relative 'sendgrid/helpers/ip_management/ip_management'
|
3
4
|
require_relative 'sendgrid/helpers/mail/asm'
|
4
5
|
require_relative 'sendgrid/helpers/mail/attachment'
|
5
6
|
require_relative 'sendgrid/helpers/mail/bcc_settings'
|
@@ -25,3 +26,4 @@ require_relative 'sendgrid/helpers/settings/settings'
|
|
25
26
|
require_relative 'sendgrid/helpers/stats/email_stats'
|
26
27
|
require_relative 'sendgrid/helpers/stats/stats_response'
|
27
28
|
require_relative 'sendgrid/helpers/stats/metrics'
|
29
|
+
require_relative 'sendgrid/helpers/permissions/scope'
|
data/lib/sendgrid/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Quickly and easily access the SendGrid API.
|
1
|
+
# Quickly and easily access the Twilio SendGrid API.
|
2
2
|
require 'ruby_http_client'
|
3
3
|
require_relative 'version'
|
4
4
|
|
@@ -6,26 +6,29 @@ module SendGrid
|
|
6
6
|
# Initialize the HTTP client
|
7
7
|
class API
|
8
8
|
attr_accessor :client
|
9
|
-
attr_reader :request_headers, :host, :version
|
9
|
+
attr_reader :request_headers, :host, :version, :impersonate_subuser
|
10
10
|
# * *Args* :
|
11
|
-
# - +api_key+ -> your SendGrid API key
|
11
|
+
# - +api_key+ -> your Twilio SendGrid API key
|
12
12
|
# - +host+ -> the base URL for the API
|
13
13
|
# - +request_headers+ -> any headers that you want to be globally applied
|
14
14
|
# - +version+ -> the version of the API you wish to access,
|
15
15
|
# currently only "v3" is supported
|
16
16
|
#
|
17
|
-
def initialize(api_key: '', host: nil, request_headers: nil, version: nil)
|
18
|
-
@api_key
|
19
|
-
@host
|
20
|
-
@version
|
21
|
-
@
|
22
|
-
@
|
17
|
+
def initialize(api_key: '', host: nil, request_headers: nil, version: nil, impersonate_subuser: nil)
|
18
|
+
@api_key = api_key
|
19
|
+
@host = host ? host : 'https://api.sendgrid.com'
|
20
|
+
@version = version ? version : 'v3'
|
21
|
+
@impersonate_subuser = impersonate_subuser
|
22
|
+
@user_agent = "sendgrid/#{SendGrid::VERSION};ruby"
|
23
|
+
@request_headers = JSON.parse('
|
23
24
|
{
|
24
25
|
"Authorization": "Bearer ' + @api_key + '",
|
25
26
|
"Accept": "application/json",
|
26
27
|
"User-agent": "' + @user_agent + '"
|
27
28
|
}
|
28
29
|
')
|
30
|
+
@request_headers['On-Behalf-Of'] = @impersonate_subuser if @impersonate_subuser
|
31
|
+
|
29
32
|
|
30
33
|
@request_headers = @request_headers.merge(request_headers) if request_headers
|
31
34
|
@client = Client.new(host: "#{@host}/#{@version}",
|
@@ -2,12 +2,29 @@
|
|
2
2
|
|
3
3
|
## Table of Contents
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
- [Installation](#installation)
|
6
|
+
- [Quick Start for Local Testing with Sample Data](#quick-start-for-local-testing-with-sample-data)
|
7
|
+
- [Quick Start for Local Testing with Real Data](#quick-start-for-local-testing-with-real-data)
|
8
|
+
- [Code Walkthrough](#code-walkthrough)
|
9
|
+
- [app.rb](#apprb)
|
10
|
+
- [config.yml](#configyml)
|
11
|
+
- [send.rb & /sample_data](#sendrb--sampledata)
|
12
|
+
- [Contributing](#contributing)
|
9
13
|
|
10
14
|
<a name="quick_start_local_sample"></a>
|
15
|
+
|
16
|
+
|
17
|
+
# Installation
|
18
|
+
|
19
|
+
In addition to the installation instructions in
|
20
|
+
[the main readme](https://github.com/sendgrid/sendgrid-ruby/tree/master/#installation),
|
21
|
+
you must also add sinatra to your Gemfile:
|
22
|
+
|
23
|
+
```
|
24
|
+
gem 'sinatra', '>= 1.4.7', '< 3'
|
25
|
+
```
|
26
|
+
|
27
|
+
|
11
28
|
# Quick Start for Local Testing with Sample Data
|
12
29
|
|
13
30
|
```bash
|
@@ -53,7 +70,7 @@ In another terminal, use [ngrok](https://ngrok.com/) to allow external access to
|
|
53
70
|
ngrok http 9292
|
54
71
|
```
|
55
72
|
|
56
|
-
Update your SendGrid Incoming Parse settings: [Settings Page](https://app.sendgrid.com/settings/parse) | [Docs](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Pointing-to-a-Hostname-and-URL)
|
73
|
+
Update your Twilio SendGrid Incoming Parse settings: [Settings Page](https://app.sendgrid.com/settings/parse) | [Docs](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Pointing-to-a-Hostname-and-URL)
|
57
74
|
|
58
75
|
- For the HOSTNAME field, use the domain that you changed the MX records (e.g. inbound.yourdomain.com)
|
59
76
|
- For the URL field, use the URL generated by ngrok + /inbound, e.g http://XXXXXXX.ngrok.io/inbound
|
@@ -1,4 +1,16 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'sinatra'
|
3
|
+
rescue LoadError
|
4
|
+
puts <<-NOTE
|
5
|
+
As of sengrid verison 6, sinatra is no longer specified as a dependency of
|
6
|
+
the sendgrid gem. All the functionality of the inbound server is still the same
|
7
|
+
and fully supported, but you just need to include the sinatra dependency in your gemfile
|
8
|
+
yourself, like so:
|
9
|
+
|
10
|
+
gem 'sinatra', '>= 1.4.7', '< 3'
|
11
|
+
NOTE
|
12
|
+
raise
|
13
|
+
end
|
2
14
|
require 'logger'
|
3
15
|
require 'json'
|
4
16
|
require 'yaml'
|
@@ -20,7 +20,7 @@ inbound@inbound.example.com
|
|
20
20
|
--xYzZY
|
21
21
|
Content-Disposition: form-data; name="html"
|
22
22
|
|
23
|
-
<html><body><strong>Hello SendGrid!</body></html>
|
23
|
+
<html><body><strong>Hello Twilio SendGrid!</body></html>
|
24
24
|
|
25
25
|
--xYzZY
|
26
26
|
Content-Disposition: form-data; name="from"
|
@@ -29,7 +29,7 @@ Example User <test@example.com>
|
|
29
29
|
--xYzZY
|
30
30
|
Content-Disposition: form-data; name="text"
|
31
31
|
|
32
|
-
Hello SendGrid!
|
32
|
+
Hello Twilio SendGrid!
|
33
33
|
|
34
34
|
--xYzZY
|
35
35
|
Content-Disposition: form-data; name="sender_ip"
|
@@ -16,13 +16,13 @@ Content-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a
|
|
16
16
|
--001a113ee97c89842f0539be8e7a
|
17
17
|
Content-Type: text/plain; charset=UTF-8
|
18
18
|
|
19
|
-
Hello SendGrid!
|
19
|
+
Hello Twilio SendGrid!
|
20
20
|
|
21
21
|
--001a113ee97c89842f0539be8e7a
|
22
22
|
Content-Type: text/html; charset=UTF-8
|
23
23
|
Content-Transfer-Encoding: quoted-printable
|
24
24
|
|
25
|
-
<html><body><strong>Hello SendGrid!</body></html>
|
25
|
+
<html><body><strong>Hello Twilio SendGrid!</body></html>
|
26
26
|
|
27
27
|
--001a113ee97c89842f0539be8e7a--
|
28
28
|
|