diff --git a/app/controllers/webhooks_controller.rb b/app/controllers/webhooks_controller.rb index f12786127..05dec8054 100644 --- a/app/controllers/webhooks_controller.rb +++ b/app/controllers/webhooks_controller.rb @@ -37,6 +37,22 @@ class WebhooksController < ActionController::Base handled ? mailgun_success : mailgun_failure end + def sendgrid + params["_json"].each do |event| + if event["event"] == "bounce".freeze + if event["status"]["4."] + sendgrid_process(event, Email::Receiver::SOFT_BOUNCE_SCORE) + else + sendgrid_process(event, Email::Receiver::HARD_BOUNCE_SCORE) + end + elsif event["event"] == "dropped".freeze + sendgrid_process(event, Email::Receiver::HARD_BOUNCE_SCORE) + end + end + + render nothing: true, status: 200 + end + private def mailgun_failure @@ -74,4 +90,15 @@ class WebhooksController < ActionController::Base true end + def sendgrid_process(event, bounce_score) + message_id = event["smtp-id"] + return if message_id.blank? + + email_log = EmailLog.find_by(message_id: message_id.tr("<>", "")) + return if email_log.nil? + + email_log.update_columns(bounced: true) + Email::Receiver.update_bounce_score(email_log.user.email, bounce_score) + end + end diff --git a/config/environments/development.rb b/config/environments/development.rb index 7079245f7..179798a6b 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -51,4 +51,22 @@ Discourse::Application.configure do if emails = GlobalSetting.developer_emails config.developer_emails = emails.split(",").map(&:downcase).map(&:strip) end + + + if GlobalSetting.smtp_address + settings = { + address: GlobalSetting.smtp_address, + port: GlobalSetting.smtp_port, + domain: GlobalSetting.smtp_domain, + user_name: GlobalSetting.smtp_user_name, + password: GlobalSetting.smtp_password, + authentication: GlobalSetting.smtp_authentication, + enable_starttls_auto: GlobalSetting.smtp_enable_start_tls + } + + settings[:openssl_verify_mode] = GlobalSetting.smtp_openssl_verify_mode if GlobalSetting.smtp_openssl_verify_mode + + config.action_mailer.smtp_settings = settings.reject{|_, y| y.nil?} + end + end diff --git a/config/routes.rb b/config/routes.rb index 9a1675e24..beb689235 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,6 +17,7 @@ Discourse::Application.routes.draw do get "/404-body" => "exceptions#not_found_body" post "webhooks/mailgun" => "webhooks#mailgun" + post "webhooks/sendgrid" => "webhooks#sendgrid" if Rails.env.development? mount Sidekiq::Web => "/sidekiq" diff --git a/db/migrate/20160530203810_add_message_id_to_email_logs.rb b/db/migrate/20160530203810_add_message_id_to_email_logs.rb new file mode 100644 index 000000000..bb74401db --- /dev/null +++ b/db/migrate/20160530203810_add_message_id_to_email_logs.rb @@ -0,0 +1,6 @@ +class AddMessageIdToEmailLogs < ActiveRecord::Migration + def change + add_column :email_logs, :message_id, :string + add_index :email_logs, :message_id + end +end diff --git a/lib/auth/default_current_user_provider.rb b/lib/auth/default_current_user_provider.rb index 01dfbd7f9..6bb2d1ed4 100644 --- a/lib/auth/default_current_user_provider.rb +++ b/lib/auth/default_current_user_provider.rb @@ -120,12 +120,11 @@ class Auth::DefaultCurrentUserProvider protected def lookup_api_user(api_key_value, request) - api_key = ApiKey.where(key: api_key_value).includes(:user).first - if api_key + if api_key = ApiKey.where(key: api_key_value).includes(:user).first api_username = request["api_username"] - if api_key.allowed_ips.present? && !api_key.allowed_ips.any?{|ip| ip.include?(request.ip)} - Rails.logger.warn("Unauthorized API access: #{api_username} ip address: #{request.ip}") + if api_key.allowed_ips.present? && !api_key.allowed_ips.any? { |ip| ip.include?(request.ip) } + Rails.logger.warn("[Unauthorized API Access] username: #{api_username}, IP address: #{request.ip}") return nil end diff --git a/lib/email/sender.rb b/lib/email/sender.rb index a83d012e1..c3884f81c 100644 --- a/lib/email/sender.rb +++ b/lib/email/sender.rb @@ -141,6 +141,8 @@ module Email @message.html_part.body = style.strip_avatars_and_emojis end + email_log.message_id = @message.message_id + begin @message.deliver_now rescue *SMTP_CLIENT_ERRORS => e diff --git a/spec/controllers/webhooks_controller_spec.rb b/spec/controllers/webhooks_controller_spec.rb index 662833b49..1e8f99db3 100644 --- a/spec/controllers/webhooks_controller_spec.rb +++ b/spec/controllers/webhooks_controller_spec.rb @@ -2,19 +2,21 @@ require "rails_helper" describe WebhooksController do - context "mailgun" do + let(:email) { "em@il.com" } + before { $redis.del("bounce_score:#{email}:#{Date.today}") } + + context "mailgun" do it "works" do SiteSetting.mailgun_api_key = "pubkey-8221462f0c915af3f6f2e2df7aa5a493" token = "705a8ccd2ce932be8e98c221fe701c1b4a0afcb8bbd57726de" - user = Fabricate(:user, email: "em@il.com") + user = Fabricate(:user, email: email) email_log = Fabricate(:email_log, user: user, bounce_key: SecureRandom.hex) return_path = "foo+verp-#{email_log.bounce_key}@bar.com" $redis.del("mailgun_token_#{token}") - $redis.del("bounce_score:#{user.email}:#{Date.today}") WebhooksController.any_instance.expects(:mailgun_verify).returns(true) post :mailgun, "token" => token, @@ -31,4 +33,29 @@ describe WebhooksController do end + context "sendgrid" do + + it "works" do + user = Fabricate(:user, email: email) + email_log = Fabricate(:email_log, user: user, message_id: "12345@il.com") + + post :sendgrid, "_json" => [ + { + "email" => email, + "timestamp" => 1249948800, + "smtp-id" => "<12345@il.com>", + "event" => "bounce", + "status" => "5.0.0" + } + ] + + expect(response).to be_success + + email_log.reload + expect(email_log.bounced).to eq(true) + expect(email_log.user.user_stat.bounce_score).to eq(2) + end + + end + end