sendgrid-ruby 6.2.0 → 6.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/config.yml +10 -0
  3. data/.github/workflows/test-and-deploy.yml +120 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +8 -0
  6. data/.rubocop_todo.yml +127 -0
  7. data/CHANGELOG.md +147 -9
  8. data/CONTRIBUTING.md +11 -21
  9. data/Dockerfile +14 -0
  10. data/FIRST_TIMERS.md +79 -0
  11. data/Gemfile +0 -1
  12. data/ISSUE_TEMPLATE.md +5 -1
  13. data/{LICENSE.md → LICENSE} +1 -1
  14. data/Makefile +9 -2
  15. data/PULL_REQUEST_TEMPLATE.md +5 -5
  16. data/README.md +23 -31
  17. data/Rakefile +2 -3
  18. data/TROUBLESHOOTING.md +17 -5
  19. data/USAGE.md +146 -39
  20. data/examples/accesssettings/accesssettings.rb +9 -12
  21. data/examples/alerts/alerts.rb +8 -11
  22. data/examples/apikeys/apikeys.rb +12 -15
  23. data/examples/asm/asm.rb +27 -30
  24. data/examples/browsers/browsers.rb +0 -3
  25. data/examples/campaigns/campaigns.rb +29 -32
  26. data/examples/categories/categories.rb +0 -3
  27. data/examples/clients/clients.rb +1 -4
  28. data/examples/contactdb/contactdb.rb +63 -66
  29. data/examples/devices/devices.rb +0 -3
  30. data/examples/emailactivity/emailactivity.rb +52 -0
  31. data/examples/geo/geo.rb +0 -3
  32. data/examples/helpers/eventwebhook/example.rb +16 -0
  33. data/examples/helpers/mail/example.rb +24 -13
  34. data/examples/helpers/settings/example.rb +1 -1
  35. data/examples/helpers/stats/example.rb +4 -4
  36. data/examples/ips/ips.rb +19 -22
  37. data/examples/mail/mail.rb +72 -75
  38. data/examples/mailboxproviders/mailboxproviders.rb +0 -3
  39. data/examples/mailsettings/mailsettings.rb +21 -24
  40. data/examples/partnersettings/partnersettings.rb +3 -6
  41. data/examples/scopes/scopes.rb +8 -10
  42. data/examples/senderauthentication/senderauthentication.rb +41 -44
  43. data/examples/senders/senders.rb +28 -31
  44. data/examples/stats/stats.rb +0 -3
  45. data/examples/subusers/subusers.rb +17 -20
  46. data/examples/suppression/suppression.rb +15 -18
  47. data/examples/templates/templates.rb +29 -31
  48. data/examples/trackingsettings/trackingsettings.rb +14 -17
  49. data/examples/user/user.rb +41 -44
  50. data/lib/rack/sendgrid_webhook_verification.rb +55 -0
  51. data/lib/sendgrid/base_interface.rb +8 -4
  52. data/lib/sendgrid/helpers/eventwebhook/eventwebhook.rb +50 -0
  53. data/lib/sendgrid/helpers/inbound/README.md +5 -5
  54. data/lib/sendgrid/helpers/inbound/app.rb +2 -2
  55. data/lib/sendgrid/helpers/inbound/public/index.html +1 -1
  56. data/lib/sendgrid/helpers/inbound/send.rb +3 -3
  57. data/lib/sendgrid/helpers/ip_management/ip_management.rb +1 -1
  58. data/lib/sendgrid/helpers/mail/README.md +3 -3
  59. data/lib/sendgrid/helpers/mail/asm.rb +6 -18
  60. data/lib/sendgrid/helpers/mail/attachment.rb +12 -42
  61. data/lib/sendgrid/helpers/mail/bcc_settings.rb +6 -18
  62. data/lib/sendgrid/helpers/mail/bypass_list_management.rb +8 -18
  63. data/lib/sendgrid/helpers/mail/category.rb +2 -2
  64. data/lib/sendgrid/helpers/mail/click_tracking.rb +6 -18
  65. data/lib/sendgrid/helpers/mail/content.rb +4 -3
  66. data/lib/sendgrid/helpers/mail/custom_arg.rb +6 -10
  67. data/lib/sendgrid/helpers/mail/email.rb +10 -5
  68. data/lib/sendgrid/helpers/mail/footer.rb +7 -27
  69. data/lib/sendgrid/helpers/mail/ganalytics.rb +10 -54
  70. data/lib/sendgrid/helpers/mail/header.rb +6 -10
  71. data/lib/sendgrid/helpers/mail/mail.rb +32 -48
  72. data/lib/sendgrid/helpers/mail/mail_settings.rb +9 -25
  73. data/lib/sendgrid/helpers/mail/open_tracking.rb +6 -18
  74. data/lib/sendgrid/helpers/mail/personalization.rb +40 -27
  75. data/lib/sendgrid/helpers/mail/section.rb +6 -10
  76. data/lib/sendgrid/helpers/mail/spam_check.rb +7 -27
  77. data/lib/sendgrid/helpers/mail/subscription_tracking.rb +8 -36
  78. data/lib/sendgrid/helpers/mail/substitution.rb +6 -10
  79. data/lib/sendgrid/helpers/mail/tracking_settings.rb +8 -20
  80. data/lib/sendgrid/helpers/permissions/scope.rb +2 -2
  81. data/lib/sendgrid/helpers/settings/README.md +2 -2
  82. data/lib/sendgrid/helpers/settings/settings.rb +1 -1
  83. data/lib/sendgrid/helpers/settings/tracking_settings_dto.rb +3 -5
  84. data/lib/sendgrid/helpers/stats/metrics.rb +5 -5
  85. data/lib/sendgrid/sendgrid.rb +4 -3
  86. data/lib/sendgrid/twilio_email.rb +1 -1
  87. data/lib/sendgrid/version.rb +1 -1
  88. data/lib/sendgrid-ruby.rb +2 -0
  89. data/mail_helper_v3.md +12 -12
  90. data/sendgrid-ruby.gemspec +8 -8
  91. data/spec/fixtures/event_webhook.rb +22 -0
  92. data/spec/rack/sendgrid_webhook_verification_spec.rb +142 -0
  93. data/spec/sendgrid/helpers/eventwebhook/eventwebhook_spec.rb +105 -0
  94. data/spec/sendgrid/helpers/settings/mail_settings_dto_spec.rb +3 -3
  95. data/spec/sendgrid/helpers/settings/partner_settings_dto_spec.rb +3 -3
  96. data/spec/sendgrid/helpers/settings/settings_spec.rb +2 -2
  97. data/spec/sendgrid/helpers/settings/tracking_settings_dto_spec.rb +3 -3
  98. data/spec/sendgrid/helpers/settings/user_settings_dto_spec.rb +3 -3
  99. data/spec/sendgrid/helpers/stats/email_stats_spec.rb +22 -23
  100. data/spec/sendgrid/helpers/stats/metrics_spec.rb +19 -20
  101. data/spec/sendgrid/helpers/stats/stats_response_spec.rb +22 -23
  102. data/spec/spec_helper.rb +3 -1
  103. data/static/img/github-fork.png +0 -0
  104. data/static/img/github-sign-up.png +0 -0
  105. data/test/sendgrid/helpers/mail/test_attachment.rb +4 -6
  106. data/test/sendgrid/helpers/mail/test_category.rb +0 -2
  107. data/test/sendgrid/helpers/mail/test_email.rb +17 -10
  108. data/test/sendgrid/helpers/mail/test_mail.rb +101 -102
  109. data/test/sendgrid/helpers/mail/test_personalizations.rb +145 -92
  110. data/test/sendgrid/permissions/test_scopes.rb +1 -3
  111. data/test/sendgrid/test_sendgrid-ruby.rb +1964 -1986
  112. data/twilio_sendgrid_logo.png +0 -0
  113. data/use-cases/README.md +17 -0
  114. data/use-cases/domain-authentication.md +5 -0
  115. data/use-cases/email-statistics.md +52 -0
  116. data/use-cases/legacy-templates.md +98 -0
  117. data/use-cases/personalizations.md +34 -0
  118. data/use-cases/sms.md +39 -0
  119. data/use-cases/transactional-templates.md +111 -0
  120. data/use-cases/twilio-email.md +13 -0
  121. data/use-cases/twilio-setup.md +54 -0
  122. metadata +69 -34
  123. data/.codeclimate.yml +0 -21
  124. data/.travis.yml +0 -40
  125. data/USE_CASES.md +0 -405
  126. data/docker/Dockerfile +0 -12
  127. data/docker/README.md +0 -30
  128. 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
- response = sg.client.templates.get()
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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
91
- version_id = "test_url_param"
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 = "test_url_param"
102
- version_id = "test_url_param"
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 = "test_url_param"
113
- version_id = "test_url_param"
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 = "test_url_param"
124
- version_id = "test_url_param"
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
-
@@ -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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
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 = "test_url_param"
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 ? version : 'v3'
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](https://github.com/sendgrid/sendgrid-ruby/tree/master/#installation),
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](https://github.com/sendgrid/sendgrid-ruby/tree/master/lib/sendgrid/helpers/inbound/sample_data).
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](https://github.com/sendgrid/sendgrid-ruby/blob/master/sendgrid/helpers/inbound/config.yml)), listens for POSTs on http://localhost:9292. When the server receives the POST, it parses and prints the key/value data.
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](https://github.com/sendgrid/sendgrid-ruby/blob/master/sendgrid/helpers/inbound/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](https://github.com/sendgrid/sendgrid-ruby/blob/master/CONTRIBUTING.md). Thanks!
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__) + '/config.yml')
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, v| settings.config['keys'].include?(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/master/sendgrid/helpers/inbound">the documentation</a> on how to use this software to utilize the SendGrid Inbound Parse webhook.
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__) + '/config.yml')
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|