FEATURE: AWS SNS bounce notifications webhooks

This commit is contained in:
Régis Hanol 2019-02-13 21:26:40 +01:00
parent 560cc4e73e
commit 4d674acc25
6 changed files with 85 additions and 8 deletions

View File

@ -65,6 +65,7 @@ gem 'fast_xor', platform: :mri
gem 'fastimage' gem 'fastimage'
gem 'aws-sdk-s3', require: false gem 'aws-sdk-s3', require: false
gem 'aws-sdk-sns', require: false
gem 'excon', require: false gem 'excon', require: false
gem 'unf', require: false gem 'unf', require: false

View File

@ -57,6 +57,9 @@ GEM
aws-sdk-core (~> 3, >= 3.26.0) aws-sdk-core (~> 3, >= 3.26.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.0)
aws-sdk-sns (1.2.0)
aws-sdk-core (~> 3)
aws-sigv4 (~> 1.0)
aws-sigv4 (1.0.3) aws-sigv4 (1.0.3)
barber (0.12.0) barber (0.12.0)
ember-source (>= 1.0, < 3.1) ember-source (>= 1.0, < 3.1)
@ -452,6 +455,7 @@ DEPENDENCIES
activesupport (= 5.2.2) activesupport (= 5.2.2)
annotate annotate
aws-sdk-s3 aws-sdk-s3
aws-sdk-sns
barber barber
better_errors better_errors
binding_of_caller binding_of_caller

View File

@ -24,7 +24,7 @@ class WebhooksController < ActionController::Base
end end
end end
render body: nil, status: 200 success
end end
def mailjet def mailjet
@ -41,7 +41,7 @@ class WebhooksController < ActionController::Base
end end
end end
render body: nil, status: 200 success
end end
def mandrill def mandrill
@ -58,7 +58,7 @@ class WebhooksController < ActionController::Base
end end
end end
render body: nil, status: 200 success
end end
def sparkpost def sparkpost
@ -84,7 +84,21 @@ class WebhooksController < ActionController::Base
end end
end end
render body: nil, status: 200 success
end
def aws
raw = request.raw_post
json = JSON.parse(raw)
case json["Type"]
when "SubscriptionConfirmation"
Jobs.enqueue(:confirm_sns_subscription, raw: raw, json: json)
when "Notification"
Jobs.enqueue(:process_sns_notification, raw: raw, json: json)
end
success
end end
private private
@ -93,7 +107,7 @@ class WebhooksController < ActionController::Base
render body: nil, status: 406 render body: nil, status: 406
end end
def mailgun_success def success
render body: nil, status: 200 render body: nil, status: 200
end end
@ -129,7 +143,7 @@ class WebhooksController < ActionController::Base
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score) process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
end end
mailgun_success success
end end
def handle_mailgun_new(params) def handle_mailgun_new(params)
@ -149,7 +163,7 @@ class WebhooksController < ActionController::Base
end end
end end
mailgun_success success
end end
def process_bounce(message_id, to_address, bounce_score) def process_bounce(message_id, to_address, bounce_score)

View File

@ -0,0 +1,21 @@
require "aws-sdk-sns"
module Jobs
class ConfirmSnsSubscription < Jobs::Base
sidekiq_options retry: false
def execute(args)
return unless raw = args[:raw].presence
return unless json = args[:json].presence
return unless subscribe_url = json["SubscribeURL"].presence
return unless Aws::SNS::MessageVerifier.new.authentic?(raw)
# confirm subscription by visiting the URL
open(subscribe_url)
end
end
end

View File

@ -0,0 +1,36 @@
require "aws-sdk-sns"
module Jobs
class ProcessSnsNotification < Jobs::Base
sidekiq_options retry: false
def execute(args)
return unless raw = args[:raw].presence
return unless json = args[:json].presence
return unless message = json["Message"].presence
return unless message["notificationType"] == "Bounce"
return unless message_id = message.dig("mail", "messageId").presence
return unless bounce_type = message.dig("bounce", "bounceType").presence
return unless Aws::SNS::MessageVerifier.new.authentic?(raw)
message.dig("bounce", "bouncedRecipients").each do |r|
if email_log = EmailLog.find_by(message_id: message_id, to_address: r["emailAddress"])
email_log.update_columns(bounced: true)
if email_log.user&.email.present?
if r["status"]&.start_with?["4."] || bounce_type == "Transient"
Email::Receiver.update_bounce_score(email_log.user.email, SiteSetting.soft_bounce_score)
else
Email::Receiver.update_bounce_score(email_log.user.email, SiteSetting.hard_bounce_score)
end
end
end
end
end
end
end

View File

@ -15,10 +15,11 @@ Discourse::Application.routes.draw do
match "/404", to: "exceptions#not_found", via: [:get, :post] match "/404", to: "exceptions#not_found", via: [:get, :post]
get "/404-body" => "exceptions#not_found_body" get "/404-body" => "exceptions#not_found_body"
post "webhooks/aws" => "webhooks#aws"
post "webhooks/mailgun" => "webhooks#mailgun" post "webhooks/mailgun" => "webhooks#mailgun"
post "webhooks/sendgrid" => "webhooks#sendgrid"
post "webhooks/mailjet" => "webhooks#mailjet" post "webhooks/mailjet" => "webhooks#mailjet"
post "webhooks/mandrill" => "webhooks#mandrill" post "webhooks/mandrill" => "webhooks#mandrill"
post "webhooks/sendgrid" => "webhooks#sendgrid"
post "webhooks/sparkpost" => "webhooks#sparkpost" post "webhooks/sparkpost" => "webhooks#sparkpost"
if Rails.env.development? if Rails.env.development?