2019-04-30 08:27:42 +08:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2015-10-11 17:41:23 +08:00
|
|
|
|
require 'rails_helper'
|
2013-06-11 03:33:37 +08:00
|
|
|
|
require 'email/sender'
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
2013-06-11 03:33:37 +08:00
|
|
|
|
describe Email::Sender do
|
2020-09-17 12:15:02 +08:00
|
|
|
|
before do
|
|
|
|
|
SiteSetting.secure_media_allow_embed_images_in_emails = false
|
|
|
|
|
end
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:post) { Fabricate(:post) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
2018-06-07 12:14:35 +08:00
|
|
|
|
context "disable_emails is enabled" do
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
|
fab!(:moderator) { Fabricate(:moderator) }
|
2018-06-07 12:14:35 +08:00
|
|
|
|
|
|
|
|
|
context "disable_emails is enabled for everyone" do
|
|
|
|
|
before { SiteSetting.disable_emails = "yes" }
|
|
|
|
|
|
|
|
|
|
it "doesn't deliver mail when mails are disabled" do
|
2019-03-22 05:57:09 +08:00
|
|
|
|
message = UserNotifications.email_login(moderator)
|
|
|
|
|
Email::Sender.new(message, :email_login).send
|
|
|
|
|
|
|
|
|
|
expect(ActionMailer::Base.deliveries).to eq([])
|
2018-06-07 12:14:35 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "delivers mail when mails are disabled but the email_type is admin_login" do
|
2019-03-22 05:57:09 +08:00
|
|
|
|
message = UserNotifications.admin_login(moderator)
|
2018-06-07 12:14:35 +08:00
|
|
|
|
Email::Sender.new(message, :admin_login).send
|
2019-03-22 05:57:09 +08:00
|
|
|
|
|
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to eq([moderator.email])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "delivers mail when mails are disabled but the email_type is test_message" do
|
|
|
|
|
message = TestMailer.send_test(moderator.email)
|
|
|
|
|
Email::Sender.new(message, :test_message).send
|
|
|
|
|
|
|
|
|
|
expect(ActionMailer::Base.deliveries.first.to).to eq([moderator.email])
|
2018-06-07 12:14:35 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "disable_emails is enabled for non-staff users" do
|
|
|
|
|
before { SiteSetting.disable_emails = "non-staff" }
|
|
|
|
|
|
2019-03-22 04:46:14 +08:00
|
|
|
|
it "doesn't deliver mail to normal user" do
|
|
|
|
|
Mail::Message.any_instance.expects(:deliver_now).never
|
2018-06-07 12:14:35 +08:00
|
|
|
|
message = Mail::Message.new(to: user.email, body: "hello")
|
2019-03-22 04:46:14 +08:00
|
|
|
|
expect(Email::Sender.new(message, :hello).send).to eq(nil)
|
2018-06-07 12:14:35 +08:00
|
|
|
|
end
|
2016-02-18 00:31:46 +08:00
|
|
|
|
|
2018-06-07 12:14:35 +08:00
|
|
|
|
it "delivers mail to staff user" do
|
|
|
|
|
Mail::Message.any_instance.expects(:deliver_now).once
|
|
|
|
|
message = Mail::Message.new(to: moderator.email, body: "hello")
|
|
|
|
|
Email::Sender.new(message, :hello).send
|
|
|
|
|
end
|
2020-10-08 11:52:17 +08:00
|
|
|
|
|
|
|
|
|
it "delivers mail to staff user when confirming new email if user is provided" do
|
|
|
|
|
Mail::Message.any_instance.expects(:deliver_now).once
|
|
|
|
|
Fabricate(:email_change_request, {
|
|
|
|
|
user: moderator,
|
|
|
|
|
new_email: "newemail@testmoderator.com",
|
|
|
|
|
old_email: moderator.email,
|
|
|
|
|
change_state: EmailChangeRequest.states[:authorizing_new]
|
|
|
|
|
})
|
|
|
|
|
message = Mail::Message.new(
|
|
|
|
|
to: "newemail@testmoderator.com", body: "hello"
|
|
|
|
|
)
|
|
|
|
|
Email::Sender.new(message, :confirm_new_email, moderator).send
|
|
|
|
|
end
|
2018-06-07 12:14:35 +08:00
|
|
|
|
end
|
2016-04-08 13:23:16 +08:00
|
|
|
|
end
|
|
|
|
|
|
2016-02-18 00:31:46 +08:00
|
|
|
|
it "doesn't deliver mail when the message is of type NullMail" do
|
|
|
|
|
Mail::Message.any_instance.expects(:deliver_now).never
|
|
|
|
|
message = ActionMailer::Base::NullMail.new
|
|
|
|
|
expect(Email::Sender.new(message, :hello).send).to eq(nil)
|
2014-08-23 17:07:37 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
|
it "doesn't deliver mail when the message is nil" do
|
2014-10-15 15:04:47 +08:00
|
|
|
|
Mail::Message.any_instance.expects(:deliver_now).never
|
2013-06-11 03:33:37 +08:00
|
|
|
|
Email::Sender.new(nil, :hello).send
|
2013-02-06 03:16:51 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "doesn't deliver when the to address is nil" do
|
|
|
|
|
message = Mail::Message.new(body: 'hello')
|
2014-10-15 15:04:47 +08:00
|
|
|
|
message.expects(:deliver_now).never
|
2013-06-11 03:33:37 +08:00
|
|
|
|
Email::Sender.new(message, :hello).send
|
2013-02-06 03:16:51 +08:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-14 00:17:59 +08:00
|
|
|
|
it "doesn't deliver when the to address uses the .invalid tld" do
|
|
|
|
|
message = Mail::Message.new(body: 'hello', to: 'myemail@example.invalid')
|
|
|
|
|
message.expects(:deliver_now).never
|
|
|
|
|
expect { Email::Sender.new(message, :hello).send }.
|
|
|
|
|
to change { SkippedEmailLog.where(reason_type: SkippedEmailLog.reason_types[:sender_message_to_invalid]).count }.by(1)
|
|
|
|
|
end
|
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
|
it "doesn't deliver when the body is nil" do
|
|
|
|
|
message = Mail::Message.new(to: 'eviltrout@test.domain')
|
2014-10-15 15:04:47 +08:00
|
|
|
|
message.expects(:deliver_now).never
|
2013-06-11 03:33:37 +08:00
|
|
|
|
Email::Sender.new(message, :hello).send
|
2013-02-06 03:16:51 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-07-08 23:48:40 +08:00
|
|
|
|
context "host_for" do
|
|
|
|
|
it "defaults to localhost" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(Email::Sender.host_for(nil)).to eq("localhost")
|
2013-07-03 02:13:46 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-07-08 23:48:40 +08:00
|
|
|
|
it "returns localhost for a weird host" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(Email::Sender.host_for("this is not a real host")).to eq("localhost")
|
2013-07-03 02:13:46 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-07-08 23:48:40 +08:00
|
|
|
|
it "parses hosts from urls" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(Email::Sender.host_for("http://meta.discourse.org")).to eq("meta.discourse.org")
|
2013-07-03 02:13:46 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-07-08 23:48:40 +08:00
|
|
|
|
it "downcases hosts" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(Email::Sender.host_for("http://ForumSite.com")).to eq("forumsite.com")
|
2013-07-03 02:13:46 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-07-08 23:48:40 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
|
context 'with a valid message' do
|
|
|
|
|
|
2013-06-13 22:56:16 +08:00
|
|
|
|
let(:reply_key) { "abcd" * 8 }
|
|
|
|
|
|
2013-02-26 00:42:20 +08:00
|
|
|
|
let(:message) do
|
2013-02-06 03:16:51 +08:00
|
|
|
|
message = Mail::Message.new to: 'eviltrout@test.domain',
|
|
|
|
|
body: '**hello**'
|
2014-10-15 15:04:47 +08:00
|
|
|
|
message.stubs(:deliver_now)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
message
|
|
|
|
|
end
|
|
|
|
|
|
2013-06-11 03:33:37 +08:00
|
|
|
|
let(:email_sender) { Email::Sender.new(message, :valid_type) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
|
|
it 'calls deliver' do
|
2014-10-15 15:04:47 +08:00
|
|
|
|
message.expects(:deliver_now).once
|
2013-02-06 03:16:51 +08:00
|
|
|
|
email_sender.send
|
|
|
|
|
end
|
|
|
|
|
|
2016-04-26 02:06:45 +08:00
|
|
|
|
context "doesn't add return_path when no plus addressing" do
|
|
|
|
|
before { SiteSetting.reply_by_email_address = '%{reply_key}@test.com' }
|
2016-04-18 15:13:41 +08:00
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should not set the return_path' do
|
|
|
|
|
email_sender.send
|
2016-04-26 02:06:45 +08:00
|
|
|
|
expect(message.header[:return_path].to_s).to eq("")
|
2016-12-13 09:59:38 +08:00
|
|
|
|
end
|
2016-04-18 15:13:41 +08:00
|
|
|
|
end
|
|
|
|
|
|
2016-04-26 02:06:45 +08:00
|
|
|
|
context "adds return_path with plus addressing" do
|
|
|
|
|
before { SiteSetting.reply_by_email_address = 'replies+%{reply_key}@test.com' }
|
2016-04-18 15:13:41 +08:00
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should set the return_path' do
|
|
|
|
|
email_sender.send
|
2016-04-26 02:06:45 +08:00
|
|
|
|
expect(message.header[:return_path].to_s).to eq("replies+verp-#{EmailLog.last.bounce_key}@test.com")
|
2016-12-13 09:59:38 +08:00
|
|
|
|
end
|
2016-04-18 15:13:41 +08:00
|
|
|
|
end
|
|
|
|
|
|
2014-10-09 02:09:21 +08:00
|
|
|
|
context "adds a List-ID header to identify the forum" do
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:category) { Fabricate(:category, name: 'Name With Space') }
|
|
|
|
|
fab!(:topic) { Fabricate(:topic, category: category) }
|
|
|
|
|
fab!(:post) { Fabricate(:post, topic: topic) }
|
2017-02-02 06:02:41 +08:00
|
|
|
|
|
2014-10-09 02:09:21 +08:00
|
|
|
|
before do
|
2017-02-02 06:02:41 +08:00
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
2015-10-21 02:30:06 +08:00
|
|
|
|
message.header['X-Discourse-Topic-Id'] = topic.id
|
2014-10-09 02:09:21 +08:00
|
|
|
|
end
|
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should add the right header' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
expect(message.header['List-ID']).to be_present
|
|
|
|
|
expect(message.header['List-ID'].to_s).to match('name-with-space')
|
|
|
|
|
end
|
2014-10-09 02:09:21 +08:00
|
|
|
|
end
|
2013-07-03 02:13:46 +08:00
|
|
|
|
|
2015-01-28 17:12:49 +08:00
|
|
|
|
context "adds a Message-ID header even when topic id is not present" do
|
2016-12-13 09:59:38 +08:00
|
|
|
|
|
|
|
|
|
it 'should add the right header' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
expect(message.header['Message-ID']).to be_present
|
|
|
|
|
end
|
2015-01-28 17:12:49 +08:00
|
|
|
|
end
|
|
|
|
|
|
2014-10-09 03:57:30 +08:00
|
|
|
|
context "adds Precedence header" do
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:topic) { Fabricate(:topic) }
|
|
|
|
|
fab!(:post) { Fabricate(:post, topic: topic) }
|
2017-02-02 06:02:41 +08:00
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
|
|
|
|
message.header['X-Discourse-Topic-Id'] = topic.id
|
2014-10-09 03:57:30 +08:00
|
|
|
|
end
|
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should add the right header' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
expect(message.header['Precedence']).to be_present
|
|
|
|
|
end
|
2014-10-09 03:57:30 +08:00
|
|
|
|
end
|
|
|
|
|
|
2015-01-29 19:53:10 +08:00
|
|
|
|
context "removes custom Discourse headers from topic notification mails" do
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:topic) { Fabricate(:topic) }
|
|
|
|
|
fab!(:post) { Fabricate(:post, topic: topic) }
|
2017-02-02 06:02:41 +08:00
|
|
|
|
|
2015-01-29 19:53:10 +08:00
|
|
|
|
before do
|
2017-02-02 06:02:41 +08:00
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
|
|
|
|
message.header['X-Discourse-Topic-Id'] = topic.id
|
2015-01-29 19:53:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should remove the right headers' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
expect(message.header['X-Discourse-Topic-Id']).not_to be_present
|
|
|
|
|
expect(message.header['X-Discourse-Post-Id']).not_to be_present
|
|
|
|
|
expect(message.header['X-Discourse-Reply-Key']).not_to be_present
|
|
|
|
|
end
|
2015-01-29 19:53:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "removes custom Discourse headers from digest/registration/other mails" do
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should remove the right headers' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
expect(message.header['X-Discourse-Topic-Id']).not_to be_present
|
|
|
|
|
expect(message.header['X-Discourse-Post-Id']).not_to be_present
|
|
|
|
|
expect(message.header['X-Discourse-Reply-Key']).not_to be_present
|
|
|
|
|
end
|
2015-01-29 19:53:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2016-11-28 21:18:02 +08:00
|
|
|
|
context "email threading" do
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:topic) { Fabricate(:topic) }
|
2016-11-28 21:18:02 +08:00
|
|
|
|
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:post_1) { Fabricate(:post, topic: topic, post_number: 1) }
|
|
|
|
|
fab!(:post_2) { Fabricate(:post, topic: topic, post_number: 2) }
|
|
|
|
|
fab!(:post_3) { Fabricate(:post, topic: topic, post_number: 3) }
|
|
|
|
|
fab!(:post_4) { Fabricate(:post, topic: topic, post_number: 4) }
|
2016-11-28 21:18:02 +08:00
|
|
|
|
|
2017-02-02 06:02:41 +08:00
|
|
|
|
let!(:post_reply_1_4) { PostReply.create(post: post_1, reply: post_4) }
|
|
|
|
|
let!(:post_reply_2_4) { PostReply.create(post: post_2, reply: post_4) }
|
|
|
|
|
let!(:post_reply_3_4) { PostReply.create(post: post_3, reply: post_4) }
|
2016-11-28 21:18:02 +08:00
|
|
|
|
|
2017-02-02 06:02:41 +08:00
|
|
|
|
before { message.header['X-Discourse-Topic-Id'] = topic.id }
|
2016-11-28 21:18:02 +08:00
|
|
|
|
|
|
|
|
|
it "doesn't set the 'In-Reply-To' and 'References' headers on the first post" do
|
|
|
|
|
message.header['X-Discourse-Post-Id'] = post_1.id
|
|
|
|
|
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
2017-02-02 06:02:41 +08:00
|
|
|
|
expect(message.header['Message-Id'].to_s).to eq("<topic/#{topic.id}@test.localhost>")
|
2016-11-28 21:18:02 +08:00
|
|
|
|
expect(message.header['In-Reply-To'].to_s).to be_blank
|
|
|
|
|
expect(message.header['References'].to_s).to be_blank
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "sets the 'In-Reply-To' header to the topic by default" do
|
|
|
|
|
message.header['X-Discourse-Post-Id'] = post_2.id
|
|
|
|
|
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
expect(message.header['Message-Id'].to_s).to eq("<topic/#{topic.id}/#{post_2.id}@test.localhost>")
|
|
|
|
|
expect(message.header['In-Reply-To'].to_s).to eq("<topic/#{topic.id}@test.localhost>")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "sets the 'In-Reply-To' header to the newest replied post" do
|
2017-02-02 06:02:41 +08:00
|
|
|
|
message.header['X-Discourse-Post-Id'] = post_4.id
|
2016-11-28 21:18:02 +08:00
|
|
|
|
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
2017-02-02 06:02:41 +08:00
|
|
|
|
expect(message.header['Message-Id'].to_s).to eq("<topic/#{topic.id}/#{post_4.id}@test.localhost>")
|
|
|
|
|
expect(message.header['In-Reply-To'].to_s).to eq("<topic/#{topic.id}/#{post_3.id}@test.localhost>")
|
2016-11-28 21:18:02 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "sets the 'References' header to the topic and all replied posts" do
|
2017-02-02 06:02:41 +08:00
|
|
|
|
message.header['X-Discourse-Post-Id'] = post_4.id
|
2016-11-28 21:18:02 +08:00
|
|
|
|
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
references = [
|
2018-02-22 18:17:49 +08:00
|
|
|
|
"<topic/#{topic.id}@test.localhost>",
|
2017-02-02 06:02:41 +08:00
|
|
|
|
"<topic/#{topic.id}/#{post_3.id}@test.localhost>",
|
2016-11-28 21:18:02 +08:00
|
|
|
|
"<topic/#{topic.id}/#{post_2.id}@test.localhost>",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
expect(message.header['References'].to_s).to eq(references.join(" "))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "uses the incoming_email message_id when available" do
|
2017-02-02 06:02:41 +08:00
|
|
|
|
topic_incoming_email = IncomingEmail.create(topic: topic, post: post_1, message_id: "foo@bar")
|
|
|
|
|
post_2_incoming_email = IncomingEmail.create(topic: topic, post: post_2, message_id: "bar@foo")
|
|
|
|
|
post_4_incoming_email = IncomingEmail.create(topic: topic, post: post_4, message_id: "wat@wat")
|
|
|
|
|
|
2016-11-28 21:18:02 +08:00
|
|
|
|
message.header['X-Discourse-Post-Id'] = post_4.id
|
|
|
|
|
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
2017-02-02 06:02:41 +08:00
|
|
|
|
expect(message.header['Message-Id'].to_s).to eq("<#{post_4_incoming_email.message_id}>")
|
|
|
|
|
|
|
|
|
|
references = [
|
2018-02-22 18:17:49 +08:00
|
|
|
|
"<#{topic_incoming_email.message_id}>",
|
2017-02-02 06:02:41 +08:00
|
|
|
|
"<topic/#{topic.id}/#{post_3.id}@test.localhost>",
|
|
|
|
|
"<#{post_2_incoming_email.message_id}>",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
expect(message.header['References'].to_s).to eq(references.join(" "))
|
2016-11-28 21:18:02 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
2016-10-30 18:38:55 +08:00
|
|
|
|
context "merges custom mandrill header" do
|
|
|
|
|
before do
|
|
|
|
|
ActionMailer::Base.smtp_settings[:address] = "smtp.mandrillapp.com"
|
|
|
|
|
message.header['X-MC-Metadata'] = { foo: "bar" }.to_json
|
|
|
|
|
end
|
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should set the right header' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
expect(message.header['X-MC-Metadata'].to_s).to match(message.message_id)
|
|
|
|
|
end
|
2016-10-30 18:38:55 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "merges custom sparkpost header" do
|
|
|
|
|
before do
|
|
|
|
|
ActionMailer::Base.smtp_settings[:address] = "smtp.sparkpostmail.com"
|
|
|
|
|
message.header['X-MSYS-API'] = { foo: "bar" }.to_json
|
|
|
|
|
end
|
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should set the right header' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
expect(message.header['X-MSYS-API'].to_s).to match(message.message_id)
|
|
|
|
|
end
|
2016-10-30 18:38:55 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
|
context 'email logs' do
|
2013-06-13 22:56:16 +08:00
|
|
|
|
let(:email_log) { EmailLog.last }
|
|
|
|
|
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should create the right log' do
|
2018-07-18 16:28:44 +08:00
|
|
|
|
expect do
|
|
|
|
|
email_sender.send
|
|
|
|
|
end.to_not change { PostReplyKey.count }
|
2016-12-13 09:59:38 +08:00
|
|
|
|
|
|
|
|
|
expect(email_log).to be_present
|
|
|
|
|
expect(email_log.email_type).to eq('valid_type')
|
|
|
|
|
expect(email_log.to_address).to eq('eviltrout@test.domain')
|
|
|
|
|
expect(email_log.user_id).to be_blank
|
|
|
|
|
end
|
2021-06-15 09:29:46 +08:00
|
|
|
|
|
|
|
|
|
context 'when the email is sent using group SMTP credentials' do
|
|
|
|
|
let(:reply) { Fabricate(:post, topic: post.topic, reply_to_user: post.user, reply_to_post_number: post.post_number) }
|
|
|
|
|
let(:notification) { Fabricate(:posted_notification, user: post.user, post: reply) }
|
|
|
|
|
let(:message) do
|
|
|
|
|
UserNotifications.user_private_message(
|
|
|
|
|
post.user,
|
|
|
|
|
post: reply,
|
|
|
|
|
notification_type: notification.notification_type,
|
|
|
|
|
notification_data_hash: notification.data_hash
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
let(:group) { Fabricate(:smtp_group) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
SiteSetting.enable_smtp = true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'adds the group id to the email log' do
|
|
|
|
|
TopicAllowedGroup.create(topic: post.topic, group: group)
|
|
|
|
|
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
expect(email_log).to be_present
|
|
|
|
|
expect(email_log.email_type).to eq('valid_type')
|
|
|
|
|
expect(email_log.to_address).to eq(post.user.email)
|
|
|
|
|
expect(email_log.user_id).to be_blank
|
|
|
|
|
expect(email_log.smtp_group_id).to eq(group.id)
|
|
|
|
|
end
|
2021-06-18 12:36:17 +08:00
|
|
|
|
|
|
|
|
|
it "does not add any of the mailing list headers" do
|
|
|
|
|
TopicAllowedGroup.create(topic: post.topic, group: group)
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
expect(message.header['List-ID']).to eq(nil)
|
|
|
|
|
expect(message.header['List-Post']).to eq(nil)
|
|
|
|
|
expect(message.header['List-Archive']).to eq(nil)
|
|
|
|
|
expect(message.header['Precedence']).to eq(nil)
|
|
|
|
|
end
|
2021-06-15 09:29:46 +08:00
|
|
|
|
end
|
2013-06-13 22:56:16 +08:00
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
2013-06-14 06:11:10 +08:00
|
|
|
|
context "email log with a post id and topic id" do
|
2018-07-18 16:28:44 +08:00
|
|
|
|
let(:topic) { post.topic }
|
2017-02-02 06:02:41 +08:00
|
|
|
|
|
2013-06-14 06:11:10 +08:00
|
|
|
|
before do
|
2017-02-02 06:02:41 +08:00
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
|
|
|
|
message.header['X-Discourse-Topic-Id'] = topic.id
|
2013-06-14 06:11:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:email_log) { EmailLog.last }
|
2016-12-13 09:59:38 +08:00
|
|
|
|
|
|
|
|
|
it 'should create the right log' do
|
|
|
|
|
email_sender.send
|
2017-02-02 06:02:41 +08:00
|
|
|
|
expect(email_log.post_id).to eq(post.id)
|
2018-07-18 10:21:54 +08:00
|
|
|
|
expect(email_log.topic.id).to eq(topic.id)
|
2016-12-13 09:59:38 +08:00
|
|
|
|
end
|
2013-06-14 06:11:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2013-06-13 22:56:16 +08:00
|
|
|
|
context 'email parts' do
|
2016-12-13 09:59:38 +08:00
|
|
|
|
it 'should contain the right message' do
|
|
|
|
|
email_sender.send
|
|
|
|
|
|
|
|
|
|
expect(message).to be_multipart
|
|
|
|
|
expect(message.text_part.content_type).to eq('text/plain; charset=UTF-8')
|
|
|
|
|
expect(message.html_part.content_type).to eq('text/html; charset=UTF-8')
|
|
|
|
|
expect(message.html_part.body.to_s).to match("<p><strong>hello</strong></p>")
|
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-07-25 20:04:00 +08:00
|
|
|
|
context "with attachments" do
|
|
|
|
|
fab!(:small_pdf) do
|
|
|
|
|
SiteSetting.authorized_extensions = 'pdf'
|
|
|
|
|
UploadCreator.new(file_from_fixtures("small.pdf", "pdf"), "small.pdf")
|
|
|
|
|
.create_for(Discourse.system_user.id)
|
|
|
|
|
end
|
|
|
|
|
fab!(:large_pdf) do
|
|
|
|
|
SiteSetting.authorized_extensions = 'pdf'
|
|
|
|
|
UploadCreator.new(file_from_fixtures("large.pdf", "pdf"), "large.pdf")
|
|
|
|
|
.create_for(Discourse.system_user.id)
|
|
|
|
|
end
|
|
|
|
|
fab!(:csv_file) do
|
|
|
|
|
SiteSetting.authorized_extensions = 'csv'
|
|
|
|
|
UploadCreator.new(file_from_fixtures("words.csv", "csv"), "words.csv")
|
|
|
|
|
.create_for(Discourse.system_user.id)
|
|
|
|
|
end
|
|
|
|
|
fab!(:image) do
|
|
|
|
|
SiteSetting.authorized_extensions = 'png'
|
|
|
|
|
UploadCreator.new(file_from_fixtures("logo.png", "images"), "logo.png")
|
|
|
|
|
.create_for(Discourse.system_user.id)
|
|
|
|
|
end
|
|
|
|
|
fab!(:post) { Fabricate(:post) }
|
|
|
|
|
fab!(:reply) do
|
|
|
|
|
raw = <<~RAW
|
2020-09-29 12:10:57 +08:00
|
|
|
|
Hello world! It’s a great day!
|
2019-07-25 22:34:46 +08:00
|
|
|
|
#{UploadMarkdown.new(small_pdf).attachment_markdown}
|
|
|
|
|
#{UploadMarkdown.new(large_pdf).attachment_markdown}
|
|
|
|
|
#{UploadMarkdown.new(image).image_markdown}
|
|
|
|
|
#{UploadMarkdown.new(csv_file).attachment_markdown}
|
2019-07-25 20:04:00 +08:00
|
|
|
|
RAW
|
|
|
|
|
reply = Fabricate(:post, raw: raw, topic: post.topic, user: Fabricate(:user))
|
|
|
|
|
reply.link_post_uploads
|
|
|
|
|
reply
|
|
|
|
|
end
|
|
|
|
|
fab!(:notification) { Fabricate(:posted_notification, user: post.user, post: reply) }
|
|
|
|
|
let(:message) do
|
|
|
|
|
UserNotifications.user_posted(
|
|
|
|
|
post.user,
|
|
|
|
|
post: reply,
|
|
|
|
|
notification_type: notification.notification_type,
|
|
|
|
|
notification_data_hash: notification.data_hash
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds only non-image uploads as attachments to the email" do
|
|
|
|
|
SiteSetting.email_total_attachment_size_limit_kb = 10_000
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
|
|
|
|
|
expect(message.attachments.length).to eq(3)
|
|
|
|
|
expect(message.attachments.map(&:filename))
|
|
|
|
|
.to contain_exactly(*[small_pdf, large_pdf, csv_file].map(&:original_filename))
|
|
|
|
|
end
|
|
|
|
|
|
2020-09-10 07:50:16 +08:00
|
|
|
|
context "when secure media enabled" do
|
|
|
|
|
before do
|
2020-09-14 19:32:25 +08:00
|
|
|
|
setup_s3
|
2020-11-02 07:52:21 +08:00
|
|
|
|
store = stub_s3_store
|
2020-09-14 19:32:25 +08:00
|
|
|
|
|
2020-09-10 07:50:16 +08:00
|
|
|
|
SiteSetting.secure_media = true
|
|
|
|
|
SiteSetting.login_required = true
|
|
|
|
|
SiteSetting.email_total_attachment_size_limit_kb = 14_000
|
|
|
|
|
SiteSetting.secure_media_max_email_embed_image_size_kb = 5_000
|
|
|
|
|
|
|
|
|
|
Jobs.run_immediately!
|
|
|
|
|
Jobs::PullHotlinkedImages.any_instance.expects(:execute)
|
|
|
|
|
FileStore::S3Store.any_instance.expects(:has_been_uploaded?).returns(true).at_least_once
|
|
|
|
|
CookedPostProcessor.any_instance.stubs(:get_size).returns([244, 66])
|
|
|
|
|
|
2020-11-02 07:52:21 +08:00
|
|
|
|
@secure_image_file = file_from_fixtures("logo.png", "images")
|
|
|
|
|
@secure_image = UploadCreator.new(@secure_image_file, "logo.png")
|
2020-09-10 07:50:16 +08:00
|
|
|
|
.create_for(Discourse.system_user.id)
|
2021-01-29 07:03:44 +08:00
|
|
|
|
@secure_image.update_secure_status(override: true)
|
2020-09-10 07:50:16 +08:00
|
|
|
|
@secure_image.update(access_control_post_id: reply.id)
|
|
|
|
|
reply.update(raw: reply.raw + "\n" + "#{UploadMarkdown.new(@secure_image).image_markdown}")
|
|
|
|
|
reply.rebake!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not attach images when embedding them is not allowed" do
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.attachments.length).to eq(3)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "when embedding secure images in email is allowed" do
|
|
|
|
|
before do
|
|
|
|
|
SiteSetting.secure_media_allow_embed_images_in_emails = true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not attach images that are not marked as secure" do
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.attachments.length).to eq(4)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not embed images that are too big" do
|
|
|
|
|
SiteSetting.secure_media_max_email_embed_image_size_kb = 1
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.attachments.length).to eq(3)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "uses the email styles to inline secure images and attaches the secure image upload to the email" do
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.attachments.length).to eq(4)
|
|
|
|
|
expect(message.attachments.map(&:filename))
|
|
|
|
|
.to contain_exactly(*[small_pdf, large_pdf, csv_file, @secure_image].map(&:original_filename))
|
2020-11-02 07:52:21 +08:00
|
|
|
|
expect(message.attachments["logo.png"].body.raw_source.force_encoding("UTF-8")).to eq(File.read(@secure_image_file))
|
2020-09-10 07:50:16 +08:00
|
|
|
|
expect(message.html_part.body).to include("cid:")
|
|
|
|
|
expect(message.html_part.body).to include("embedded-secure-image")
|
|
|
|
|
expect(message.attachments.length).to eq(4)
|
|
|
|
|
end
|
2020-09-29 12:10:57 +08:00
|
|
|
|
|
|
|
|
|
it "uses correct UTF-8 encoding for the body of the email" do
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.html_part.body).not_to include("Itâ\u0080\u0099s")
|
|
|
|
|
expect(message.html_part.body).to include("It’s")
|
|
|
|
|
expect(message.html_part.charset.downcase).to eq("utf-8")
|
|
|
|
|
end
|
2020-11-02 07:52:21 +08:00
|
|
|
|
|
|
|
|
|
context "when the uploaded secure image has an optimized image" do
|
|
|
|
|
let!(:optimized) { Fabricate(:optimized_image, upload: @secure_image) }
|
2020-11-23 09:16:08 +08:00
|
|
|
|
let!(:optimized_image_file) { file_from_fixtures("smallest.png", "images") }
|
2020-11-02 07:52:21 +08:00
|
|
|
|
|
2020-11-23 09:16:08 +08:00
|
|
|
|
before do
|
2021-05-27 23:42:25 +08:00
|
|
|
|
url = Discourse.store.store_optimized_image(optimized_image_file, optimized)
|
|
|
|
|
optimized.update(url: Discourse.store.absolute_base_url + '/' + url)
|
2020-11-02 07:52:21 +08:00
|
|
|
|
Discourse.store.cache_file(optimized_image_file, File.basename("#{optimized.sha1}.png"))
|
2020-11-23 09:16:08 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "uses the email styles and the optimized image to inline secure images and attaches the secure image upload to the email" do
|
2020-11-02 07:52:21 +08:00
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.attachments.length).to eq(4)
|
|
|
|
|
expect(message.attachments.map(&:filename))
|
|
|
|
|
.to contain_exactly(*[small_pdf, large_pdf, csv_file, @secure_image].map(&:original_filename))
|
|
|
|
|
expect(message.attachments["logo.png"].body.raw_source.force_encoding("UTF-8")).to eq(File.read(optimized_image_file))
|
|
|
|
|
expect(message.html_part.body).to include("cid:")
|
|
|
|
|
expect(message.html_part.body).to include("embedded-secure-image")
|
2020-11-23 09:16:08 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "uses the optimized image size in the max size limit calculation, not the original image size" do
|
|
|
|
|
SiteSetting.email_total_attachment_size_limit_kb = 45
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
2020-11-02 07:52:21 +08:00
|
|
|
|
expect(message.attachments.length).to eq(4)
|
2020-11-23 09:16:08 +08:00
|
|
|
|
expect(message.attachments["logo.png"].body.raw_source.force_encoding("UTF-8")).to eq(File.read(optimized_image_file))
|
2020-11-02 07:52:21 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2020-09-10 07:50:16 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds only non-image uploads as attachments to the email and leaves the image intact with original source" do
|
|
|
|
|
SiteSetting.email_total_attachment_size_limit_kb = 10_000
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
|
|
|
|
|
expect(message.attachments.length).to eq(3)
|
|
|
|
|
expect(message.attachments.map(&:filename))
|
|
|
|
|
.to contain_exactly(*[small_pdf, large_pdf, csv_file].map(&:original_filename))
|
|
|
|
|
expect(message.html_part.body).to include("<img src=\"#{Discourse.base_url}#{image.url}\"")
|
|
|
|
|
end
|
|
|
|
|
|
2019-07-25 20:04:00 +08:00
|
|
|
|
it "respects the size limit and attaches only files that fit into the max email size" do
|
|
|
|
|
SiteSetting.email_total_attachment_size_limit_kb = 40
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
|
|
|
|
|
expect(message.attachments.length).to eq(2)
|
|
|
|
|
expect(message.attachments.map(&:filename))
|
|
|
|
|
.to contain_exactly(*[small_pdf, csv_file].map(&:original_filename))
|
|
|
|
|
end
|
2020-03-12 18:31:16 +08:00
|
|
|
|
|
|
|
|
|
it "structures the email as a multipart/mixed with a multipart/alternative first part" do
|
|
|
|
|
SiteSetting.email_total_attachment_size_limit_kb = 10_000
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
|
|
|
|
|
expect(message.content_type).to start_with("multipart/mixed")
|
|
|
|
|
expect(message.parts.size).to eq(4)
|
|
|
|
|
expect(message.parts[0].content_type).to start_with("multipart/alternative")
|
|
|
|
|
expect(message.parts[0].parts.size).to eq(2)
|
|
|
|
|
end
|
2020-09-29 12:10:57 +08:00
|
|
|
|
|
|
|
|
|
it "uses correct UTF-8 encoding for the body of the email" do
|
|
|
|
|
Email::Sender.new(message, :valid_type).send
|
|
|
|
|
expect(message.html_part.body).not_to include("Itâ\u0080\u0099s")
|
|
|
|
|
expect(message.html_part.body).to include("It’s")
|
|
|
|
|
expect(message.html_part.charset.downcase).to eq("utf-8")
|
|
|
|
|
end
|
2019-07-25 20:04:00 +08:00
|
|
|
|
end
|
|
|
|
|
|
2018-08-22 19:13:58 +08:00
|
|
|
|
context 'with a deleted post' do
|
|
|
|
|
|
|
|
|
|
it 'should skip sending the email' do
|
|
|
|
|
post = Fabricate(:post, deleted_at: 1.day.ago)
|
|
|
|
|
|
|
|
|
|
message = Mail::Message.new to: 'disc@ourse.org', body: 'some content'
|
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
|
|
|
|
message.header['X-Discourse-Topic-Id'] = post.topic_id
|
|
|
|
|
message.expects(:deliver_now).never
|
|
|
|
|
|
|
|
|
|
email_sender = Email::Sender.new(message, :valid_type)
|
|
|
|
|
expect { email_sender.send }.to change { SkippedEmailLog.count }
|
|
|
|
|
|
|
|
|
|
log = SkippedEmailLog.last
|
|
|
|
|
expect(log.reason_type).to eq(SkippedEmailLog.reason_types[:sender_post_deleted])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
2020-03-13 08:04:15 +08:00
|
|
|
|
context 'with a deleted topic' do
|
|
|
|
|
|
|
|
|
|
it 'should skip sending the email' do
|
|
|
|
|
post = Fabricate(:post, topic: Fabricate(:topic, deleted_at: 1.day.ago))
|
|
|
|
|
|
|
|
|
|
message = Mail::Message.new to: 'disc@ourse.org', body: 'some content'
|
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
|
|
|
|
message.header['X-Discourse-Topic-Id'] = post.topic_id
|
|
|
|
|
message.expects(:deliver_now).never
|
|
|
|
|
|
|
|
|
|
email_sender = Email::Sender.new(message, :valid_type)
|
|
|
|
|
expect { email_sender.send }.to change { SkippedEmailLog.count }
|
|
|
|
|
|
|
|
|
|
log = SkippedEmailLog.last
|
|
|
|
|
expect(log.reason_type).to eq(SkippedEmailLog.reason_types[:sender_topic_deleted])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
|
context 'with a user' do
|
2013-02-26 00:42:20 +08:00
|
|
|
|
let(:message) do
|
2013-02-06 03:16:51 +08:00
|
|
|
|
message = Mail::Message.new to: 'eviltrout@test.domain', body: 'test body'
|
2014-10-15 15:04:47 +08:00
|
|
|
|
message.stubs(:deliver_now)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
message
|
|
|
|
|
end
|
|
|
|
|
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:user) { Fabricate(:user) }
|
2013-06-11 03:33:37 +08:00
|
|
|
|
let(:email_sender) { Email::Sender.new(message, :valid_type, user) }
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
email_sender.send
|
|
|
|
|
@email_log = EmailLog.last
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'should have the current user_id' do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(@email_log.user_id).to eq(user.id)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
end
|
|
|
|
|
|
2018-07-18 16:28:44 +08:00
|
|
|
|
describe "post reply keys" do
|
2019-05-07 11:12:20 +08:00
|
|
|
|
fab!(:post) { Fabricate(:post) }
|
2018-07-18 16:28:44 +08:00
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
message.header['X-Discourse-Post-Id'] = post.id
|
|
|
|
|
message.header['Reply-To'] = "test-%{reply_key}@test.com"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe 'when allow reply by email header is not present' do
|
|
|
|
|
it 'should not create a post reply key' do
|
|
|
|
|
expect { email_sender.send }.to_not change { PostReplyKey.count }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe 'when allow reply by email header is present' do
|
|
|
|
|
let(:header) { Email::MessageBuilder::ALLOW_REPLY_BY_EMAIL_HEADER }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
message.header[header] = "test-%{reply_key}@test.com"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'should create a post reply key' do
|
|
|
|
|
expect { email_sender.send }.to change { PostReplyKey.count }.by(1)
|
|
|
|
|
post_reply_key = PostReplyKey.last
|
|
|
|
|
|
|
|
|
|
expect(message.header['Reply-To'].value).to eq(
|
|
|
|
|
"test-#{post_reply_key.reply_key}@test.com"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(message.header[header]).to eq(nil)
|
|
|
|
|
expect(post_reply_key.user_id).to eq(user.id)
|
|
|
|
|
expect(post_reply_key.post_id).to eq(post.id)
|
|
|
|
|
expect { email_sender.send }.to change { PostReplyKey.count }.by(0)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|