FEATURE: AWS SNS bounce notifications webhooks
This commit is contained in:
parent
560cc4e73e
commit
4d674acc25
1
Gemfile
1
Gemfile
|
@ -65,6 +65,7 @@ gem 'fast_xor', platform: :mri
|
|||
gem 'fastimage'
|
||||
|
||||
gem 'aws-sdk-s3', require: false
|
||||
gem 'aws-sdk-sns', require: false
|
||||
gem 'excon', require: false
|
||||
gem 'unf', require: false
|
||||
|
||||
|
|
|
@ -57,6 +57,9 @@ GEM
|
|||
aws-sdk-core (~> 3, >= 3.26.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.0)
|
||||
aws-sdk-sns (1.2.0)
|
||||
aws-sdk-core (~> 3)
|
||||
aws-sigv4 (~> 1.0)
|
||||
aws-sigv4 (1.0.3)
|
||||
barber (0.12.0)
|
||||
ember-source (>= 1.0, < 3.1)
|
||||
|
@ -452,6 +455,7 @@ DEPENDENCIES
|
|||
activesupport (= 5.2.2)
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
aws-sdk-sns
|
||||
barber
|
||||
better_errors
|
||||
binding_of_caller
|
||||
|
|
|
@ -24,7 +24,7 @@ class WebhooksController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
render body: nil, status: 200
|
||||
success
|
||||
end
|
||||
|
||||
def mailjet
|
||||
|
@ -41,7 +41,7 @@ class WebhooksController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
render body: nil, status: 200
|
||||
success
|
||||
end
|
||||
|
||||
def mandrill
|
||||
|
@ -58,7 +58,7 @@ class WebhooksController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
render body: nil, status: 200
|
||||
success
|
||||
end
|
||||
|
||||
def sparkpost
|
||||
|
@ -84,7 +84,21 @@ class WebhooksController < ActionController::Base
|
|||
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
|
||||
|
||||
private
|
||||
|
@ -93,7 +107,7 @@ class WebhooksController < ActionController::Base
|
|||
render body: nil, status: 406
|
||||
end
|
||||
|
||||
def mailgun_success
|
||||
def success
|
||||
render body: nil, status: 200
|
||||
end
|
||||
|
||||
|
@ -129,7 +143,7 @@ class WebhooksController < ActionController::Base
|
|||
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
|
||||
end
|
||||
|
||||
mailgun_success
|
||||
success
|
||||
end
|
||||
|
||||
def handle_mailgun_new(params)
|
||||
|
@ -149,7 +163,7 @@ class WebhooksController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
mailgun_success
|
||||
success
|
||||
end
|
||||
|
||||
def process_bounce(message_id, to_address, bounce_score)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -15,10 +15,11 @@ Discourse::Application.routes.draw do
|
|||
match "/404", to: "exceptions#not_found", via: [:get, :post]
|
||||
get "/404-body" => "exceptions#not_found_body"
|
||||
|
||||
post "webhooks/aws" => "webhooks#aws"
|
||||
post "webhooks/mailgun" => "webhooks#mailgun"
|
||||
post "webhooks/sendgrid" => "webhooks#sendgrid"
|
||||
post "webhooks/mailjet" => "webhooks#mailjet"
|
||||
post "webhooks/mandrill" => "webhooks#mandrill"
|
||||
post "webhooks/sendgrid" => "webhooks#sendgrid"
|
||||
post "webhooks/sparkpost" => "webhooks#sparkpost"
|
||||
|
||||
if Rails.env.development?
|
||||
|
|
Loading…
Reference in New Issue