sendgrid-ruby 1.1.6 → 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.
Files changed (160) hide show
  1. checksums.yaml +5 -5
  2. data/.env_sample +1 -3
  3. data/.github/ISSUE_TEMPLATE/config.yml +10 -0
  4. data/.github/workflows/test-and-deploy.yml +120 -0
  5. data/.gitignore +3 -0
  6. data/.rubocop.yml +5 -27
  7. data/.rubocop_todo.yml +127 -0
  8. data/CHANGELOG.md +417 -1
  9. data/CODE_OF_CONDUCT.md +73 -0
  10. data/CONTRIBUTING.md +202 -0
  11. data/Dockerfile +14 -0
  12. data/FIRST_TIMERS.md +79 -0
  13. data/Gemfile +4 -4
  14. data/ISSUE_TEMPLATE.md +30 -0
  15. data/LICENSE +21 -0
  16. data/Makefile +14 -0
  17. data/PULL_REQUEST_TEMPLATE.md +31 -0
  18. data/README.md +153 -229
  19. data/Rakefile +9 -3
  20. data/TROUBLESHOOTING.md +151 -0
  21. data/UPGRADE.md +5 -0
  22. data/USAGE.md +5144 -0
  23. data/config.ru +4 -0
  24. data/examples/accesssettings/accesssettings.rb +80 -0
  25. data/examples/alerts/alerts.rb +59 -0
  26. data/examples/apikeys/apikeys.rb +81 -0
  27. data/examples/asm/asm.rb +170 -0
  28. data/examples/browsers/browsers.rb +13 -0
  29. data/examples/campaigns/campaigns.rb +150 -0
  30. data/examples/categories/categories.rb +33 -0
  31. data/examples/clients/clients.rb +24 -0
  32. data/examples/contactdb/contactdb.rb +392 -0
  33. data/examples/devices/devices.rb +13 -0
  34. data/examples/emailactivity/emailactivity.rb +52 -0
  35. data/examples/geo/geo.rb +13 -0
  36. data/examples/helpers/eventwebhook/example.rb +16 -0
  37. data/examples/helpers/mail/example.rb +158 -0
  38. data/examples/helpers/settings/example.rb +23 -0
  39. data/examples/helpers/stats/example.rb +42 -0
  40. data/examples/ips/ips.rb +164 -0
  41. data/examples/mail/mail.rb +170 -0
  42. data/examples/mailboxproviders/mailboxproviders.rb +13 -0
  43. data/examples/mailsettings/mailsettings.rb +216 -0
  44. data/examples/partnersettings/partnersettings.rb +36 -0
  45. data/examples/scopes/scopes.rb +59 -0
  46. data/examples/senderauthentication/senderauthentication.rb +307 -0
  47. data/examples/senders/senders.rb +95 -0
  48. data/examples/stats/stats.rb +13 -0
  49. data/examples/subusers/subusers.rb +166 -0
  50. data/examples/suppression/suppression.rb +198 -0
  51. data/examples/templates/templates.rb +127 -0
  52. data/examples/trackingsettings/trackingsettings.rb +107 -0
  53. data/examples/user/user.rb +290 -0
  54. data/gemfiles/Sinatra_1.gemfile +6 -0
  55. data/gemfiles/Sinatra_2.gemfile +6 -0
  56. data/lib/rack/sendgrid_webhook_verification.rb +55 -0
  57. data/lib/sendgrid/base_interface.rb +40 -0
  58. data/lib/sendgrid/helpers/eventwebhook/eventwebhook.rb +50 -0
  59. data/lib/sendgrid/helpers/inbound/README.md +98 -0
  60. data/lib/sendgrid/helpers/inbound/app.rb +32 -0
  61. data/lib/sendgrid/helpers/inbound/config.yml +26 -0
  62. data/lib/sendgrid/helpers/inbound/public/index.html +10 -0
  63. data/lib/sendgrid/helpers/inbound/sample_data/default_data.txt +58 -0
  64. data/lib/sendgrid/helpers/inbound/sample_data/raw_data.txt +57 -0
  65. data/lib/sendgrid/helpers/inbound/sample_data/raw_data_with_attachments.txt +298 -0
  66. data/lib/sendgrid/helpers/inbound/send.rb +26 -0
  67. data/lib/sendgrid/helpers/ip_management/ip_management.rb +17 -0
  68. data/lib/sendgrid/helpers/mail/README.md +14 -0
  69. data/lib/sendgrid/helpers/mail/asm.rb +19 -0
  70. data/lib/sendgrid/helpers/mail/attachment.rb +55 -0
  71. data/lib/sendgrid/helpers/mail/bcc_settings.rb +19 -0
  72. data/lib/sendgrid/helpers/mail/bypass_list_management.rb +31 -0
  73. data/lib/sendgrid/helpers/mail/category.rb +18 -0
  74. data/lib/sendgrid/helpers/mail/click_tracking.rb +19 -0
  75. data/lib/sendgrid/helpers/mail/content.rb +19 -0
  76. data/lib/sendgrid/helpers/mail/custom_arg.rb +18 -0
  77. data/lib/sendgrid/helpers/mail/email.rb +32 -0
  78. data/lib/sendgrid/helpers/mail/footer.rb +21 -0
  79. data/lib/sendgrid/helpers/mail/ganalytics.rb +28 -0
  80. data/lib/sendgrid/helpers/mail/header.rb +18 -0
  81. data/lib/sendgrid/helpers/mail/mail.rb +122 -0
  82. data/lib/sendgrid/helpers/mail/mail_settings.rb +45 -0
  83. data/lib/sendgrid/helpers/mail/open_tracking.rb +19 -0
  84. data/lib/sendgrid/helpers/mail/personalization.rb +93 -0
  85. data/lib/sendgrid/helpers/mail/section.rb +18 -0
  86. data/lib/sendgrid/helpers/mail/spam_check.rb +21 -0
  87. data/lib/sendgrid/helpers/mail/subscription_tracking.rb +23 -0
  88. data/lib/sendgrid/helpers/mail/substitution.rb +18 -0
  89. data/lib/sendgrid/helpers/mail/tracking_settings.rb +39 -0
  90. data/lib/sendgrid/helpers/permissions/scope.rb +28 -0
  91. data/lib/sendgrid/helpers/permissions/scopes.yml +309 -0
  92. data/lib/sendgrid/helpers/settings/README.md +14 -0
  93. data/lib/sendgrid/helpers/settings/mail_settings_dto.rb +13 -0
  94. data/lib/sendgrid/helpers/settings/partner_settings_dto.rb +13 -0
  95. data/lib/sendgrid/helpers/settings/settings.rb +28 -0
  96. data/lib/sendgrid/helpers/settings/tracking_settings_dto.rb +22 -0
  97. data/lib/sendgrid/helpers/settings/user_settings_dto.rb +13 -0
  98. data/lib/sendgrid/helpers/stats/email_stats.rb +46 -0
  99. data/lib/sendgrid/helpers/stats/metrics.rb +33 -0
  100. data/lib/sendgrid/helpers/stats/stats_response.rb +29 -0
  101. data/lib/sendgrid/sendgrid.rb +21 -0
  102. data/lib/sendgrid/twilio_email.rb +21 -0
  103. data/lib/sendgrid/version.rb +1 -1
  104. data/lib/sendgrid-ruby.rb +32 -7
  105. data/mail_helper_v3.md +390 -0
  106. data/sendgrid-ruby.gemspec +16 -20
  107. data/spec/fixtures/event_webhook.rb +22 -0
  108. data/spec/rack/sendgrid_webhook_verification_spec.rb +142 -0
  109. data/spec/sendgrid/helpers/eventwebhook/eventwebhook_spec.rb +105 -0
  110. data/spec/sendgrid/helpers/ip_management/ip_management_spec.rb +12 -0
  111. data/spec/sendgrid/helpers/settings/mail_settings_dto_spec.rb +32 -0
  112. data/spec/sendgrid/helpers/settings/partner_settings_dto_spec.rb +24 -0
  113. data/spec/sendgrid/helpers/settings/settings_spec.rb +25 -0
  114. data/spec/sendgrid/helpers/settings/tracking_settings_dto_spec.rb +27 -0
  115. data/spec/sendgrid/helpers/settings/user_settings_dto_spec.rb +24 -0
  116. data/spec/sendgrid/helpers/stats/email_stats_spec.rb +111 -0
  117. data/spec/sendgrid/helpers/stats/metrics_spec.rb +45 -0
  118. data/spec/sendgrid/helpers/stats/stats_response_spec.rb +75 -0
  119. data/spec/sendgrid/sendgrid_spec.rb +11 -0
  120. data/spec/sendgrid/twilio_email_spec.rb +11 -0
  121. data/spec/spec_helper.rb +12 -1
  122. data/static/img/github-fork.png +0 -0
  123. data/static/img/github-sign-up.png +0 -0
  124. data/test/sendgrid/helpers/mail/test_attachment.rb +33 -0
  125. data/test/sendgrid/helpers/mail/test_category.rb +25 -0
  126. data/test/sendgrid/helpers/mail/test_email.rb +41 -0
  127. data/test/sendgrid/helpers/mail/test_mail.rb +260 -0
  128. data/test/sendgrid/helpers/mail/test_personalizations.rb +214 -0
  129. data/test/sendgrid/permissions/test_scopes.rb +36 -0
  130. data/test/sendgrid/test_sendgrid-ruby.rb +2729 -0
  131. data/twilio_sendgrid_logo.png +0 -0
  132. data/use-cases/README.md +17 -0
  133. data/use-cases/domain-authentication.md +5 -0
  134. data/use-cases/email-statistics.md +52 -0
  135. data/use-cases/legacy-templates.md +98 -0
  136. data/use-cases/personalizations.md +34 -0
  137. data/use-cases/sms.md +39 -0
  138. data/use-cases/transactional-templates.md +111 -0
  139. data/use-cases/twilio-email.md +13 -0
  140. data/use-cases/twilio-setup.md +54 -0
  141. metadata +187 -112
  142. data/.rspec +0 -2
  143. data/.travis.yml +0 -20
  144. data/FETCH_HEAD +0 -0
  145. data/Guardfile +0 -10
  146. data/LICENSE.txt +0 -22
  147. data/example.rb +0 -41
  148. data/lib/sendgrid/client.rb +0 -62
  149. data/lib/sendgrid/exceptions.rb +0 -7
  150. data/lib/sendgrid/mail.rb +0 -182
  151. data/lib/sendgrid/recipient.rb +0 -29
  152. data/lib/sendgrid/response.rb +0 -14
  153. data/lib/sendgrid/template.rb +0 -26
  154. data/lib/sendgrid/template_mailer.rb +0 -59
  155. data/spec/lib/sendgrid/client_spec.rb +0 -87
  156. data/spec/lib/sendgrid/mail_spec.rb +0 -151
  157. data/spec/lib/sendgrid/recipient_spec.rb +0 -91
  158. data/spec/lib/sendgrid/template_mailer_spec.rb +0 -86
  159. data/spec/lib/sendgrid/template_spec.rb +0 -61
  160. data/spec/lib/sendgrid_spec.rb +0 -7
