2019-04-29 20:27:42 -04:00
# frozen_string_literal: true
2013-06-10 15:33:37 -04:00
require 'email/sender'
2013-02-05 14:16:51 -05:00
2022-07-27 22:27:38 -04:00
RSpec . describe Email :: Sender do
2020-09-17 00:15:02 -04:00
before do
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads_allow_embed_images_in_emails = false
2020-09-17 00:15:02 -04:00
end
2019-05-06 23:12:20 -04:00
fab! ( :post ) { Fabricate ( :post ) }
2022-06-14 20:28:30 -04:00
let ( :mock_smtp_transaction_response ) { " 250 Ok: queued as 2l3Md07BObzB8kRyHZeoN0baSUAhzc7A-NviRioOr80=@mailhog.example " }
def stub_deliver_response ( message )
message . stubs ( :deliver! ) . returns (
Net :: SMTP :: Response . new ( " 250 " , mock_smtp_transaction_response )
)
end
2013-02-05 14:16:51 -05:00
2022-07-27 12:14:14 -04:00
context " when disable_emails is enabled " do
2019-05-06 23:12:20 -04:00
fab! ( :user ) { Fabricate ( :user ) }
fab! ( :moderator ) { Fabricate ( :moderator ) }
2018-06-07 00:14:35 -04:00
2022-07-27 12:14:14 -04:00
context " when disable_emails is enabled for everyone " do
2018-06-07 00:14:35 -04:00
before { SiteSetting . disable_emails = " yes " }
it " doesn't deliver mail when mails are disabled " do
2019-03-21 17:57:09 -04:00
message = UserNotifications . email_login ( moderator )
Email :: Sender . new ( message , :email_login ) . send
expect ( ActionMailer :: Base . deliveries ) . to eq ( [ ] )
2018-06-07 00:14:35 -04:00
end
it " delivers mail when mails are disabled but the email_type is admin_login " do
2019-03-21 17:57:09 -04:00
message = UserNotifications . admin_login ( moderator )
2018-06-07 00:14:35 -04:00
Email :: Sender . new ( message , :admin_login ) . send
2019-03-21 17:57:09 -04: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 00:14:35 -04:00
end
end
2022-07-27 12:14:14 -04:00
context " when disable_emails is enabled for non-staff users " do
2018-06-07 00:14:35 -04:00
before { SiteSetting . disable_emails = " non-staff " }
2019-03-21 16:46:14 -04:00
it " doesn't deliver mail to normal user " do
2022-06-14 20:28:30 -04:00
Mail :: Message . any_instance . expects ( :deliver! ) . never
2018-06-07 00:14:35 -04:00
message = Mail :: Message . new ( to : user . email , body : " hello " )
2022-06-14 20:28:30 -04:00
stub_deliver_response ( message )
2019-03-21 16:46:14 -04:00
expect ( Email :: Sender . new ( message , :hello ) . send ) . to eq ( nil )
2018-06-07 00:14:35 -04:00
end
2016-02-17 11:31:46 -05:00
2018-06-07 00:14:35 -04:00
it " delivers mail to staff user " do
2022-06-14 20:28:30 -04:00
Mail :: Message . any_instance . expects ( :deliver! ) . once
2018-06-07 00:14:35 -04:00
message = Mail :: Message . new ( to : moderator . email , body : " hello " )
Email :: Sender . new ( message , :hello ) . send
end
2020-10-07 23:52:17 -04:00
it " delivers mail to staff user when confirming new email if user is provided " do
2022-06-14 20:28:30 -04:00
Mail :: Message . any_instance . expects ( :deliver! ) . once
2020-10-07 23:52:17 -04:00
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 00:14:35 -04:00
end
2016-04-08 01:23:16 -04:00
end
2016-02-17 11:31:46 -05:00
it " doesn't deliver mail when the message is of type NullMail " do
2022-06-14 20:28:30 -04:00
Mail :: Message . any_instance . expects ( :deliver! ) . never
2016-02-17 11:31:46 -05:00
message = ActionMailer :: Base :: NullMail . new
expect ( Email :: Sender . new ( message , :hello ) . send ) . to eq ( nil )
2014-08-23 05:07:37 -04:00
end
2013-02-05 14:16:51 -05:00
it " doesn't deliver mail when the message is nil " do
2022-06-14 20:28:30 -04:00
Mail :: Message . any_instance . expects ( :deliver! ) . never
2013-06-10 15:33:37 -04:00
Email :: Sender . new ( nil , :hello ) . send
2013-02-05 14:16:51 -05:00
end
it " doesn't deliver when the to address is nil " do
message = Mail :: Message . new ( body : 'hello' )
2022-06-14 20:28:30 -04:00
message . expects ( :deliver! ) . never
2013-06-10 15:33:37 -04:00
Email :: Sender . new ( message , :hello ) . send
2013-02-05 14:16:51 -05:00
end
2019-03-13 12:17:59 -04:00
it " doesn't deliver when the to address uses the .invalid tld " do
message = Mail :: Message . new ( body : 'hello' , to : 'myemail@example.invalid' )
2022-06-14 20:28:30 -04:00
message . expects ( :deliver! ) . never
2019-03-13 12:17:59 -04:00
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-05 14:16:51 -05:00
it " doesn't deliver when the body is nil " do
message = Mail :: Message . new ( to : 'eviltrout@test.domain' )
2022-06-14 20:28:30 -04:00
message . expects ( :deliver! ) . never
2013-06-10 15:33:37 -04:00
Email :: Sender . new ( message , :hello ) . send
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
describe " .host_for " do
2013-07-08 11:48:40 -04:00
it " defaults to localhost " do
2015-01-09 11:34:37 -05:00
expect ( Email :: Sender . host_for ( nil ) ) . to eq ( " localhost " )
2013-07-02 14:13:46 -04:00
end
2013-07-08 11:48:40 -04:00
it " returns localhost for a weird host " do
2015-01-09 11:34:37 -05:00
expect ( Email :: Sender . host_for ( " this is not a real host " ) ) . to eq ( " localhost " )
2013-07-02 14:13:46 -04:00
end
2013-07-08 11:48:40 -04:00
it " parses hosts from urls " do
2015-01-09 11:34:37 -05:00
expect ( Email :: Sender . host_for ( " http://meta.discourse.org " ) ) . to eq ( " meta.discourse.org " )
2013-07-02 14:13:46 -04:00
end
2013-07-08 11:48:40 -04:00
it " downcases hosts " do
2015-01-09 11:34:37 -05:00
expect ( Email :: Sender . host_for ( " http://ForumSite.com " ) ) . to eq ( " forumsite.com " )
2013-07-02 14:13:46 -04:00
end
2013-07-08 11:48:40 -04:00
end
2013-02-05 14:16:51 -05:00
context 'with a valid message' do
2013-06-13 10:56:16 -04:00
let ( :reply_key ) { " abcd " * 8 }
2013-02-25 11:42:20 -05:00
let ( :message ) do
2022-02-02 19:36:32 -05:00
message = Mail :: Message . new (
to : 'eviltrout@test.domain' ,
body : '**hello**'
)
2022-06-14 20:28:30 -04:00
stub_deliver_response ( message )
2013-02-05 14:16:51 -05:00
message
end
2013-06-10 15:33:37 -04:00
let ( :email_sender ) { Email :: Sender . new ( message , :valid_type ) }
2013-02-05 14:16:51 -05:00
it 'calls deliver' do
2022-06-14 20:28:30 -04:00
message . expects ( :deliver! ) . once
2013-02-05 14:16:51 -05:00
email_sender . send
end
2022-07-27 12:14:14 -04:00
context " when no plus addressing " do
2016-04-25 14:06:45 -04:00
before { SiteSetting . reply_by_email_address = '%{reply_key}@test.com' }
2016-04-18 03:13:41 -04:00
2016-12-12 20:59:38 -05:00
it 'should not set the return_path' do
email_sender . send
2016-04-25 14:06:45 -04:00
expect ( message . header [ :return_path ] . to_s ) . to eq ( " " )
2016-12-12 20:59:38 -05:00
end
2016-04-18 03:13:41 -04:00
end
2022-07-27 12:14:14 -04:00
context " with plus addressing " do
2016-04-25 14:06:45 -04:00
before { SiteSetting . reply_by_email_address = 'replies+%{reply_key}@test.com' }
2016-04-18 03:13:41 -04:00
2016-12-12 20:59:38 -05:00
it 'should set the return_path' do
email_sender . send
2016-04-25 14:06:45 -04:00
expect ( message . header [ :return_path ] . to_s ) . to eq ( " replies+verp- #{ EmailLog . last . bounce_key } @test.com " )
2016-12-12 20:59:38 -05:00
end
2016-04-18 03:13:41 -04:00
end
2022-07-27 12:14:14 -04:00
context " when topic id is present " do
2019-05-06 23:12:20 -04:00
fab! ( :category ) { Fabricate ( :category , name : 'Name With Space' ) }
fab! ( :topic ) { Fabricate ( :topic , category : category ) }
fab! ( :post ) { Fabricate ( :post , topic : topic ) }
2017-02-01 17:02:41 -05:00
2014-10-08 14:09:21 -04:00
before do
2017-02-01 17:02:41 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post . id
2015-10-20 14:30:06 -04:00
message . header [ 'X-Discourse-Topic-Id' ] = topic . id
2014-10-08 14:09:21 -04:00
end
2016-12-12 20:59:38 -05: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-08 14:09:21 -04:00
end
2013-07-02 14:13:46 -04:00
2022-07-27 12:14:14 -04:00
context " when topic id is not present " do
2016-12-12 20:59:38 -05:00
it 'should add the right header' do
email_sender . send
expect ( message . header [ 'Message-ID' ] ) . to be_present
end
2015-01-28 04:12:49 -05:00
end
2022-07-27 12:14:14 -04:00
context " when reply_key is present " do
2021-10-11 13:57:42 -04:00
fab! ( :user ) { Fabricate ( :user ) }
let ( :email_sender ) { Email :: Sender . new ( message , :valid_type , user ) }
let ( :reply_key ) { PostReplyKey . find_by! ( post_id : post . id , user_id : user . id ) . reply_key }
before do
SiteSetting . reply_by_email_address = 'replies+%{reply_key}@test.com'
SiteSetting . email_custom_headers = 'Auto-Submitted: auto-generated|Mail-Reply-To: sender-name+%{reply_key}@domain.net'
message . header [ 'X-Discourse-Post-Id' ] = post . id
end
it 'replaces headers with reply_key if present' do
message . header [ Email :: MessageBuilder :: ALLOW_REPLY_BY_EMAIL_HEADER ] = 'test-%{reply_key}@test.com'
message . header [ 'Reply-To' ] = 'Test <test-%{reply_key}@test.com>'
message . header [ 'Auto-Submitted' ] = 'auto-generated'
message . header [ 'Mail-Reply-To' ] = 'sender-name+%{reply_key}@domain.net'
email_sender . send
expect ( message . header [ 'Reply-To' ] . to_s ) . to eq ( " Test <test- #{ reply_key } @test.com> " )
expect ( message . header [ 'Auto-Submitted' ] . to_s ) . to eq ( 'auto-generated' )
expect ( message . header [ 'Mail-Reply-To' ] . to_s ) . to eq ( " sender-name+ #{ reply_key } @domain.net " )
end
it 'removes headers with reply_key if absent' do
message . header [ 'Auto-Submitted' ] = 'auto-generated'
message . header [ 'Mail-Reply-To' ] = 'sender-name+%{reply_key}@domain.net'
email_sender . send
expect ( message . header [ 'Reply-To' ] . to_s ) . to eq ( '' )
expect ( message . header [ 'Auto-Submitted' ] . to_s ) . to eq ( 'auto-generated' )
expect ( message . header [ 'Mail-Reply-To' ] . to_s ) . to eq ( '' )
end
end
2022-07-27 12:14:14 -04:00
describe " adds Precedence header " do
2019-05-06 23:12:20 -04:00
fab! ( :topic ) { Fabricate ( :topic ) }
fab! ( :post ) { Fabricate ( :post , topic : topic ) }
2017-02-01 17:02:41 -05:00
before do
message . header [ 'X-Discourse-Post-Id' ] = post . id
message . header [ 'X-Discourse-Topic-Id' ] = topic . id
2014-10-08 15:57:30 -04:00
end
2016-12-12 20:59:38 -05:00
it 'should add the right header' do
email_sender . send
expect ( message . header [ 'Precedence' ] ) . to be_present
end
2014-10-08 15:57:30 -04:00
end
2022-07-27 12:14:14 -04:00
describe " removes custom Discourse headers from digest/registration/other mails " do
2016-12-12 20:59:38 -05: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 06:53:10 -05:00
end
2022-09-25 19:14:24 -04:00
describe " email threading " do
2019-05-06 23:12:20 -04:00
fab! ( :topic ) { Fabricate ( :topic ) }
2016-11-28 08:18:02 -05:00
2019-05-06 23:12:20 -04: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 ) }
2022-09-25 19:14:24 -04:00
fab! ( :post_5 ) { Fabricate ( :post , topic : topic , post_number : 5 ) }
fab! ( :post_6 ) { Fabricate ( :post , topic : topic , post_number : 6 ) }
2016-11-28 08:18:02 -05:00
2017-02-01 17:02:41 -05: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 ) }
2022-09-25 19:14:24 -04:00
let! ( :post_reply_4_5 ) { PostReply . create ( post : post_4 , reply : post_5 ) }
let! ( :post_reply_4_6 ) { PostReply . create ( post : post_4 , reply : post_6 ) }
let! ( :post_reply_5_6 ) { PostReply . create ( post : post_5 , reply : post_6 ) }
2016-11-28 08:18:02 -05:00
2021-12-05 19:34:39 -05:00
before do
message . header [ 'X-Discourse-Topic-Id' ] = topic . id
end
2016-11-28 08:18:02 -05:00
2022-09-25 19:14:24 -04:00
it " doesn't set References or In-Reply-To headers on the first post, only generates a Message-ID and saves it against the post " do
2016-11-28 08:18:02 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post_1 . id
email_sender . send
2022-09-25 19:14:24 -04:00
post_1 . reload
2016-11-28 08:18:02 -05:00
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'Message-Id' ] . to_s ) . to eq ( " <discourse/post/ #{ post_1 . id } @test.localhost> " )
expect ( post_1 . outbound_message_id ) . to eq ( " discourse/post/ #{ post_1 . id } @test.localhost " )
2016-11-28 08:18:02 -05:00
expect ( message . header [ 'In-Reply-To' ] . to_s ) . to be_blank
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'References' ] . to_s ) . to be_blank
2016-11-28 08:18:02 -05:00
end
2022-09-25 19:14:24 -04:00
it " uses the existing Message-ID header from the incoming email when sending the first post email " do
2022-02-02 19:36:32 -05:00
incoming = Fabricate (
:incoming_email ,
topic : topic ,
post : post_1 ,
message_id : " blah1234@someemailprovider.com " ,
created_via : IncomingEmail . created_via_types [ :handle_mail ]
)
2022-09-25 19:14:24 -04:00
post_1 . update! ( outbound_message_id : incoming . message_id )
2021-12-07 17:14:48 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post_1 . id
email_sender . send
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'Message-Id' ] . to_s ) . to eq ( " <blah1234@someemailprovider.com> " )
2021-12-07 17:14:48 -05:00
expect ( message . header [ 'In-Reply-To' ] . to_s ) . to be_blank
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'References' ] . to_s ) . to be_blank
2021-12-07 17:14:48 -05:00
end
2022-09-25 19:14:24 -04:00
it " if no post is directly replied to then the Message-ID of post 1 via outbound_message_id should be used " do
2016-11-28 08:18:02 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post_2 . id
email_sender . send
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'Message-Id' ] . to_s ) . to eq ( " <discourse/post/ #{ post_2 . id } @test.localhost> " )
expect ( message . header [ 'In-Reply-To' ] . to_s ) . to eq ( " <discourse/post/ #{ post_1 . id } @test.localhost> " )
expect ( message . header [ 'References' ] . to_s ) . to eq ( " <discourse/post/ #{ post_1 . id } @test.localhost> " )
2016-11-28 08:18:02 -05:00
end
2022-09-25 19:14:24 -04:00
it " sets the References header to the most recently created replied post, as well as the OP, if there are no other replies in the chain " do
2017-02-01 17:02:41 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post_4 . id
2016-11-28 08:18:02 -05:00
email_sender . send
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'Message-ID' ] . to_s ) . to eq ( " <discourse/post/ #{ post_4 . id } @test.localhost> " )
expect ( message . header [ 'References' ] . to_s ) . to eq ( " <discourse/post/ #{ post_1 . id } @test.localhost> <discourse/post/ #{ post_3 . id } @test.localhost> " )
end
it " sets the In-Reply-To header to all the posts that the post is connected to via PostReply " do
message . header [ 'X-Discourse-Post-Id' ] = post_6 . id
email_sender . send
expect ( message . header [ 'Message-ID' ] . to_s ) . to eq ( " <discourse/post/ #{ post_6 . id } @test.localhost> " )
expect ( message . header [ 'In-Reply-To' ] . to_s ) . to eq ( " <discourse/post/ #{ post_4 . id } @test.localhost> <discourse/post/ #{ post_5 . id } @test.localhost> " )
2016-11-28 08:18:02 -05:00
end
2022-09-25 19:14:24 -04:00
it " sets the In-Reply-To and References header to the most recently created replied post and includes the parents of that post in References, as well as the OP " do
2017-02-01 17:02:41 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post_4 . id
2022-09-25 19:14:24 -04:00
PostReply . create ( post : post_2 , reply : post_3 )
2016-11-28 08:18:02 -05:00
email_sender . send
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'Message-ID' ] . to_s ) . to eq ( " <discourse/post/ #{ post_4 . id } @test.localhost> " )
expect ( message . header [ 'In-Reply-To' ] . to_s ) . to eq ( " <discourse/post/ #{ post_1 . id } @test.localhost> <discourse/post/ #{ post_2 . id } @test.localhost> <discourse/post/ #{ post_3 . id } @test.localhost> " )
2016-11-28 08:18:02 -05:00
references = [
2022-09-25 19:14:24 -04:00
" <discourse/post/ #{ post_1 . id } @test.localhost> " ,
" <discourse/post/ #{ post_2 . id } @test.localhost> " ,
" <discourse/post/ #{ post_3 . id } @test.localhost> "
2016-11-28 08:18:02 -05:00
]
expect ( message . header [ 'References' ] . to_s ) . to eq ( references . join ( " " ) )
end
2022-09-25 19:14:24 -04:00
it " handles a complex reply tree to the OP for References, only using one Message-ID if there are multiple parents for a post " do
message . header [ 'X-Discourse-Post-Id' ] = post_6 . id
PostReply . create ( post : post_2 , reply : post_6 )
2016-11-28 08:18:02 -05:00
email_sender . send
2022-09-25 19:14:24 -04:00
expect ( message . header [ 'Message-ID' ] . to_s ) . to eq ( " <discourse/post/ #{ post_6 . id } @test.localhost> " )
expect ( message . header [ 'In-Reply-To' ] . to_s ) . to eq ( " <discourse/post/ #{ post_2 . id } @test.localhost> <discourse/post/ #{ post_4 . id } @test.localhost> <discourse/post/ #{ post_5 . id } @test.localhost> " )
2017-02-01 17:02:41 -05:00
references = [
2022-09-25 19:14:24 -04:00
" <discourse/post/ #{ post_1 . id } @test.localhost> " ,
" <discourse/post/ #{ post_3 . id } @test.localhost> " ,
" <discourse/post/ #{ post_4 . id } @test.localhost> " ,
" <discourse/post/ #{ post_5 . id } @test.localhost> "
2017-02-01 17:02:41 -05:00
]
expect ( message . header [ 'References' ] . to_s ) . to eq ( references . join ( " " ) )
2016-11-28 08:18:02 -05:00
end
end
2022-07-27 12:14:14 -04:00
describe " merges custom mandrill header " do
2016-10-30 06:38:55 -04:00
before do
ActionMailer :: Base . smtp_settings [ :address ] = " smtp.mandrillapp.com "
message . header [ 'X-MC-Metadata' ] = { foo : " bar " } . to_json
end
2016-12-12 20:59:38 -05: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 06:38:55 -04:00
end
2022-07-27 12:14:14 -04:00
describe " merges custom sparkpost header " do
2016-10-30 06:38:55 -04:00
before do
ActionMailer :: Base . smtp_settings [ :address ] = " smtp.sparkpostmail.com "
message . header [ 'X-MSYS-API' ] = { foo : " bar " } . to_json
end
2016-12-12 20:59:38 -05: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 06:38:55 -04:00
end
2022-07-27 12:14:14 -04:00
context 'with email logs' do
2013-06-13 10:56:16 -04:00
let ( :email_log ) { EmailLog . last }
2016-12-12 20:59:38 -05:00
it 'should create the right log' do
2018-07-18 04:28:44 -04:00
expect do
email_sender . send
end . to_not change { PostReplyKey . count }
2016-12-12 20:59:38 -05: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
2021-06-21 18:32:01 -04:00
expect ( email_log . raw ) . to eq ( nil )
2016-12-12 20:59:38 -05:00
end
2021-06-14 21:29:46 -04: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
2021-06-27 18:55:13 -04:00
GroupSmtpMailer . send_mail (
group ,
post . user . email ,
post
2021-06-14 21:29:46 -04:00
)
end
let ( :group ) { Fabricate ( :smtp_group ) }
before do
SiteSetting . enable_smtp = true
2022-06-14 20:28:30 -04:00
stub_deliver_response ( message )
2021-06-14 21:29:46 -04:00
end
2021-06-21 18:32:01 -04:00
it 'adds the group id and raw content to the email log' do
2021-06-14 21:29:46 -04:00
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 )
2021-06-21 18:32:01 -04:00
expect ( email_log . raw ) . to include ( " Hello world " )
2021-06-14 21:29:46 -04:00
end
2021-06-18 00:36:17 -04: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-Archive' ] ) . to eq ( nil )
expect ( message . header [ 'Precedence' ] ) . to eq ( nil )
2021-06-20 19:33:32 -04:00
expect ( message . header [ 'List-Unsubscribe' ] ) . to eq ( nil )
2021-06-18 00:36:17 -04:00
end
2021-11-23 19:54:01 -05:00
it " removes the Auto-Submitted header " do
TopicAllowedGroup . create! ( topic : post . topic , group : group )
email_sender . send
expect ( message . header [ 'Auto-Submitted' ] ) . to eq ( nil )
end
2021-06-14 21:29:46 -04:00
end
2013-06-13 10:56:16 -04:00
end
2013-02-05 14:16:51 -05:00
2022-07-27 12:14:14 -04:00
context " with email log with a post id and topic id " do
2018-07-18 04:28:44 -04:00
let ( :topic ) { post . topic }
2017-02-01 17:02:41 -05:00
2013-06-13 18:11:10 -04:00
before do
2017-02-01 17:02:41 -05:00
message . header [ 'X-Discourse-Post-Id' ] = post . id
message . header [ 'X-Discourse-Topic-Id' ] = topic . id
2013-06-13 18:11:10 -04:00
end
let ( :email_log ) { EmailLog . last }
2016-12-12 20:59:38 -05:00
it 'should create the right log' do
email_sender . send
2017-02-01 17:02:41 -05:00
expect ( email_log . post_id ) . to eq ( post . id )
2021-06-21 18:32:01 -04:00
expect ( email_log . topic_id ) . to eq ( topic . id )
2018-07-17 22:21:54 -04:00
expect ( email_log . topic . id ) . to eq ( topic . id )
2016-12-12 20:59:38 -05:00
end
2013-06-13 18:11:10 -04:00
end
2022-07-27 12:14:14 -04:00
context 'with email parts' do
2016-12-12 20:59:38 -05: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-05 14:16:51 -05:00
end
end
2019-07-25 08:04:00 -04: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 00:10:57 -04:00
Hello world! It ’ s a great day!
2019-07-25 10:34:46 -04: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 08:04:00 -04: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
2022-09-28 19:24:33 -04:00
context " when secure uploads enabled " do
2020-09-09 19:50:16 -04:00
before do
2020-09-14 07:32:25 -04:00
setup_s3
2020-11-01 18:52:21 -05:00
store = stub_s3_store
2020-09-14 07:32:25 -04:00
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads = true
2020-09-09 19:50:16 -04:00
SiteSetting . login_required = true
SiteSetting . email_total_attachment_size_limit_kb = 14_000
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads_max_email_embed_image_size_kb = 5_000
2020-09-09 19:50:16 -04:00
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-01 18:52:21 -05:00
@secure_image_file = file_from_fixtures ( " logo.png " , " images " )
@secure_image = UploadCreator . new ( @secure_image_file , " logo.png " )
2020-09-09 19:50:16 -04:00
. create_for ( Discourse . system_user . id )
2021-01-28 18:03:44 -05:00
@secure_image . update_secure_status ( override : true )
2020-09-09 19:50:16 -04: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
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads_allow_embed_images_in_emails = true
2020-09-09 19:50:16 -04:00
end
2021-08-03 11:58:34 -04:00
it " can inline images with duplicate names " do
@secure_image_2 = UploadCreator . new ( file_from_fixtures ( " logo-dev.png " , " images " ) , " logo.png " ) . create_for ( Discourse . system_user . id )
@secure_image_2 . update_secure_status ( override : true )
@secure_image_2 . update ( access_control_post_id : reply . id )
Jobs :: PullHotlinkedImages . any_instance . expects ( :execute )
reply . update ( raw : " #{ UploadMarkdown . new ( @secure_image ) . image_markdown } \n #{ UploadMarkdown . new ( @secure_image_2 ) . image_markdown } " )
reply . rebake!
Email :: Sender . new ( message , :valid_type ) . send
expect ( message . attachments . size ) . to eq ( 2 )
expect ( message . to_s . scan ( / cid:[ \ w \ -@.]+ / ) . length ) . to eq ( 2 )
expect ( message . to_s . scan ( / cid:[ \ w \ -@.]+ / ) . uniq . length ) . to eq ( 2 )
end
2020-09-09 19:50:16 -04:00
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
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads_max_email_embed_image_size_kb = 1
2020-09-09 19:50:16 -04:00
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-01 18:52:21 -05:00
expect ( message . attachments [ " logo.png " ] . body . raw_source . force_encoding ( " UTF-8 " ) ) . to eq ( File . read ( @secure_image_file ) )
2020-09-09 19:50:16 -04: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 00:10:57 -04: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-01 18:52:21 -05:00
context " when the uploaded secure image has an optimized image " do
let! ( :optimized ) { Fabricate ( :optimized_image , upload : @secure_image ) }
2020-11-22 20:16:08 -05:00
let! ( :optimized_image_file ) { file_from_fixtures ( " smallest.png " , " images " ) }
2020-11-01 18:52:21 -05:00
2020-11-22 20:16:08 -05:00
before do
2021-05-27 11:42:25 -04:00
url = Discourse . store . store_optimized_image ( optimized_image_file , optimized )
optimized . update ( url : Discourse . store . absolute_base_url + '/' + url )
2020-11-01 18:52:21 -05:00
Discourse . store . cache_file ( optimized_image_file , File . basename ( " #{ optimized . sha1 } .png " ) )
2020-11-22 20:16:08 -05: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-01 18:52:21 -05: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-22 20:16:08 -05: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-01 18:52:21 -05:00
expect ( message . attachments . length ) . to eq ( 4 )
2020-11-22 20:16:08 -05:00
expect ( message . attachments [ " logo.png " ] . body . raw_source . force_encoding ( " UTF-8 " ) ) . to eq ( File . read ( optimized_image_file ) )
2020-11-01 18:52:21 -05:00
end
end
2020-09-09 19:50:16 -04: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 08:04:00 -04: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 06:31:16 -04: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 00:10:57 -04: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 08:04:00 -04:00
end
2018-08-22 07:13:58 -04: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
2022-06-14 20:28:30 -04:00
message . expects ( :deliver! ) . never
2018-08-22 07:13:58 -04:00
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-12 20:04:15 -04: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
2022-06-14 20:28:30 -04:00
message . expects ( :deliver! ) . never
2020-03-12 20:04:15 -04:00
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-05 14:16:51 -05:00
context 'with a user' do
2013-02-25 11:42:20 -05:00
let ( :message ) do
2013-02-05 14:16:51 -05:00
message = Mail :: Message . new to : 'eviltrout@test.domain' , body : 'test body'
2022-06-14 20:28:30 -04:00
stub_deliver_response ( message )
2013-02-05 14:16:51 -05:00
message
end
2019-05-06 23:12:20 -04:00
fab! ( :user ) { Fabricate ( :user ) }
2013-06-10 15:33:37 -04:00
let ( :email_sender ) { Email :: Sender . new ( message , :valid_type , user ) }
2013-02-05 14:16:51 -05:00
before do
email_sender . send
@email_log = EmailLog . last
end
it 'should have the current user_id' do
2015-01-09 11:34:37 -05:00
expect ( @email_log . user_id ) . to eq ( user . id )
2013-02-05 14:16:51 -05:00
end
2022-06-14 20:28:30 -04:00
it 'should have the smtp_transaction_response message' do
expect ( @email_log . smtp_transaction_response ) . to eq ( mock_smtp_transaction_response )
end
2018-07-18 04:28:44 -04:00
describe " post reply keys " do
2019-05-06 23:12:20 -04:00
fab! ( :post ) { Fabricate ( :post ) }
2018-07-18 04:28:44 -04: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 )
2022-07-19 10:03:03 -04:00
expect { email_sender . send } . not_to change { PostReplyKey . count }
2018-07-18 04:28:44 -04:00
end
2022-06-06 15:13:26 -04:00
it 'should find existing key' do
existing_post_reply_key = PostReplyKey . create ( post_id : post . id , user_id : user . id )
2022-07-19 10:03:03 -04:00
expect { email_sender . send } . not_to change { PostReplyKey . count }
2022-06-06 15:13:26 -04:00
post_reply_key = PostReplyKey . last
expect ( post_reply_key ) . to eq ( existing_post_reply_key )
end
2018-07-18 04:28:44 -04:00
end
end
2013-02-05 14:16:51 -05:00
end
2021-06-21 18:32:01 -04:00
context " with cc addresses " do
let ( :message ) do
message = Mail :: Message . new to : 'eviltrout@test.domain' , body : 'test body' , cc : 'someguy@test.com;otherguy@xyz.com'
2022-06-14 20:28:30 -04:00
stub_deliver_response ( message )
2021-06-21 18:32:01 -04:00
message
end
fab! ( :user ) { Fabricate ( :user ) }
let ( :email_sender ) { Email :: Sender . new ( message , :valid_type , user ) }
it " logs the cc addresses in the email log (but not users if they do not match the emails) " do
email_sender . send
email_log = EmailLog . last
expect ( email_log . cc_addresses ) . to eq ( " someguy@test.com;otherguy@xyz.com " )
expect ( email_log . cc_users ) . to eq ( [ ] )
end
it " logs the cc users if they match the emails " do
user1 = Fabricate ( :user , email : " someguy@test.com " )
user2 = Fabricate ( :user , email : " otherguy@xyz.com " )
email_sender . send
email_log = EmailLog . last
expect ( email_log . cc_addresses ) . to eq ( " someguy@test.com;otherguy@xyz.com " )
expect ( email_log . cc_users ) . to match_array ( [ user1 , user2 ] )
end
end
2013-02-05 14:16:51 -05:00
end