sendgrid-ruby 6.2.0 → 6.6.2
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/ISSUE_TEMPLATE/config.yml +10 -0
- data/.github/workflows/test-and-deploy.yml +120 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +127 -0
- data/CHANGELOG.md +147 -9
- data/CONTRIBUTING.md +11 -21
- data/Dockerfile +14 -0
- data/FIRST_TIMERS.md +79 -0
- data/Gemfile +0 -1
- data/ISSUE_TEMPLATE.md +5 -1
- data/{LICENSE.md → LICENSE} +1 -1
- data/Makefile +9 -2
- data/PULL_REQUEST_TEMPLATE.md +5 -5
- data/README.md +23 -31
- data/Rakefile +2 -3
- data/TROUBLESHOOTING.md +17 -5
- data/USAGE.md +146 -39
- data/examples/accesssettings/accesssettings.rb +9 -12
- data/examples/alerts/alerts.rb +8 -11
- data/examples/apikeys/apikeys.rb +12 -15
- data/examples/asm/asm.rb +27 -30
- data/examples/browsers/browsers.rb +0 -3
- data/examples/campaigns/campaigns.rb +29 -32
- data/examples/categories/categories.rb +0 -3
- data/examples/clients/clients.rb +1 -4
- data/examples/contactdb/contactdb.rb +63 -66
- data/examples/devices/devices.rb +0 -3
- data/examples/emailactivity/emailactivity.rb +52 -0
- data/examples/geo/geo.rb +0 -3
- data/examples/helpers/eventwebhook/example.rb +16 -0
- data/examples/helpers/mail/example.rb +24 -13
- data/examples/helpers/settings/example.rb +1 -1
- data/examples/helpers/stats/example.rb +4 -4
- data/examples/ips/ips.rb +19 -22
- data/examples/mail/mail.rb +72 -75
- data/examples/mailboxproviders/mailboxproviders.rb +0 -3
- data/examples/mailsettings/mailsettings.rb +21 -24
- data/examples/partnersettings/partnersettings.rb +3 -6
- data/examples/scopes/scopes.rb +8 -10
- data/examples/senderauthentication/senderauthentication.rb +41 -44
- data/examples/senders/senders.rb +28 -31
- data/examples/stats/stats.rb +0 -3
- data/examples/subusers/subusers.rb +17 -20
- data/examples/suppression/suppression.rb +15 -18
- data/examples/templates/templates.rb +29 -31
- data/examples/trackingsettings/trackingsettings.rb +14 -17
- data/examples/user/user.rb +41 -44
- data/lib/rack/sendgrid_webhook_verification.rb +55 -0
- data/lib/sendgrid/base_interface.rb +8 -4
- data/lib/sendgrid/helpers/eventwebhook/eventwebhook.rb +50 -0
- data/lib/sendgrid/helpers/inbound/README.md +5 -5
- data/lib/sendgrid/helpers/inbound/app.rb +2 -2
- data/lib/sendgrid/helpers/inbound/public/index.html +1 -1
- data/lib/sendgrid/helpers/inbound/send.rb +3 -3
- data/lib/sendgrid/helpers/ip_management/ip_management.rb +1 -1
- data/lib/sendgrid/helpers/mail/README.md +3 -3
- data/lib/sendgrid/helpers/mail/asm.rb +6 -18
- data/lib/sendgrid/helpers/mail/attachment.rb +12 -42
- data/lib/sendgrid/helpers/mail/bcc_settings.rb +6 -18
- data/lib/sendgrid/helpers/mail/bypass_list_management.rb +8 -18
- data/lib/sendgrid/helpers/mail/category.rb +2 -2
- data/lib/sendgrid/helpers/mail/click_tracking.rb +6 -18
- data/lib/sendgrid/helpers/mail/content.rb +4 -3
- data/lib/sendgrid/helpers/mail/custom_arg.rb +6 -10
- data/lib/sendgrid/helpers/mail/email.rb +10 -5
- data/lib/sendgrid/helpers/mail/footer.rb +7 -27
- data/lib/sendgrid/helpers/mail/ganalytics.rb +10 -54
- data/lib/sendgrid/helpers/mail/header.rb +6 -10
- data/lib/sendgrid/helpers/mail/mail.rb +32 -48
- data/lib/sendgrid/helpers/mail/mail_settings.rb +9 -25
- data/lib/sendgrid/helpers/mail/open_tracking.rb +6 -18
- data/lib/sendgrid/helpers/mail/personalization.rb +40 -27
- data/lib/sendgrid/helpers/mail/section.rb +6 -10
- data/lib/sendgrid/helpers/mail/spam_check.rb +7 -27
- data/lib/sendgrid/helpers/mail/subscription_tracking.rb +8 -36
- data/lib/sendgrid/helpers/mail/substitution.rb +6 -10
- data/lib/sendgrid/helpers/mail/tracking_settings.rb +8 -20
- data/lib/sendgrid/helpers/permissions/scope.rb +2 -2
- data/lib/sendgrid/helpers/settings/README.md +2 -2
- data/lib/sendgrid/helpers/settings/settings.rb +1 -1
- data/lib/sendgrid/helpers/settings/tracking_settings_dto.rb +3 -5
- data/lib/sendgrid/helpers/stats/metrics.rb +5 -5
- data/lib/sendgrid/sendgrid.rb +4 -3
- data/lib/sendgrid/twilio_email.rb +1 -1
- data/lib/sendgrid/version.rb +1 -1
- data/lib/sendgrid-ruby.rb +2 -0
- data/mail_helper_v3.md +12 -12
- data/sendgrid-ruby.gemspec +8 -8
- data/spec/fixtures/event_webhook.rb +22 -0
- data/spec/rack/sendgrid_webhook_verification_spec.rb +142 -0
- data/spec/sendgrid/helpers/eventwebhook/eventwebhook_spec.rb +105 -0
- data/spec/sendgrid/helpers/settings/mail_settings_dto_spec.rb +3 -3
- data/spec/sendgrid/helpers/settings/partner_settings_dto_spec.rb +3 -3
- data/spec/sendgrid/helpers/settings/settings_spec.rb +2 -2
- data/spec/sendgrid/helpers/settings/tracking_settings_dto_spec.rb +3 -3
- data/spec/sendgrid/helpers/settings/user_settings_dto_spec.rb +3 -3
- data/spec/sendgrid/helpers/stats/email_stats_spec.rb +22 -23
- data/spec/sendgrid/helpers/stats/metrics_spec.rb +19 -20
- data/spec/sendgrid/helpers/stats/stats_response_spec.rb +22 -23
- data/spec/spec_helper.rb +3 -1
- data/static/img/github-fork.png +0 -0
- data/static/img/github-sign-up.png +0 -0
- data/test/sendgrid/helpers/mail/test_attachment.rb +4 -6
- data/test/sendgrid/helpers/mail/test_category.rb +0 -2
- data/test/sendgrid/helpers/mail/test_email.rb +17 -10
- data/test/sendgrid/helpers/mail/test_mail.rb +101 -102
- data/test/sendgrid/helpers/mail/test_personalizations.rb +145 -92
- data/test/sendgrid/permissions/test_scopes.rb +1 -3
- data/test/sendgrid/test_sendgrid-ruby.rb +1964 -1986
- data/twilio_sendgrid_logo.png +0 -0
- data/use-cases/README.md +17 -0
- data/use-cases/domain-authentication.md +5 -0
- data/use-cases/email-statistics.md +52 -0
- data/use-cases/legacy-templates.md +98 -0
- data/use-cases/personalizations.md +34 -0
- data/use-cases/sms.md +39 -0
- data/use-cases/transactional-templates.md +111 -0
- data/use-cases/twilio-email.md +13 -0
- data/use-cases/twilio-setup.md +54 -0
- metadata +69 -34
- data/.codeclimate.yml +0 -21
- data/.travis.yml +0 -40
- data/USE_CASES.md +0 -405
- data/docker/Dockerfile +0 -12
- data/docker/README.md +0 -30
- data/test/prism.sh +0 -42
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
require 'sendgrid-ruby'
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
|
|
5
4
|
|
|
6
|
-
|
|
7
5
|
##################################################
|
|
8
6
|
# Create a transactional template. #
|
|
9
7
|
# POST /templates #
|
|
@@ -17,10 +15,11 @@ puts response.body
|
|
|
17
15
|
puts response.headers
|
|
18
16
|
|
|
19
17
|
##################################################
|
|
20
|
-
# Retrieve all transactional templates. #
|
|
18
|
+
# Retrieve all transactional templates (legacy & dynamic). #
|
|
21
19
|
# GET /templates #
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
params = JSON.parse('{"generations": "legacy,dynamic"}')
|
|
22
|
+
response = sg.client.templates.get(query_params: params)
|
|
24
23
|
puts response.status_code
|
|
25
24
|
puts response.body
|
|
26
25
|
puts response.headers
|
|
@@ -32,7 +31,7 @@ puts response.headers
|
|
|
32
31
|
data = JSON.parse('{
|
|
33
32
|
"name": "new_example_name"
|
|
34
33
|
}')
|
|
35
|
-
template_id =
|
|
34
|
+
template_id = 'test_url_param'
|
|
36
35
|
response = sg.client.templates._(template_id).patch(request_body: data)
|
|
37
36
|
puts response.status_code
|
|
38
37
|
puts response.body
|
|
@@ -42,8 +41,8 @@ puts response.headers
|
|
|
42
41
|
# Retrieve a single transactional template. #
|
|
43
42
|
# GET /templates/{template_id} #
|
|
44
43
|
|
|
45
|
-
template_id =
|
|
46
|
-
response = sg.client.templates._(template_id).get
|
|
44
|
+
template_id = 'test_url_param'
|
|
45
|
+
response = sg.client.templates._(template_id).get
|
|
47
46
|
puts response.status_code
|
|
48
47
|
puts response.body
|
|
49
48
|
puts response.headers
|
|
@@ -52,8 +51,8 @@ puts response.headers
|
|
|
52
51
|
# Delete a template. #
|
|
53
52
|
# DELETE /templates/{template_id} #
|
|
54
53
|
|
|
55
|
-
template_id =
|
|
56
|
-
response = sg.client.templates._(template_id).delete
|
|
54
|
+
template_id = 'test_url_param'
|
|
55
|
+
response = sg.client.templates._(template_id).delete
|
|
57
56
|
puts response.status_code
|
|
58
57
|
puts response.body
|
|
59
58
|
puts response.headers
|
|
@@ -63,14 +62,14 @@ puts response.headers
|
|
|
63
62
|
# POST /templates/{template_id}/versions #
|
|
64
63
|
|
|
65
64
|
data = JSON.parse('{
|
|
66
|
-
"active": 1,
|
|
67
|
-
"html_content": "<%body%>",
|
|
68
|
-
"name": "example_version_name",
|
|
69
|
-
"plain_content": "<%body%>",
|
|
70
|
-
"subject": "<%subject%>",
|
|
65
|
+
"active": 1,
|
|
66
|
+
"html_content": "<%body%>",
|
|
67
|
+
"name": "example_version_name",
|
|
68
|
+
"plain_content": "<%body%>",
|
|
69
|
+
"subject": "<%subject%>",
|
|
71
70
|
"template_id": "ddb96bbc-9b92-425e-8979-99464621b543"
|
|
72
71
|
}')
|
|
73
|
-
template_id =
|
|
72
|
+
template_id = 'test_url_param'
|
|
74
73
|
response = sg.client.templates._(template_id).versions.post(request_body: data)
|
|
75
74
|
puts response.status_code
|
|
76
75
|
puts response.body
|
|
@@ -81,14 +80,14 @@ puts response.headers
|
|
|
81
80
|
# PATCH /templates/{template_id}/versions/{version_id} #
|
|
82
81
|
|
|
83
82
|
data = JSON.parse('{
|
|
84
|
-
"active": 1,
|
|
85
|
-
"html_content": "<%body%>",
|
|
86
|
-
"name": "updated_example_name",
|
|
87
|
-
"plain_content": "<%body%>",
|
|
83
|
+
"active": 1,
|
|
84
|
+
"html_content": "<%body%>",
|
|
85
|
+
"name": "updated_example_name",
|
|
86
|
+
"plain_content": "<%body%>",
|
|
88
87
|
"subject": "<%subject%>"
|
|
89
88
|
}')
|
|
90
|
-
template_id =
|
|
91
|
-
version_id =
|
|
89
|
+
template_id = 'test_url_param'
|
|
90
|
+
version_id = 'test_url_param'
|
|
92
91
|
response = sg.client.templates._(template_id).versions._(version_id).patch(request_body: data)
|
|
93
92
|
puts response.status_code
|
|
94
93
|
puts response.body
|
|
@@ -98,9 +97,9 @@ puts response.headers
|
|
|
98
97
|
# Retrieve a specific transactional template version. #
|
|
99
98
|
# GET /templates/{template_id}/versions/{version_id} #
|
|
100
99
|
|
|
101
|
-
template_id =
|
|
102
|
-
version_id =
|
|
103
|
-
response = sg.client.templates._(template_id).versions._(version_id).get
|
|
100
|
+
template_id = 'test_url_param'
|
|
101
|
+
version_id = 'test_url_param'
|
|
102
|
+
response = sg.client.templates._(template_id).versions._(version_id).get
|
|
104
103
|
puts response.status_code
|
|
105
104
|
puts response.body
|
|
106
105
|
puts response.headers
|
|
@@ -109,9 +108,9 @@ puts response.headers
|
|
|
109
108
|
# Delete a transactional template version. #
|
|
110
109
|
# DELETE /templates/{template_id}/versions/{version_id} #
|
|
111
110
|
|
|
112
|
-
template_id =
|
|
113
|
-
version_id =
|
|
114
|
-
response = sg.client.templates._(template_id).versions._(version_id).delete
|
|
111
|
+
template_id = 'test_url_param'
|
|
112
|
+
version_id = 'test_url_param'
|
|
113
|
+
response = sg.client.templates._(template_id).versions._(version_id).delete
|
|
115
114
|
puts response.status_code
|
|
116
115
|
puts response.body
|
|
117
116
|
puts response.headers
|
|
@@ -120,10 +119,9 @@ puts response.headers
|
|
|
120
119
|
# Activate a transactional template version. #
|
|
121
120
|
# POST /templates/{template_id}/versions/{version_id}/activate #
|
|
122
121
|
|
|
123
|
-
template_id =
|
|
124
|
-
version_id =
|
|
125
|
-
response = sg.client.templates._(template_id).versions._(version_id).activate.post
|
|
122
|
+
template_id = 'test_url_param'
|
|
123
|
+
version_id = 'test_url_param'
|
|
124
|
+
response = sg.client.templates._(template_id).versions._(version_id).activate.post
|
|
126
125
|
puts response.status_code
|
|
127
126
|
puts response.body
|
|
128
127
|
puts response.headers
|
|
129
|
-
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
require 'sendgrid-ruby'
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
|
|
5
4
|
|
|
6
|
-
|
|
7
5
|
##################################################
|
|
8
6
|
# Retrieve Tracking Settings #
|
|
9
7
|
# GET /tracking_settings #
|
|
@@ -30,7 +28,7 @@ puts response.headers
|
|
|
30
28
|
# Retrieve Click Track Settings #
|
|
31
29
|
# GET /tracking_settings/click #
|
|
32
30
|
|
|
33
|
-
response = sg.client.tracking_settings.click.get
|
|
31
|
+
response = sg.client.tracking_settings.click.get
|
|
34
32
|
puts response.status_code
|
|
35
33
|
puts response.body
|
|
36
34
|
puts response.headers
|
|
@@ -40,11 +38,11 @@ puts response.headers
|
|
|
40
38
|
# PATCH /tracking_settings/google_analytics #
|
|
41
39
|
|
|
42
40
|
data = JSON.parse('{
|
|
43
|
-
"enabled": true,
|
|
44
|
-
"utm_campaign": "website",
|
|
45
|
-
"utm_content": "",
|
|
46
|
-
"utm_medium": "email",
|
|
47
|
-
"utm_source": "sendgrid.com",
|
|
41
|
+
"enabled": true,
|
|
42
|
+
"utm_campaign": "website",
|
|
43
|
+
"utm_content": "",
|
|
44
|
+
"utm_medium": "email",
|
|
45
|
+
"utm_source": "sendgrid.com",
|
|
48
46
|
"utm_term": ""
|
|
49
47
|
}')
|
|
50
48
|
response = sg.client.tracking_settings.google_analytics.patch(request_body: data)
|
|
@@ -56,7 +54,7 @@ puts response.headers
|
|
|
56
54
|
# Retrieve Google Analytics Settings #
|
|
57
55
|
# GET /tracking_settings/google_analytics #
|
|
58
56
|
|
|
59
|
-
response = sg.client.tracking_settings.google_analytics.get
|
|
57
|
+
response = sg.client.tracking_settings.google_analytics.get
|
|
60
58
|
puts response.status_code
|
|
61
59
|
puts response.body
|
|
62
60
|
puts response.headers
|
|
@@ -77,7 +75,7 @@ puts response.headers
|
|
|
77
75
|
# Get Open Tracking Settings #
|
|
78
76
|
# GET /tracking_settings/open #
|
|
79
77
|
|
|
80
|
-
response = sg.client.tracking_settings.open.get
|
|
78
|
+
response = sg.client.tracking_settings.open.get
|
|
81
79
|
puts response.status_code
|
|
82
80
|
puts response.body
|
|
83
81
|
puts response.headers
|
|
@@ -87,11 +85,11 @@ puts response.headers
|
|
|
87
85
|
# PATCH /tracking_settings/subscription #
|
|
88
86
|
|
|
89
87
|
data = JSON.parse('{
|
|
90
|
-
"enabled": true,
|
|
91
|
-
"html_content": "html content",
|
|
92
|
-
"landing": "landing page html",
|
|
93
|
-
"plain_content": "text content",
|
|
94
|
-
"replace": "replacement tag",
|
|
88
|
+
"enabled": true,
|
|
89
|
+
"html_content": "html content",
|
|
90
|
+
"landing": "landing page html",
|
|
91
|
+
"plain_content": "text content",
|
|
92
|
+
"replace": "replacement tag",
|
|
95
93
|
"url": "url"
|
|
96
94
|
}')
|
|
97
95
|
response = sg.client.tracking_settings.subscription.patch(request_body: data)
|
|
@@ -103,8 +101,7 @@ puts response.headers
|
|
|
103
101
|
# Retrieve Subscription Tracking Settings #
|
|
104
102
|
# GET /tracking_settings/subscription #
|
|
105
103
|
|
|
106
|
-
response = sg.client.tracking_settings.subscription.get
|
|
104
|
+
response = sg.client.tracking_settings.subscription.get
|
|
107
105
|
puts response.status_code
|
|
108
106
|
puts response.body
|
|
109
107
|
puts response.headers
|
|
110
|
-
|
data/examples/user/user.rb
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
require 'sendgrid-ruby'
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
|
|
5
4
|
|
|
6
|
-
|
|
7
5
|
##################################################
|
|
8
6
|
# Get a user's account information. #
|
|
9
7
|
# GET /user/account #
|
|
10
8
|
|
|
11
|
-
response = sg.client.user.account.get
|
|
9
|
+
response = sg.client.user.account.get
|
|
12
10
|
puts response.status_code
|
|
13
11
|
puts response.body
|
|
14
12
|
puts response.headers
|
|
@@ -17,7 +15,7 @@ puts response.headers
|
|
|
17
15
|
# Retrieve your credit balance #
|
|
18
16
|
# GET /user/credits #
|
|
19
17
|
|
|
20
|
-
response = sg.client.user.credits.get
|
|
18
|
+
response = sg.client.user.credits.get
|
|
21
19
|
puts response.status_code
|
|
22
20
|
puts response.body
|
|
23
21
|
puts response.headers
|
|
@@ -38,7 +36,7 @@ puts response.headers
|
|
|
38
36
|
# Retrieve your account email address #
|
|
39
37
|
# GET /user/email #
|
|
40
38
|
|
|
41
|
-
response = sg.client.user.email.get
|
|
39
|
+
response = sg.client.user.email.get
|
|
42
40
|
puts response.status_code
|
|
43
41
|
puts response.body
|
|
44
42
|
puts response.headers
|
|
@@ -48,7 +46,7 @@ puts response.headers
|
|
|
48
46
|
# PUT /user/password #
|
|
49
47
|
|
|
50
48
|
data = JSON.parse('{
|
|
51
|
-
"new_password": "new_password",
|
|
49
|
+
"new_password": "new_password",
|
|
52
50
|
"old_password": "old_password"
|
|
53
51
|
}')
|
|
54
52
|
response = sg.client.user.password.put(request_body: data)
|
|
@@ -61,8 +59,8 @@ puts response.headers
|
|
|
61
59
|
# PATCH /user/profile #
|
|
62
60
|
|
|
63
61
|
data = JSON.parse('{
|
|
64
|
-
"city": "Orange",
|
|
65
|
-
"first_name": "Example",
|
|
62
|
+
"city": "Orange",
|
|
63
|
+
"first_name": "Example",
|
|
66
64
|
"last_name": "User"
|
|
67
65
|
}')
|
|
68
66
|
response = sg.client.user.profile.patch(request_body: data)
|
|
@@ -74,7 +72,7 @@ puts response.headers
|
|
|
74
72
|
# Get a user's profile #
|
|
75
73
|
# GET /user/profile #
|
|
76
74
|
|
|
77
|
-
response = sg.client.user.profile.get
|
|
75
|
+
response = sg.client.user.profile.get
|
|
78
76
|
puts response.status_code
|
|
79
77
|
puts response.body
|
|
80
78
|
puts response.headers
|
|
@@ -84,7 +82,7 @@ puts response.headers
|
|
|
84
82
|
# POST /user/scheduled_sends #
|
|
85
83
|
|
|
86
84
|
data = JSON.parse('{
|
|
87
|
-
"batch_id": "YOUR_BATCH_ID",
|
|
85
|
+
"batch_id": "YOUR_BATCH_ID",
|
|
88
86
|
"status": "pause"
|
|
89
87
|
}')
|
|
90
88
|
response = sg.client.user.scheduled_sends.post(request_body: data)
|
|
@@ -96,7 +94,7 @@ puts response.headers
|
|
|
96
94
|
# Retrieve all scheduled sends #
|
|
97
95
|
# GET /user/scheduled_sends #
|
|
98
96
|
|
|
99
|
-
response = sg.client.user.scheduled_sends.get
|
|
97
|
+
response = sg.client.user.scheduled_sends.get
|
|
100
98
|
puts response.status_code
|
|
101
99
|
puts response.body
|
|
102
100
|
puts response.headers
|
|
@@ -108,7 +106,7 @@ puts response.headers
|
|
|
108
106
|
data = JSON.parse('{
|
|
109
107
|
"status": "pause"
|
|
110
108
|
}')
|
|
111
|
-
batch_id =
|
|
109
|
+
batch_id = 'test_url_param'
|
|
112
110
|
response = sg.client.user.scheduled_sends._(batch_id).patch(request_body: data)
|
|
113
111
|
puts response.status_code
|
|
114
112
|
puts response.body
|
|
@@ -118,8 +116,8 @@ puts response.headers
|
|
|
118
116
|
# Retrieve scheduled send #
|
|
119
117
|
# GET /user/scheduled_sends/{batch_id} #
|
|
120
118
|
|
|
121
|
-
batch_id =
|
|
122
|
-
response = sg.client.user.scheduled_sends._(batch_id).get
|
|
119
|
+
batch_id = 'test_url_param'
|
|
120
|
+
response = sg.client.user.scheduled_sends._(batch_id).get
|
|
123
121
|
puts response.status_code
|
|
124
122
|
puts response.body
|
|
125
123
|
puts response.headers
|
|
@@ -128,8 +126,8 @@ puts response.headers
|
|
|
128
126
|
# Delete a cancellation or pause of a scheduled send #
|
|
129
127
|
# DELETE /user/scheduled_sends/{batch_id} #
|
|
130
128
|
|
|
131
|
-
batch_id =
|
|
132
|
-
response = sg.client.user.scheduled_sends._(batch_id).delete
|
|
129
|
+
batch_id = 'test_url_param'
|
|
130
|
+
response = sg.client.user.scheduled_sends._(batch_id).delete
|
|
133
131
|
puts response.status_code
|
|
134
132
|
puts response.body
|
|
135
133
|
puts response.headers
|
|
@@ -139,7 +137,7 @@ puts response.headers
|
|
|
139
137
|
# PATCH /user/settings/enforced_tls #
|
|
140
138
|
|
|
141
139
|
data = JSON.parse('{
|
|
142
|
-
"require_tls": true,
|
|
140
|
+
"require_tls": true,
|
|
143
141
|
"require_valid_cert": false
|
|
144
142
|
}')
|
|
145
143
|
response = sg.client.user.settings.enforced_tls.patch(request_body: data)
|
|
@@ -151,7 +149,7 @@ puts response.headers
|
|
|
151
149
|
# Retrieve current Enforced TLS settings. #
|
|
152
150
|
# GET /user/settings/enforced_tls #
|
|
153
151
|
|
|
154
|
-
response = sg.client.user.settings.enforced_tls.get
|
|
152
|
+
response = sg.client.user.settings.enforced_tls.get
|
|
155
153
|
puts response.status_code
|
|
156
154
|
puts response.body
|
|
157
155
|
puts response.headers
|
|
@@ -172,7 +170,7 @@ puts response.headers
|
|
|
172
170
|
# Retrieve your username #
|
|
173
171
|
# GET /user/username #
|
|
174
172
|
|
|
175
|
-
response = sg.client.user.username.get
|
|
173
|
+
response = sg.client.user.username.get
|
|
176
174
|
puts response.status_code
|
|
177
175
|
puts response.body
|
|
178
176
|
puts response.headers
|
|
@@ -182,18 +180,18 @@ puts response.headers
|
|
|
182
180
|
# PATCH /user/webhooks/event/settings #
|
|
183
181
|
|
|
184
182
|
data = JSON.parse('{
|
|
185
|
-
"bounce": true,
|
|
186
|
-
"click": true,
|
|
187
|
-
"deferred": true,
|
|
188
|
-
"delivered": true,
|
|
189
|
-
"dropped": true,
|
|
190
|
-
"enabled": true,
|
|
191
|
-
"group_resubscribe": true,
|
|
192
|
-
"group_unsubscribe": true,
|
|
193
|
-
"open": true,
|
|
194
|
-
"processed": true,
|
|
195
|
-
"spam_report": true,
|
|
196
|
-
"unsubscribe": true,
|
|
183
|
+
"bounce": true,
|
|
184
|
+
"click": true,
|
|
185
|
+
"deferred": true,
|
|
186
|
+
"delivered": true,
|
|
187
|
+
"dropped": true,
|
|
188
|
+
"enabled": true,
|
|
189
|
+
"group_resubscribe": true,
|
|
190
|
+
"group_unsubscribe": true,
|
|
191
|
+
"open": true,
|
|
192
|
+
"processed": true,
|
|
193
|
+
"spam_report": true,
|
|
194
|
+
"unsubscribe": true,
|
|
197
195
|
"url": "url"
|
|
198
196
|
}')
|
|
199
197
|
response = sg.client.user.webhooks.event.settings.patch(request_body: data)
|
|
@@ -205,7 +203,7 @@ puts response.headers
|
|
|
205
203
|
# Retrieve Event Webhook settings #
|
|
206
204
|
# GET /user/webhooks/event/settings #
|
|
207
205
|
|
|
208
|
-
response = sg.client.user.webhooks.event.settings.get
|
|
206
|
+
response = sg.client.user.webhooks.event.settings.get
|
|
209
207
|
puts response.status_code
|
|
210
208
|
puts response.body
|
|
211
209
|
puts response.headers
|
|
@@ -227,9 +225,9 @@ puts response.headers
|
|
|
227
225
|
# POST /user/webhooks/parse/settings #
|
|
228
226
|
|
|
229
227
|
data = JSON.parse('{
|
|
230
|
-
"hostname": "myhostname.com",
|
|
231
|
-
"send_raw": false,
|
|
232
|
-
"spam_check": true,
|
|
228
|
+
"hostname": "myhostname.com",
|
|
229
|
+
"send_raw": false,
|
|
230
|
+
"spam_check": true,
|
|
233
231
|
"url": "http://email.myhosthame.com"
|
|
234
232
|
}')
|
|
235
233
|
response = sg.client.user.webhooks.parse.settings.post(request_body: data)
|
|
@@ -241,7 +239,7 @@ puts response.headers
|
|
|
241
239
|
# Retrieve all parse settings #
|
|
242
240
|
# GET /user/webhooks/parse/settings #
|
|
243
241
|
|
|
244
|
-
response = sg.client.user.webhooks.parse.settings.get
|
|
242
|
+
response = sg.client.user.webhooks.parse.settings.get
|
|
245
243
|
puts response.status_code
|
|
246
244
|
puts response.body
|
|
247
245
|
puts response.headers
|
|
@@ -251,11 +249,11 @@ puts response.headers
|
|
|
251
249
|
# PATCH /user/webhooks/parse/settings/{hostname} #
|
|
252
250
|
|
|
253
251
|
data = JSON.parse('{
|
|
254
|
-
"send_raw": true,
|
|
255
|
-
"spam_check": false,
|
|
252
|
+
"send_raw": true,
|
|
253
|
+
"spam_check": false,
|
|
256
254
|
"url": "http://newdomain.com/parse"
|
|
257
255
|
}')
|
|
258
|
-
hostname =
|
|
256
|
+
hostname = 'test_url_param'
|
|
259
257
|
response = sg.client.user.webhooks.parse.settings._(hostname).patch(request_body: data)
|
|
260
258
|
puts response.status_code
|
|
261
259
|
puts response.body
|
|
@@ -265,8 +263,8 @@ puts response.headers
|
|
|
265
263
|
# Retrieve a specific parse setting #
|
|
266
264
|
# GET /user/webhooks/parse/settings/{hostname} #
|
|
267
265
|
|
|
268
|
-
hostname =
|
|
269
|
-
response = sg.client.user.webhooks.parse.settings._(hostname).get
|
|
266
|
+
hostname = 'test_url_param'
|
|
267
|
+
response = sg.client.user.webhooks.parse.settings._(hostname).get
|
|
270
268
|
puts response.status_code
|
|
271
269
|
puts response.body
|
|
272
270
|
puts response.headers
|
|
@@ -275,8 +273,8 @@ puts response.headers
|
|
|
275
273
|
# Delete a parse setting #
|
|
276
274
|
# DELETE /user/webhooks/parse/settings/{hostname} #
|
|
277
275
|
|
|
278
|
-
hostname =
|
|
279
|
-
response = sg.client.user.webhooks.parse.settings._(hostname).delete
|
|
276
|
+
hostname = 'test_url_param'
|
|
277
|
+
response = sg.client.user.webhooks.parse.settings._(hostname).delete
|
|
280
278
|
puts response.status_code
|
|
281
279
|
puts response.body
|
|
282
280
|
puts response.headers
|
|
@@ -290,4 +288,3 @@ response = sg.client.user.webhooks.parse.stats.get(query_params: params)
|
|
|
290
288
|
puts response.status_code
|
|
291
289
|
puts response.body
|
|
292
290
|
puts response.headers
|
|
293
|
-
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
# Middleware that verifies webhooks from SendGrid using the EventWebhook
|
|
5
|
+
# verifier.
|
|
6
|
+
#
|
|
7
|
+
# The middleware takes a public key with which to set up the request
|
|
8
|
+
# validator and any number of paths. When a path matches the incoming request
|
|
9
|
+
# path, the request will be verified using the signature and timestamp of the
|
|
10
|
+
# request.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
#
|
|
14
|
+
# require 'rack'
|
|
15
|
+
# use Rack::SendGridWebhookVerification, ENV['PUBLIC_KEY'], /\/emails/
|
|
16
|
+
#
|
|
17
|
+
# The above appends this middleware to the stack, using a public key saved in
|
|
18
|
+
# the ENV and only against paths that match /\/emails/. If the request
|
|
19
|
+
# validates then it gets passed on to the action as normal. If the request
|
|
20
|
+
# doesn't validate then the middleware responds immediately with a 403 status.
|
|
21
|
+
class SendGridWebhookVerification
|
|
22
|
+
def initialize(app, public_key, *paths)
|
|
23
|
+
@app = app
|
|
24
|
+
@public_key = public_key
|
|
25
|
+
@path_regex = Regexp.union(paths)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def call(env)
|
|
29
|
+
return @app.call(env) unless env['PATH_INFO'].match(@path_regex)
|
|
30
|
+
|
|
31
|
+
request = Rack::Request.new(env)
|
|
32
|
+
|
|
33
|
+
event_webhook = SendGrid::EventWebhook.new
|
|
34
|
+
ec_public_key = event_webhook.convert_public_key_to_ecdsa(@public_key)
|
|
35
|
+
verified = event_webhook.verify_signature(
|
|
36
|
+
ec_public_key,
|
|
37
|
+
request.body.read,
|
|
38
|
+
request.env[SendGrid::EventWebhookHeader::SIGNATURE],
|
|
39
|
+
request.env[SendGrid::EventWebhookHeader::TIMESTAMP]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
request.body.rewind
|
|
43
|
+
|
|
44
|
+
if verified
|
|
45
|
+
@app.call(env)
|
|
46
|
+
else
|
|
47
|
+
[
|
|
48
|
+
403,
|
|
49
|
+
{ 'Content-Type' => 'text/plain' },
|
|
50
|
+
['SendGrid Request Verification Failed.']
|
|
51
|
+
]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -4,7 +4,8 @@ require_relative 'version'
|
|
|
4
4
|
# Initialize the HTTP client
|
|
5
5
|
class BaseInterface
|
|
6
6
|
attr_accessor :client
|
|
7
|
-
attr_reader :request_headers, :host, :version, :impersonate_subuser
|
|
7
|
+
attr_reader :request_headers, :host, :version, :impersonate_subuser, :http_options
|
|
8
|
+
|
|
8
9
|
# * *Args* :
|
|
9
10
|
# - +auth+ -> authorization header value
|
|
10
11
|
# - +host+ -> the base URL for the API
|
|
@@ -13,11 +14,12 @@ class BaseInterface
|
|
|
13
14
|
# currently only "v3" is supported
|
|
14
15
|
# - +impersonate_subuser+ -> the subuser to impersonate, will be passed
|
|
15
16
|
# in the "On-Behalf-Of" header
|
|
17
|
+
# - +http_options+ -> http options that you want to be globally applied to each request
|
|
16
18
|
#
|
|
17
|
-
def initialize(auth:, host:, request_headers: nil, version: nil, impersonate_subuser: nil)
|
|
19
|
+
def initialize(auth:, host:, request_headers: nil, version: nil, impersonate_subuser: nil, http_options: {})
|
|
18
20
|
@auth = auth
|
|
19
21
|
@host = host
|
|
20
|
-
@version = version
|
|
22
|
+
@version = version || 'v3'
|
|
21
23
|
@impersonate_subuser = impersonate_subuser
|
|
22
24
|
@user_agent = "sendgrid/#{SendGrid::VERSION};ruby"
|
|
23
25
|
@request_headers = JSON.parse('
|
|
@@ -30,7 +32,9 @@ class BaseInterface
|
|
|
30
32
|
@request_headers['On-Behalf-Of'] = @impersonate_subuser if @impersonate_subuser
|
|
31
33
|
|
|
32
34
|
@request_headers = @request_headers.merge(request_headers) if request_headers
|
|
35
|
+
@http_options = http_options
|
|
33
36
|
@client = SendGrid::Client.new(host: "#{@host}/#{@version}",
|
|
34
|
-
request_headers: @request_headers
|
|
37
|
+
request_headers: @request_headers,
|
|
38
|
+
http_options: @http_options)
|
|
35
39
|
end
|
|
36
40
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'digest'
|
|
3
|
+
require 'openssl'
|
|
4
|
+
|
|
5
|
+
module SendGrid
|
|
6
|
+
# This class allows you to use the Event Webhook feature. Read the docs for
|
|
7
|
+
# more details: https://sendgrid.com/docs/for-developers/tracking-events/event
|
|
8
|
+
class EventWebhook
|
|
9
|
+
# * *Args* :
|
|
10
|
+
# - +public_key+ -> verification key under Mail Settings
|
|
11
|
+
#
|
|
12
|
+
def convert_public_key_to_ecdsa(public_key)
|
|
13
|
+
verify_engine
|
|
14
|
+
OpenSSL::PKey::EC.new(Base64.decode64(public_key))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# * *Args* :
|
|
18
|
+
# - +public_key+ -> elliptic curve public key
|
|
19
|
+
# - +payload+ -> event payload in the request body
|
|
20
|
+
# - +signature+ -> signature value obtained from the 'X-Twilio-Email-Event-Webhook-Signature' header
|
|
21
|
+
# - +timestamp+ -> timestamp value obtained from the 'X-Twilio-Email-Event-Webhook-Timestamp' header
|
|
22
|
+
def verify_signature(public_key, payload, signature, timestamp)
|
|
23
|
+
verify_engine
|
|
24
|
+
timestamped_playload = "#{timestamp}#{payload}"
|
|
25
|
+
payload_digest = Digest::SHA256.digest(timestamped_playload)
|
|
26
|
+
decoded_signature = Base64.decode64(signature)
|
|
27
|
+
public_key.dsa_verify_asn1(payload_digest, decoded_signature)
|
|
28
|
+
rescue StandardError
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def verify_engine
|
|
33
|
+
# JRuby does not fully support ECDSA: https://github.com/jruby/jruby-openssl/issues/193
|
|
34
|
+
raise NotSupportedError, "Event Webhook verification is not supported by JRuby" if RUBY_PLATFORM == "java"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Error < ::RuntimeError
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class NotSupportedError < Error
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# This class lists headers that get posted to the webhook. Read the docs for
|
|
45
|
+
# more details: https://sendgrid.com/docs/for-developers/tracking-events/event
|
|
46
|
+
class EventWebhookHeader
|
|
47
|
+
SIGNATURE = "HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_SIGNATURE".freeze
|
|
48
|
+
TIMESTAMP = "HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_TIMESTAMP".freeze
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
# Installation
|
|
18
18
|
|
|
19
19
|
In addition to the installation instructions in
|
|
20
|
-
[the main readme](
|
|
20
|
+
[the main readme](../../../../README.md#installation),
|
|
21
21
|
you must also add sinatra to your Gemfile:
|
|
22
22
|
|
|
23
23
|
```
|
|
@@ -47,7 +47,7 @@ bundle install
|
|
|
47
47
|
ruby ./lib/sendgrid/helpers/inbound/send.rb ./lib/sendgrid/helpers/inbound/sample_data/default_data.txt
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
More sample data can be found [here](
|
|
50
|
+
More sample data can be found [here](sample_data).
|
|
51
51
|
|
|
52
52
|
View the results in the first terminal.
|
|
53
53
|
|
|
@@ -82,11 +82,11 @@ Next, send an email to [anything]@inbound.yourdomain.com, then look at the termi
|
|
|
82
82
|
|
|
83
83
|
## app.rb
|
|
84
84
|
|
|
85
|
-
This module runs a [Sinatra](http://www.sinatrarb.com/) server, that by default (you can change those settings [here](
|
|
85
|
+
This module runs a [Sinatra](http://www.sinatrarb.com/) server, that by default (you can change those settings [here](config.yml)), listens for POSTs on http://localhost:9292. When the server receives the POST, it parses and prints the key/value data.
|
|
86
86
|
|
|
87
87
|
## config.yml
|
|
88
88
|
|
|
89
|
-
This module loads application environment variables (located in [config.yml](
|
|
89
|
+
This module loads application environment variables (located in [config.yml](config.yml)).
|
|
90
90
|
|
|
91
91
|
## send.rb & /sample_data
|
|
92
92
|
|
|
@@ -95,4 +95,4 @@ This module is used to send sample test data. It is useful for testing and devel
|
|
|
95
95
|
<a name="contributing"></a>
|
|
96
96
|
# Contributing
|
|
97
97
|
|
|
98
|
-
If you would like to contribute to this project, please see our [contributing guide](
|
|
98
|
+
If you would like to contribute to this project, please see our [contributing guide](../../../../CONTRIBUTING.md). Thanks!
|
|
@@ -18,7 +18,7 @@ require 'yaml'
|
|
|
18
18
|
class Main < Sinatra::Base
|
|
19
19
|
configure :production, :development do
|
|
20
20
|
enable :logging
|
|
21
|
-
set :config, YAML.load_file(File.dirname(__FILE__)
|
|
21
|
+
set :config, YAML.load_file("#{File.dirname(__FILE__)}/config.yml")
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
get '/' do
|
|
@@ -26,7 +26,7 @@ class Main < Sinatra::Base
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
post settings.config['endpoint'] do
|
|
29
|
-
filtered = params.select {|k,
|
|
29
|
+
filtered = params.select { |k, _v| settings.config['keys'].include?(k) }
|
|
30
30
|
logger.info JSON.pretty_generate(filtered)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
<body>
|
|
6
6
|
<h1>You have successfuly launched the server!</h1>
|
|
7
7
|
|
|
8
|
-
Check out <a href="https://github.com/sendgrid/sendgrid-ruby/tree/
|
|
8
|
+
Check out <a href="https://github.com/sendgrid/sendgrid-ruby/tree/HEAD/sendgrid/helpers/inbound">the documentation</a> on how to use this software to utilize the SendGrid Inbound Parse webhook.
|
|
9
9
|
</body>
|
|
10
10
|
</html>
|
|
@@ -4,11 +4,11 @@ require 'ruby_http_client'
|
|
|
4
4
|
require 'yaml'
|
|
5
5
|
require 'optparse'
|
|
6
6
|
|
|
7
|
-
OPTS = {}
|
|
7
|
+
OPTS = {}.freeze
|
|
8
8
|
opt = OptionParser.new
|
|
9
|
-
opt.on('--host=HOST') {|v| OPTS[:host] = v}
|
|
9
|
+
opt.on('--host=HOST') { |v| OPTS[:host] = v }
|
|
10
10
|
argv = opt.parse!(ARGV)
|
|
11
|
-
config = YAML.load_file(File.dirname(__FILE__)
|
|
11
|
+
config = YAML.load_file("#{File.dirname(__FILE__)}/config.yml")
|
|
12
12
|
host = OPTS[:host] || config['host']
|
|
13
13
|
client = SendGrid::Client.new(host: host)
|
|
14
14
|
File.open(argv[0]) do |file|
|