@@ -0,0 +1,290 @@
1
+ require 'sendgrid-ruby'
2
+
3
+ sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
4
+
5
+ ##################################################
6
+ # Get a user's account information. #
7
+ # GET /user/account #
8
+
9
+ response = sg.client.user.account.get
10
+ puts response.status_code
11
+ puts response.body
12
+ puts response.headers
13
+
14
+ ##################################################
15
+ # Retrieve your credit balance #
16
+ # GET /user/credits #
17
+
18
+ response = sg.client.user.credits.get
19
+ puts response.status_code
20
+ puts response.body
21
+ puts response.headers
22
+
23
+ ##################################################
24
+ # Update your account email address #
25
+ # PUT /user/email #
26
+
27
+ data = JSON.parse('{
28
+ "email": "example@example.com"
29
+ }')
30
+ response = sg.client.user.email.put(request_body: data)
31
+ puts response.status_code
32
+ puts response.body
33
+ puts response.headers
34
+
35
+ ##################################################
36
+ # Retrieve your account email address #
37
+ # GET /user/email #
38
+
39
+ response = sg.client.user.email.get
40
+ puts response.status_code
41
+ puts response.body
42
+ puts response.headers
43
+
44
+ ##################################################
45
+ # Update your password #
46
+ # PUT /user/password #
47
+
48
+ data = JSON.parse('{
49
+ "new_password": "new_password",
50
+ "old_password": "old_password"
51
+ }')
52
+ response = sg.client.user.password.put(request_body: data)
53
+ puts response.status_code
54
+ puts response.body
55
+ puts response.headers
56
+
57
+ ##################################################
58
+ # Update a user's profile #
59
+ # PATCH /user/profile #
60
+
61
+ data = JSON.parse('{
62
+ "city": "Orange",
63
+ "first_name": "Example",
64
+ "last_name": "User"
65
+ }')
66
+ response = sg.client.user.profile.patch(request_body: data)
67
+ puts response.status_code
68
+ puts response.body
69
+ puts response.headers
70
+
71
+ ##################################################
72
+ # Get a user's profile #
73
+ # GET /user/profile #
74
+
75
+ response = sg.client.user.profile.get
76
+ puts response.status_code
77
+ puts response.body
78
+ puts response.headers
79
+
80
+ ##################################################
81
+ # Cancel or pause a scheduled send #
82
+ # POST /user/scheduled_sends #
83
+
84
+ data = JSON.parse('{
85
+ "batch_id": "YOUR_BATCH_ID",
86
+ "status": "pause"
87
+ }')
88
+ response = sg.client.user.scheduled_sends.post(request_body: data)
89
+ puts response.status_code
90
+ puts response.body
91
+ puts response.headers
92
+
93
+ ##################################################
94
+ # Retrieve all scheduled sends #
95
+ # GET /user/scheduled_sends #
96
+
97
+ response = sg.client.user.scheduled_sends.get
98
+ puts response.status_code
99
+ puts response.body
100
+ puts response.headers
101
+
102
+ ##################################################
103
+ # Update user scheduled send information #
104
+ # PATCH /user/scheduled_sends/{batch_id} #
105
+
106
+ data = JSON.parse('{
107
+ "status": "pause"
108
+ }')
109
+ batch_id = 'test_url_param'
110
+ response = sg.client.user.scheduled_sends._(batch_id).patch(request_body: data)
111
+ puts response.status_code
112
+ puts response.body
113
+ puts response.headers
114
+
115
+ ##################################################
116
+ # Retrieve scheduled send #
117
+ # GET /user/scheduled_sends/{batch_id} #
118
+
119
+ batch_id = 'test_url_param'
120
+ response = sg.client.user.scheduled_sends._(batch_id).get
121
+ puts response.status_code
122
+ puts response.body
123
+ puts response.headers
124
+
125
+ ##################################################
126
+ # Delete a cancellation or pause of a scheduled send #
127
+ # DELETE /user/scheduled_sends/{batch_id} #
128
+
129
+ batch_id = 'test_url_param'
130
+ response = sg.client.user.scheduled_sends._(batch_id).delete
131
+ puts response.status_code
132
+ puts response.body
133
+ puts response.headers
134
+
135
+ ##################################################
136
+ # Update Enforced TLS settings #
137
+ # PATCH /user/settings/enforced_tls #
138
+
139
+ data = JSON.parse('{
140
+ "require_tls": true,
141
+ "require_valid_cert": false
142
+ }')
143
+ response = sg.client.user.settings.enforced_tls.patch(request_body: data)
144
+ puts response.status_code
145
+ puts response.body
146
+ puts response.headers
147
+
148
+ ##################################################
149
+ # Retrieve current Enforced TLS settings. #
150
+ # GET /user/settings/enforced_tls #
151
+
152
+ response = sg.client.user.settings.enforced_tls.get
153
+ puts response.status_code
154
+ puts response.body
155
+ puts response.headers
156
+
157
+ ##################################################
158
+ # Update your username #
159
+ # PUT /user/username #
160
+
161
+ data = JSON.parse('{
162
+ "username": "test_username"
163
+ }')
164
+ response = sg.client.user.username.put(request_body: data)
165
+ puts response.status_code
166
+ puts response.body
167
+ puts response.headers
168
+
169
+ ##################################################
170
+ # Retrieve your username #
171
+ # GET /user/username #
172
+
173
+ response = sg.client.user.username.get
174
+ puts response.status_code
175
+ puts response.body
176
+ puts response.headers
177
+
178
+ ##################################################
179
+ # Update Event Notification Settings #
180
+ # PATCH /user/webhooks/event/settings #
181
+
182
+ data = JSON.parse('{
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,
195
+ "url": "url"
196
+ }')
197
+ response = sg.client.user.webhooks.event.settings.patch(request_body: data)
198
+ puts response.status_code
199
+ puts response.body
200
+ puts response.headers
201
+
202
+ ##################################################
203
+ # Retrieve Event Webhook settings #
204
+ # GET /user/webhooks/event/settings #
205
+
206
+ response = sg.client.user.webhooks.event.settings.get
207
+ puts response.status_code
208
+ puts response.body
209
+ puts response.headers
210
+
211
+ ##################################################
212
+ # Test Event Notification Settings #
213
+ # POST /user/webhooks/event/test #
214
+
215
+ data = JSON.parse('{
216
+ "url": "url"
217
+ }')
218
+ response = sg.client.user.webhooks.event.test.post(request_body: data)
219
+ puts response.status_code
220
+ puts response.body
221
+ puts response.headers
222
+
223
+ ##################################################
224
+ # Create a parse setting #
225
+ # POST /user/webhooks/parse/settings #
226
+
227
+ data = JSON.parse('{
228
+ "hostname": "myhostname.com",
229
+ "send_raw": false,
230
+ "spam_check": true,
231
+ "url": "http://email.myhosthame.com"
232
+ }')
233
+ response = sg.client.user.webhooks.parse.settings.post(request_body: data)
234
+ puts response.status_code
235
+ puts response.body
236
+ puts response.headers
237
+
238
+ ##################################################
239
+ # Retrieve all parse settings #
240
+ # GET /user/webhooks/parse/settings #
241
+
242
+ response = sg.client.user.webhooks.parse.settings.get
243
+ puts response.status_code
244
+ puts response.body
245
+ puts response.headers
246
+
247
+ ##################################################
248
+ # Update a parse setting #
249
+ # PATCH /user/webhooks/parse/settings/{hostname} #
250
+
251
+ data = JSON.parse('{
252
+ "send_raw": true,
253
+ "spam_check": false,
254
+ "url": "http://newdomain.com/parse"
255
+ }')
256
+ hostname = 'test_url_param'
257
+ response = sg.client.user.webhooks.parse.settings._(hostname).patch(request_body: data)
258
+ puts response.status_code
259
+ puts response.body
260
+ puts response.headers
261
+
262
+ ##################################################
263
+ # Retrieve a specific parse setting #
264
+ # GET /user/webhooks/parse/settings/{hostname} #
265
+
266
+ hostname = 'test_url_param'
267
+ response = sg.client.user.webhooks.parse.settings._(hostname).get
268
+ puts response.status_code
269
+ puts response.body
270
+ puts response.headers
271
+
272
+ ##################################################
273
+ # Delete a parse setting #
274
+ # DELETE /user/webhooks/parse/settings/{hostname} #
275
+
276
+ hostname = 'test_url_param'
277
+ response = sg.client.user.webhooks.parse.settings._(hostname).delete
278
+ puts response.status_code
279
+ puts response.body
280
+ puts response.headers
281
+
282
+ ##################################################
283
+ # Retrieves Inbound Parse Webhook statistics. #
284
+ # GET /user/webhooks/parse/stats #
285
+
286
+ params = JSON.parse('{"aggregated_by": "day", "limit": "test_string", "start_date": "2016-01-01", "end_date": "2016-04-01", "offset": "test_string"}')
287
+ response = sg.client.user.webhooks.parse.stats.get(query_params: params)
288
+ puts response.status_code
289
+ puts response.body
290
+ puts response.headers
@@ -0,0 +1,6 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'ruby_http_client'
6
+ gem 'sinatra', '~> 1.4'
@@ -0,0 +1,6 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'ruby_http_client'
6
+ gem 'sinatra', '>= 2.0.0.rc2'
@@ -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
@@ -0,0 +1,40 @@
1
+ require 'ruby_http_client'
2
+ require_relative 'version'
3
+
4
+ # Initialize the HTTP client
5
+ class BaseInterface
6
+ attr_accessor :client
7
+ attr_reader :request_headers, :host, :version, :impersonate_subuser, :http_options
8
+
9
+ # * *Args* :
10
+ # - +auth+ -> authorization header value
11
+ # - +host+ -> the base URL for the API
12
+ # - +request_headers+ -> any headers that you want to be globally applied
13
+ # - +version+ -> the version of the API you wish to access,
14
+ # currently only "v3" is supported
15
+ # - +impersonate_subuser+ -> the subuser to impersonate, will be passed
16
+ # in the "On-Behalf-Of" header
17
+ # - +http_options+ -> http options that you want to be globally applied to each request
18
+ #
19
+ def initialize(auth:, host:, request_headers: nil, version: nil, impersonate_subuser: nil, http_options: {})
20
+ @auth = auth
21
+ @host = host
22
+ @version = version || 'v3'
23
+ @impersonate_subuser = impersonate_subuser
24
+ @user_agent = "sendgrid/#{SendGrid::VERSION};ruby"
25
+ @request_headers = JSON.parse('
26
+ {
27
+ "Authorization": "' + @auth + '",
28
+ "Accept": "application/json",
29
+ "User-Agent": "' + @user_agent + '"
30
+ }
31
+ ')
32
+ @request_headers['On-Behalf-Of'] = @impersonate_subuser if @impersonate_subuser
33
+
34
+ @request_headers = @request_headers.merge(request_headers) if request_headers
35
+ @http_options = http_options
36
+ @client = SendGrid::Client.new(host: "#{@host}/#{@version}",
37
+ request_headers: @request_headers,
38
+ http_options: @http_options)
39
+ end
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
@@ -0,0 +1,98 @@
1
+ **This helper is a stand alone module to help get you started consuming and processing Inbound Parse data.**
2
+
3
+ ## Table of Contents
4
+
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)
13
+
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](../../../../README.md#installation),
21
+ you must also add sinatra to your Gemfile:
22
+
23
+ ```
24
+ gem 'sinatra', '>= 1.4.7', '< 3'
25
+ ```
26
+
27
+
28
+ # Quick Start for Local Testing with Sample Data
29
+
30
+ ```bash
31
+ git clone https://github.com/sendgrid/sendgrid-ruby.git
32
+ cd sendgrid-ruby
33
+ bundle install
34
+ ```
35
+
36
+ Run the Inbound Parse listener in your terminal:
37
+
38
+ ```ruby
39
+ rackup
40
+ ```
41
+
42
+ In another terminal, run the test data sender:
43
+
44
+ ```bash
45
+ cd [path to sendgrid-ruby]
46
+ bundle install
47
+ ruby ./lib/sendgrid/helpers/inbound/send.rb ./lib/sendgrid/helpers/inbound/sample_data/default_data.txt
48
+ ```
49
+
50
+ More sample data can be found [here](sample_data).
51
+
52
+ View the results in the first terminal.
53
+
54
+ <a name="quick_start_local_real"></a>
55
+ # Quick Start for Local Testing with Real Data
56
+
57
+ [Setup your MX records.](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Setup) Depending on your domain name host, you may need to wait up to 48 hours for the settings to propagate.
58
+
59
+ Run the Inbound Parse listener in your terminal:
60
+
61
+ ```bash
62
+ git clone https://github.com/sendgrid/sendgrid-ruby.git
63
+ cd sendgrid-ruby
64
+ bundle install
65
+ rackup
66
+ ```
67
+
68
+ In another terminal, use [ngrok](https://ngrok.com/) to allow external access to your machine:
69
+ ```bash
70
+ ngrok http 9292
71
+ ```
72
+
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)
74
+
75
+ - For the HOSTNAME field, use the domain that you changed the MX records (e.g. inbound.yourdomain.com)
76
+ - For the URL field, use the URL generated by ngrok + /inbound, e.g http://XXXXXXX.ngrok.io/inbound
77
+
78
+ Next, send an email to [anything]@inbound.yourdomain.com, then look at the terminal where you started the Inbound Parse listener.
79
+
80
+ <a name="code_walkthrough"></a>
81
+ # Code Walkthrough
82
+
83
+ ## app.rb
84
+
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
+
87
+ ## config.yml
88
+
89
+ This module loads application environment variables (located in [config.yml](config.yml)).
90
+
91
+ ## send.rb & /sample_data
92
+
93
+ This module is used to send sample test data. It is useful for testing and development, particularly while you wait for your MX records to propagate.
94
+
95
+ <a name="contributing"></a>
96
+ # Contributing
97
+
98
+ If you would like to contribute to this project, please see our [contributing guide](../../../../CONTRIBUTING.md). Thanks!
@@ -0,0 +1,32 @@
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
14
+ require 'logger'
15
+ require 'json'
16
+ require 'yaml'
17
+
18
+ class Main < Sinatra::Base
19
+ configure :production, :development do
20
+ enable :logging
21
+ set :config, YAML.load_file("#{File.dirname(__FILE__)}/config.yml")
22
+ end
23
+
24
+ get '/' do
25
+ redirect to('index.html')
26
+ end
27
+
28
+ post settings.config['endpoint'] do
29
+ filtered = params.select { |k, _v| settings.config['keys'].include?(k) }
30
+ logger.info JSON.pretty_generate(filtered)
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ # Incoming Parse endpoint for receiver
2
+ endpoint: '/inbound'
3
+
4
+ # List all Incoming Parse fields you would like parsed
5
+ # Reference: https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html
6
+ keys:
7
+ - from
8
+ - attachments
9
+ - headers
10
+ - text
11
+ - envelope
12
+ - to
13
+ - html
14
+ - sender_ip
15
+ - attachment-info
16
+ - subject
17
+ - dkim
18
+ - SPF
19
+ - charsets
20
+ - content-ids
21
+ - spam_report
22
+ - spam_score
23
+ - email
24
+
25
+ # URL that the sender will POST to
26
+ host: 'http://127.0.0.1:9292/inbound'
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <head>
3
+ <title>Twilio SendGrid Incoming Parse</title>
4
+ </head>
5
+ <body>
6
+ <h1>You have successfuly launched the server!</h1>
7
+
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
+ </body>
10
+ </html>
@@ -0,0 +1,58 @@
1
+ --xYzZY
2
+ Content-Disposition: form-data; name="headers"
3
+
4
+ MIME-Version: 1.0
5
+ Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 18:10:13 -0700 (PDT)
6
+ From: Example User <test@example.com>
7
+ Date: Wed, 10 Aug 2016 18:10:13 -0700
8
+ Subject: Inbound Parse Test Data
9
+ To: inbound@inbound.example.com
10
+ Content-Type: multipart/alternative; boundary=001a113df448cad2d00539c16e89
11
+
12
+ --xYzZY
13
+ Content-Disposition: form-data; name="dkim"
14
+
15
+ {@sendgrid.com : pass}
16
+ --xYzZY
17
+ Content-Disposition: form-data; name="to"
18
+
19
+ inbound@inbound.example.com
20
+ --xYzZY
21
+ Content-Disposition: form-data; name="html"
22
+
23
+ <html><body><strong>Hello Twilio SendGrid!</body></html>
24
+
25
+ --xYzZY
26
+ Content-Disposition: form-data; name="from"
27
+
28
+ Example User <test@example.com>
29
+ --xYzZY
30
+ Content-Disposition: form-data; name="text"
31
+
32
+ Hello Twilio SendGrid!
33
+
34
+ --xYzZY
35
+ Content-Disposition: form-data; name="sender_ip"
36
+
37
+ 0.0.0.0
38
+ --xYzZY
39
+ Content-Disposition: form-data; name="envelope"
40
+
41
+ {"to":["inbound@inbound.example.com"],"from":"test@example.com"}
42
+ --xYzZY
43
+ Content-Disposition: form-data; name="attachments"
44
+
45
+ 0
46
+ --xYzZY
47
+ Content-Disposition: form-data; name="subject"
48
+
49
+ Testing non-raw
50
+ --xYzZY
51
+ Content-Disposition: form-data; name="charsets"
52
+
53
+ {"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"}
54
+ --xYzZY
55
+ Content-Disposition: form-data; name="SPF"
56
+
57
+ pass
58
+ --xYzZY--