Permalink
Browse files

a new implementation of the SendGrid event endpoint

Batching events from SendGrid is more scalable, but introduces a hiccup: SendGrid doesn't POST a fully valid JSON response body, but rather newline-separated valid JSON strings
To compensate for this, we move the SendGrid event Rack endpoint above the ParamsParser and coerce the raw POST data to be valid JSON
Generalizes the endpoint to accept future email categories and event types
  • Loading branch information...
1 parent a294943 commit 40e9a9b2f1fa804f71ea484e886f191b36d2125e @agrobbin committed Nov 12, 2012
Showing with 20 additions and 9 deletions.
  1. +19 −8 app/middleware/send_grid_events.rb
  2. +1 −1 config/initializers/sendgrid.rb
@@ -5,20 +5,31 @@ def initialize(app)
end
def call(env)
- if env['PATH_INFO'] == '/sendgrid_tracking' && env['REQUEST_METHOD'] == 'POST'
- request = Rack::Request.new(env)
- params = request.params
+ if env['PATH_INFO'] == '/sendgrid_events' && env['REQUEST_METHOD'] == 'POST'
+ request = ActionDispatch::Request.new(env)
+ # Newlines need to be replaced with commas, and the total raw post encapsulated in brackets
+ events = ActiveSupport::JSON.decode("[#{request.raw_post.sub("\n", ",")}]")
- # Mark notification as read when the email is opened if it isn't already marked.
- if params['category'] == 'notification' && params['event'] == 'open'
- notification = Notification.find(params['notification_id'])
- notification.read! unless notification.read
- end
+ events = events.group_by {|event| event['category']}
+ events.each {|category, events| send("process_#{category}_events!", events)}
[200, {"Content-Type" => "text/html"}, [""]]
else
@app.call(env)
end
end
+ # To test notification email events:
+ # curl -i -H "Content-Type: application/json" -X POST -d $'{"email":"test@gmail.com","event":"open","category":"notification","notification_id":"1"}' http://localhost:3000/sendgrid_events
+ # curl -i -H "Content-Type: application/json" -X POST -d $'{"email":"test@gmail.com","event":"open","category":"notification","notification_id":"1"}\n{"email":"test2@gmail.com","event":"open","category":"notification","notification_id":"2"}' http://localhost:3000/sendgrid_events
+ def process_notification_events!(events)
+ events = events.group_by {|event| event['event']}
+ events.each do |event, notifications|
+ case event
+ when 'open'
+ Notification.where(id: notifications.collect {|n| n['notification_id']}).update_all(read: true)
+ end
+ end
+ end
+
end
@@ -1,4 +1,4 @@
-Rails.application.config.middleware.use SendGridEvents
+Rails.application.config.middleware.insert_before ActionDispatch::ParamsParser, SendGridEvents
ActionMailer::Base.register_interceptor SendGrid::MailInterceptor
ActionMailer::Base.smtp_settings = {

0 comments on commit 40e9a9b

Please sign in to comment.