diff --git a/app/lib/balancer_delivery_method.rb b/app/lib/balancer_delivery_method.rb index 2f9774af0..2ed33ae91 100644 --- a/app/lib/balancer_delivery_method.rb +++ b/app/lib/balancer_delivery_method.rb @@ -14,6 +14,7 @@ # # Be sure to restart your server when you modify this file. class BalancerDeliveryMethod + BYPASS_UNVERIFIED_MAIL_PROTECTION = 'BYPASS_UNVERIFIED_MAIL_PROTECTION'.freeze FORCE_DELIVERY_METHOD_HEADER = 'X-deliver-with' # Allows configuring the random number generator used for selecting a delivery method, # mostly for testing purposes. @@ -24,6 +25,8 @@ class BalancerDeliveryMethod end def deliver!(mail) + return if prevent_delivery?(mail) + balanced_delivery_method = delivery_method(mail) ApplicationMailer.wrap_delivery_behavior(mail, balanced_delivery_method) @@ -40,6 +43,18 @@ class BalancerDeliveryMethod private + def prevent_delivery?(mail) + return false if mail[BYPASS_UNVERIFIED_MAIL_PROTECTION].present? + + user = User.find_by(email: mail.to.first) + return user.unverified_email? if user.present? + + individual = Individual.find_by(email: mail.to.first) + return individual.unverified_email? if individual.present? + + true + end + def force_delivery_method?(mail) @delivery_methods.keys.map(&:to_s).include?(mail[FORCE_DELIVERY_METHOD_HEADER]&.value) end diff --git a/app/models/individual.rb b/app/models/individual.rb index 812435242..fd9406391 100644 --- a/app/models/individual.rb +++ b/app/models/individual.rb @@ -29,4 +29,6 @@ class Individual < ApplicationRecord gender: fc_information.gender == 'female' ? GENDER_FEMALE : GENDER_MALE ) end + + def unverified_email? = !email_verified_at? end diff --git a/app/models/user.rb b/app/models/user.rb index d047ab1d1..576f65759 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -267,6 +267,8 @@ class User < ApplicationRecord super && blocked_at.nil? end + def unverified_email? = !email_verified_at? + private def does_not_merge_on_self diff --git a/spec/lib/balancer_delivery_method_spec.rb b/spec/lib/balancer_delivery_method_spec.rb index 7fb2495be..36c691195 100644 --- a/spec/lib/balancer_delivery_method_spec.rb +++ b/spec/lib/balancer_delivery_method_spec.rb @@ -1,7 +1,11 @@ RSpec.describe BalancerDeliveryMethod do class ExampleMailer < ApplicationMailer - def greet(name) - mail(to: "smtp_to", from: "smtp_from", body: "Hello #{name}") + def greet(name, bypass_unverified_mail_protection: true) + mail(to: name, from: "smtp_from", body: "Hello #{name}") + + if bypass_unverified_mail_protection + headers['BYPASS_UNVERIFIED_MAIL_PROTECTION'] = true + end end end @@ -9,7 +13,8 @@ RSpec.describe BalancerDeliveryMethod do before_action :set_x_deliver_with def greet(name) - mail(to: "smtp_to", from: "smtp_from", body: "Hello #{name}") + mail(to: name, from: "smtp_from", body: "Hello #{name}") + headers['BYPASS_UNVERIFIED_MAIL_PROTECTION'] = true end private @@ -145,6 +150,57 @@ RSpec.describe BalancerDeliveryMethod do end end + context 'when the email does not bypass unverified mail protection' do + let(:mail) { ExampleMailer.greet(email, bypass_unverified_mail_protection:) } + let(:bypass_unverified_mail_protection) { false } + + before do + ActionMailer::Base.balancer_settings = { mock_smtp: 10 } + mail.deliver_now + end + + context 'when the email belongs to a user' do + let(:email) { user.email } + let(:user) { create(:user, email: 'u@a.com', email_verified_at:) } + + context 'and the email is not verified' do + let(:email_verified_at) { nil } + + it { expect(mail).not_to have_been_delivered_using(MockSmtp) } + end + + context 'and the email is not verified but a bypass flag is added' do + let(:email_verified_at) { nil } + let(:bypass_unverified_mail_protection) { true } + + it { expect(mail).to have_been_delivered_using(MockSmtp) } + end + + context 'and the email is verified' do + let(:email_verified_at) { Time.current } + + it { expect(mail).to have_been_delivered_using(MockSmtp) } + end + end + + context 'when the email belongs to a individual' do + let(:email) { individual.email } + let(:individual) { create(:individual, email: 'u@a.com', email_verified_at:) } + + context 'and the email is not verified' do + let(:email_verified_at) { nil } + + it { expect(mail).not_to have_been_delivered_using(MockSmtp) } + end + + context 'and the email is verified' do + let(:email_verified_at) { Time.current } + + it { expect(mail).to have_been_delivered_using(MockSmtp) } + end + end + end + # Helpers def have_been_delivered_using(delivery_class)