2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-09 04:28:27 +08:00
|
|
|
require "email/processor"
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
RSpec.describe Email::Processor do
|
2020-05-23 12:56:13 +08:00
|
|
|
after { Discourse.redis.flushdb }
|
2016-08-09 04:28:27 +08:00
|
|
|
|
2017-07-22 01:24:31 +08:00
|
|
|
let(:from) { "foo@bar.com" }
|
|
|
|
|
2018-08-03 03:43:53 +08:00
|
|
|
context "when reply via email is too short" do
|
2018-08-21 14:29:58 +08:00
|
|
|
let(:mail) { file_from_fixtures("chinese_reply.eml", "emails").read }
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:post)
|
2023-11-22 02:31:42 +08:00
|
|
|
fab!(:user) { Fabricate(:user, email: "discourse@bar.com", refresh_auto_groups: true) }
|
2018-08-21 14:29:58 +08:00
|
|
|
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:post_reply_key) do
|
2018-08-21 14:29:58 +08:00
|
|
|
Fabricate(
|
|
|
|
:post_reply_key,
|
|
|
|
user: user,
|
|
|
|
post: post,
|
|
|
|
reply_key: "4f97315cc828096c9cb34c6f1a0d6fe8",
|
2018-08-03 03:43:53 +08:00
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
2018-08-21 14:29:58 +08:00
|
|
|
SiteSetting.email_in = true
|
|
|
|
SiteSetting.reply_by_email_address = "reply+%{reply_key}@bar.com"
|
2018-08-03 03:43:53 +08:00
|
|
|
SiteSetting.min_post_length = 1000
|
|
|
|
end
|
|
|
|
|
|
|
|
it "rejects reply and sends an email with custom error message" do
|
|
|
|
processor = Email::Processor.new(mail)
|
|
|
|
processor.process!
|
|
|
|
|
2018-08-21 14:29:58 +08:00
|
|
|
rejection_raw = ActionMailer::Base.deliveries.first.body.raw_source
|
2018-08-03 03:43:53 +08:00
|
|
|
|
|
|
|
count = SiteSetting.min_post_length
|
2018-08-21 14:29:58 +08:00
|
|
|
destination = processor.receiver.mail.to
|
|
|
|
former_title = processor.receiver.mail.subject
|
2018-08-03 03:43:53 +08:00
|
|
|
|
|
|
|
expect(rejection_raw.gsub(/\r/, "")).to eq(
|
|
|
|
I18n.t(
|
|
|
|
"system_messages.email_reject_post_too_short.text_body_template",
|
|
|
|
count: count,
|
|
|
|
destination: destination,
|
|
|
|
former_title: former_title,
|
|
|
|
).gsub(/\r/, ""),
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-05-18 10:39:37 +08:00
|
|
|
describe "when mail is not set" do
|
|
|
|
it "does not raise an error" do
|
|
|
|
expect { Email::Processor.process!(nil) }.not_to raise_error
|
|
|
|
expect { Email::Processor.process!("") }.not_to raise_error
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-09 04:28:27 +08:00
|
|
|
describe "rate limits" do
|
2017-07-22 01:24:31 +08:00
|
|
|
let(:mail) { "From: #{from}\nTo: bar@foo.com\nSubject: FOO BAR\n\nFoo foo bar bar?" }
|
2016-08-09 04:28:27 +08:00
|
|
|
let(:limit_exceeded) { RateLimiter::LimitExceeded.new(10) }
|
|
|
|
|
|
|
|
before { Email::Receiver.any_instance.expects(:process!).raises(limit_exceeded) }
|
|
|
|
|
|
|
|
it "enqueues a background job by default" do
|
2020-07-24 17:16:52 +08:00
|
|
|
expect_enqueued_with(job: :process_email, args: { mail: mail }) do
|
|
|
|
Email::Processor.process!(mail, retry_on_rate_limit: true)
|
|
|
|
end
|
2016-08-09 04:28:27 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't enqueue a background job when retry is disabled" do
|
2020-07-24 17:16:52 +08:00
|
|
|
expect_not_enqueued_with(job: :process_email, args: { mail: mail }) do
|
|
|
|
expect { Email::Processor.process!(mail, retry_on_rate_limit: false) }.to raise_error(
|
|
|
|
limit_exceeded,
|
|
|
|
)
|
|
|
|
end
|
2016-08-09 04:28:27 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "known error" do
|
2017-07-22 01:24:31 +08:00
|
|
|
let(:mail) { "From: #{from}\nTo: bar@foo.com" }
|
|
|
|
let(:mail2) { "From: #{from}\nTo: foo@foo.com" }
|
|
|
|
let(:mail3) { "From: #{from}\nTo: foobar@foo.com" }
|
|
|
|
|
|
|
|
it "only sends one rejection email per day" do
|
|
|
|
key = "rejection_email:#{[from]}:email_reject_empty:#{Date.today}"
|
2019-12-03 17:05:53 +08:00
|
|
|
Discourse.redis.expire(key, 0)
|
2017-07-22 01:24:31 +08:00
|
|
|
|
|
|
|
expect { Email::Processor.process!(mail) }.to change { EmailLog.count }.by(1)
|
|
|
|
|
2022-07-19 22:03:03 +08:00
|
|
|
expect { Email::Processor.process!(mail2) }.not_to change { EmailLog.count }
|
2017-07-22 01:24:31 +08:00
|
|
|
|
2017-07-24 21:17:42 +08:00
|
|
|
freeze_time(Date.today + 1)
|
|
|
|
|
|
|
|
key = "rejection_email:#{[from]}:email_reject_empty:#{Date.today}"
|
2019-12-03 17:05:53 +08:00
|
|
|
Discourse.redis.expire(key, 0)
|
2017-07-24 21:17:42 +08:00
|
|
|
|
|
|
|
expect { Email::Processor.process!(mail3) }.to change { EmailLog.count }.by(1)
|
2017-07-22 01:24:31 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "unrecognized error" do
|
2019-04-08 17:36:39 +08:00
|
|
|
let(:mail) do
|
|
|
|
"Date: Fri, 15 Jan 2016 00:12:43 +0100\nFrom: #{from}\nTo: bar@foo.com\nSubject: FOO BAR\n\nFoo foo bar bar?"
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2019-04-08 17:36:39 +08:00
|
|
|
let(:mail2) do
|
|
|
|
"Date: Fri, 15 Jan 2016 00:12:43 +0100\nFrom: #{from}\nTo: foo@foo.com\nSubject: BAR BAR\n\nBar bar bar bar?"
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2017-07-22 01:24:31 +08:00
|
|
|
|
|
|
|
it "sends a rejection email on an unrecognized error" do
|
2018-10-10 09:34:50 +08:00
|
|
|
begin
|
|
|
|
@orig_logger = Rails.logger
|
|
|
|
Rails.logger = @fake_logger = FakeLogger.new
|
2017-07-22 01:24:31 +08:00
|
|
|
|
2018-10-10 09:34:50 +08:00
|
|
|
Email::Processor.any_instance.stubs(:can_send_rejection_email?).returns(true)
|
|
|
|
Email::Receiver.any_instance.stubs(:process_internal).raises("boom")
|
|
|
|
|
|
|
|
Email::Processor.process!(mail)
|
|
|
|
|
2022-05-05 09:53:54 +08:00
|
|
|
errors = @fake_logger.errors
|
2018-10-10 09:34:50 +08:00
|
|
|
expect(errors.size).to eq(1)
|
|
|
|
expect(errors.first).to include("boom")
|
|
|
|
|
|
|
|
incoming_email = IncomingEmail.last
|
2022-03-03 21:28:13 +08:00
|
|
|
expect(incoming_email.error).to eq("RuntimeError")
|
2018-10-10 09:34:50 +08:00
|
|
|
expect(incoming_email.rejection_message).to be_present
|
|
|
|
|
|
|
|
expect(EmailLog.last.email_type).to eq("email_reject_unrecognized_error")
|
|
|
|
ensure
|
|
|
|
Rails.logger = @orig_logger
|
|
|
|
end
|
2017-07-22 01:24:31 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "sends more than one rejection email per day" do
|
|
|
|
Email::Receiver.any_instance.stubs(:process_internal).raises("boom")
|
|
|
|
key = "rejection_email:#{[from]}:email_reject_unrecognized_error:#{Date.today}"
|
2019-12-03 17:05:53 +08:00
|
|
|
Discourse.redis.expire(key, 0)
|
2017-07-22 01:24:31 +08:00
|
|
|
|
|
|
|
expect { Email::Processor.process!(mail) }.to change { EmailLog.count }.by(1)
|
|
|
|
|
|
|
|
expect { Email::Processor.process!(mail2) }.to change { EmailLog.count }.by(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "from reply to email address" do
|
2019-04-08 17:36:39 +08:00
|
|
|
let(:mail) do
|
|
|
|
"Date: Fri, 15 Jan 2016 00:12:43 +0100\nFrom: reply@bar.com\nTo: reply@bar.com\nSubject: FOO BAR\n\nFoo foo bar bar?"
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2018-05-23 16:04:45 +08:00
|
|
|
|
|
|
|
it "ignores the email" do
|
|
|
|
Email::Receiver
|
|
|
|
.any_instance
|
|
|
|
.stubs(:process_internal)
|
|
|
|
.raises(Email::Receiver::FromReplyByAddressError.new)
|
|
|
|
|
2022-07-19 22:03:03 +08:00
|
|
|
expect { Email::Processor.process!(mail) }.not_to change { EmailLog.count }
|
2018-05-23 16:04:45 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "mailinglist mirror" do
|
2017-11-17 21:48:48 +08:00
|
|
|
before do
|
|
|
|
SiteSetting.email_in = true
|
|
|
|
Fabricate(:mailinglist_mirror_category)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not send rejection email" do
|
|
|
|
Email::Receiver.any_instance.stubs(:process_internal).raises("boom")
|
|
|
|
|
|
|
|
email = <<~EMAIL
|
|
|
|
From: foo@example.com
|
|
|
|
To: list@example.com
|
|
|
|
Subject: Hello world
|
|
|
|
EMAIL
|
|
|
|
|
|
|
|
expect { Email::Processor.process!(email) }.to_not change { EmailLog.count }
|
|
|
|
end
|
|
|
|
end
|
2018-08-21 16:17:08 +08:00
|
|
|
|
|
|
|
describe "when replying to a post that is too old" do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:user) { Fabricate(:user, email: "discourse@bar.com") }
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:topic)
|
2022-10-25 15:29:09 +08:00
|
|
|
fab!(:post) { Fabricate(:post, topic: topic, created_at: 3.days.ago) }
|
|
|
|
let(:mail) do
|
|
|
|
file_from_fixtures("old_destination.eml", "emails")
|
|
|
|
.read
|
|
|
|
.gsub("424242", topic.id.to_s)
|
|
|
|
.gsub("123456", post.id.to_s)
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2022-10-25 15:29:09 +08:00
|
|
|
|
2018-08-21 16:17:08 +08:00
|
|
|
it "rejects the email with the right response" do
|
|
|
|
SiteSetting.disallow_reply_by_email_after_days = 2
|
|
|
|
processor = Email::Processor.new(mail)
|
|
|
|
processor.process!
|
|
|
|
|
|
|
|
rejection_raw = ActionMailer::Base.deliveries.first.body.to_s
|
|
|
|
|
|
|
|
expect(rejection_raw).to eq(
|
|
|
|
I18n.t(
|
|
|
|
"system_messages.email_reject_old_destination.text_body_template",
|
|
|
|
destination: '["reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com"]',
|
|
|
|
former_title: "Some Old Post",
|
|
|
|
short_url: "#{Discourse.base_url}/p/#{post.id}",
|
|
|
|
number_of_days: 2,
|
2023-01-09 19:18:21 +08:00
|
|
|
),
|
2018-08-21 16:17:08 +08:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2022-08-18 23:18:58 +08:00
|
|
|
|
|
|
|
describe "when group email recipients exceeds maximum_recipients_per_new_group_email site setting" do
|
|
|
|
let(:mail) { file_from_fixtures("cc.eml", "emails").read }
|
|
|
|
|
|
|
|
it "rejects the email with the right response" do
|
|
|
|
SiteSetting.maximum_recipients_per_new_group_email = 3
|
|
|
|
|
|
|
|
processor = Email::Processor.new(mail)
|
|
|
|
processor.process!
|
|
|
|
|
|
|
|
rejection_raw = ActionMailer::Base.deliveries.first.body.to_s
|
|
|
|
|
|
|
|
expect(rejection_raw).to eq(
|
|
|
|
I18n.t(
|
|
|
|
"system_messages.email_reject_too_many_recipients.text_body_template",
|
|
|
|
destination: '["someone@else.com"]',
|
|
|
|
former_title: "The more, the merrier",
|
|
|
|
max_recipients_count: 3,
|
|
|
|
base_url: Discourse.base_url,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2016-08-09 04:28:27 +08:00
|
|
|
end
|