2016-01-18 18:57:55 -05:00
require " rails_helper "
require " email/receiver "
2013-06-10 16:46:08 -04:00
describe Email :: Receiver do
2013-06-13 18:11:10 -04:00
before do
2016-01-18 18:57:55 -05:00
SiteSetting . email_in = true
SiteSetting . reply_by_email_address = " reply+%{reply_key}@bar.com "
2016-06-10 10:14:42 -04:00
SiteSetting . alternative_reply_by_email_addresses = " alt+%{reply_key}@bar.com "
2013-06-13 18:11:10 -04:00
end
2013-06-10 16:46:08 -04:00
2016-01-18 18:57:55 -05:00
def process ( email_name )
2016-03-07 10:56:17 -05:00
Email :: Receiver . new ( email ( email_name ) ) . process!
2016-01-18 18:57:55 -05:00
end
2014-08-26 20:08:53 -04:00
2016-01-18 18:57:55 -05:00
it " raises an EmptyEmailError when 'mail_string' is blank " do
expect { Email :: Receiver . new ( nil ) } . to raise_error ( Email :: Receiver :: EmptyEmailError )
expect { Email :: Receiver . new ( " " ) } . to raise_error ( Email :: Receiver :: EmptyEmailError )
end
2014-08-28 15:09:42 -04:00
2016-04-18 16:58:30 -04:00
it " raises a ScreenedEmailError when email address is screened " do
ScreenedEmail . expects ( :should_block? ) . with ( " screened@mail.com " ) . returns ( true )
expect { process ( :screened_email ) } . to raise_error ( Email :: Receiver :: ScreenedEmailError )
end
2017-10-03 05:23:18 -04:00
it " raises EmailNotAllowed when email address is not on whitelist " do
SiteSetting . email_domains_whitelist = " example.com|bar.com "
expect { process ( :blacklist_whitelist_email ) } . to raise_error ( Email :: Receiver :: EmailNotAllowed )
end
it " raises EmailNotAllowed when email address is on blacklist " do
SiteSetting . email_domains_blacklist = " email.com|mail.com "
expect { process ( :blacklist_whitelist_email ) } . to raise_error ( Email :: Receiver :: EmailNotAllowed )
end
2016-04-18 16:58:30 -04:00
it " raises an UserNotFoundError when staged users are disabled " do
2016-03-23 13:56:03 -04:00
SiteSetting . enable_staged_users = false
expect { process ( :user_not_found ) } . to raise_error ( Email :: Receiver :: UserNotFoundError )
end
2016-01-18 18:57:55 -05:00
it " raises an AutoGeneratedEmailError when the mail is auto generated " do
expect { process ( :auto_generated_precedence ) } . to raise_error ( Email :: Receiver :: AutoGeneratedEmailError )
expect { process ( :auto_generated_header ) } . to raise_error ( Email :: Receiver :: AutoGeneratedEmailError )
end
2014-11-25 11:44:59 -05:00
2016-01-18 18:57:55 -05:00
it " raises a NoBodyDetectedError when the body is blank " do
expect { process ( :no_body ) } . to raise_error ( Email :: Receiver :: NoBodyDetectedError )
end
2014-12-01 13:21:14 -05:00
2017-09-12 16:35:24 -04:00
it " raises a NoSenderDetectedError when the From header is missing " do
expect { process ( :no_from ) } . to raise_error ( Email :: Receiver :: NoSenderDetectedError )
end
2016-01-18 18:57:55 -05:00
it " raises an InactiveUserError when the sender is inactive " do
Fabricate ( :user , email : " inactive@bar.com " , active : false )
expect { process ( :inactive_sender ) } . to raise_error ( Email :: Receiver :: InactiveUserError )
end
2015-11-18 15:22:50 -05:00
2017-11-10 12:18:08 -05:00
it " raises a SilencedUserError when the sender has been silenced " do
2017-11-13 13:41:36 -05:00
Fabricate ( :user , email : " silenced@bar.com " , silenced_till : 1 . year . from_now )
2017-11-10 12:18:08 -05:00
expect { process ( :silenced_sender ) } . to raise_error ( Email :: Receiver :: SilencedUserError )
2016-02-11 04:39:57 -05:00
end
2017-07-24 09:25:26 -04:00
it " doesn't raise an InactiveUserError when the sender is staged " do
user = Fabricate ( :user , email : " staged@bar.com " , active : false , staged : true )
email_log = Fabricate ( :email_log ,
to_address : 'reply+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@bar.com' ,
reply_key : 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ,
user : user ,
post : Fabricate ( :post )
)
2016-01-18 18:57:55 -05:00
expect { process ( :staged_sender ) } . not_to raise_error
end
2015-11-18 15:22:50 -05:00
2016-01-18 18:57:55 -05:00
it " raises a BadDestinationAddress when destinations aren't matching any of the incoming emails " do
expect { process ( :bad_destinations ) } . to raise_error ( Email :: Receiver :: BadDestinationAddress )
end
2015-11-18 15:22:50 -05:00
2016-05-02 17:15:32 -04:00
it " raises a BouncerEmailError when email is a bounced email " do
2016-04-07 10:21:17 -04:00
expect { process ( :bounced_email ) } . to raise_error ( Email :: Receiver :: BouncedEmailError )
2016-05-02 17:15:32 -04:00
expect ( IncomingEmail . last . is_bounce ) . to eq ( true )
2018-01-03 11:59:20 -05:00
expect { process ( :bounced_email_multiple_status_codes ) } . to raise_error ( Email :: Receiver :: BouncedEmailError )
expect ( IncomingEmail . last . is_bounce ) . to eq ( true )
2016-04-07 10:21:17 -04:00
end
2017-08-04 10:20:44 -04:00
it " logs a blank error " do
Email :: Receiver . any_instance . stubs ( :process_internal ) . raises ( RuntimeError , " " )
process ( :existing_user ) rescue RuntimeError
expect ( IncomingEmail . last . error ) . to eq ( " RuntimeError " )
end
2016-05-02 17:15:32 -04:00
context " bounces to VERP " do
let ( :bounce_key ) { " 14b08c855160d67f2e0c2f8ef36e251e " }
let ( :bounce_key_2 ) { " b542fb5a9bacda6d28cc061d18e4eb83 " }
2016-05-06 13:34:33 -04:00
let! ( :user ) { Fabricate ( :user , email : " foo@bar.com " ) }
2016-05-02 17:15:32 -04:00
let! ( :email_log ) { Fabricate ( :email_log , user : user , bounce_key : bounce_key ) }
let! ( :email_log_2 ) { Fabricate ( :email_log , user : user , bounce_key : bounce_key_2 ) }
before do
$redis . del ( " bounce_score: #{ user . email } : #{ Date . today } " )
$redis . del ( " bounce_score: #{ user . email } : #{ 2 . days . from_now . to_date } " )
end
it " deals with soft bounces " do
expect { process ( :soft_bounce_via_verp ) } . to raise_error ( Email :: Receiver :: BouncedEmailError )
email_log . reload
expect ( email_log . bounced ) . to eq ( true )
expect ( email_log . user . user_stat . bounce_score ) . to eq ( 1 )
end
it " deals with hard bounces " do
expect { process ( :hard_bounce_via_verp ) } . to raise_error ( Email :: Receiver :: BouncedEmailError )
email_log . reload
expect ( email_log . bounced ) . to eq ( true )
expect ( email_log . user . user_stat . bounce_score ) . to eq ( 2 )
2017-07-24 09:17:42 -04:00
freeze_time 2 . days . from_now
2016-05-02 17:15:32 -04:00
2017-07-24 09:17:42 -04:00
expect { process ( :hard_bounce_via_verp_2 ) } . to raise_error ( Email :: Receiver :: BouncedEmailError )
email_log_2 . reload
expect ( email_log_2 . user . user_stat . bounce_score ) . to eq ( 4 )
expect ( email_log_2 . bounced ) . to eq ( true )
2016-05-02 17:15:32 -04:00
end
end
2016-01-18 18:57:55 -05:00
context " reply " do
2015-11-18 15:22:50 -05:00
2016-01-18 18:57:55 -05:00
let ( :reply_key ) { " 4f97315cc828096c9cb34c6f1a0d6fe8 " }
2016-06-26 13:25:45 -04:00
let ( :category ) { Fabricate ( :category ) }
2016-01-18 18:57:55 -05:00
let ( :user ) { Fabricate ( :user , email : " discourse@bar.com " ) }
2016-06-26 13:25:45 -04:00
let ( :topic ) { create_topic ( category : category , user : user ) }
2016-01-18 18:57:55 -05:00
let ( :post ) { create_post ( topic : topic , user : user ) }
let! ( :email_log ) { Fabricate ( :email_log , reply_key : reply_key , user : user , topic : topic , post : post ) }
2014-11-25 11:44:59 -05:00
2016-03-14 13:18:58 -04:00
it " uses MD5 of 'mail_string' there is no message_id " do
mail_string = email ( :missing_message_id )
expect { Email :: Receiver . new ( mail_string ) . process! } . to change { IncomingEmail . count }
expect ( IncomingEmail . last . message_id ) . to eq ( Digest :: MD5 . hexdigest ( mail_string ) )
end
2016-01-18 18:57:55 -05:00
it " raises a ReplyUserNotMatchingError when the email address isn't matching the one we sent the notification to " do
expect { process ( :reply_user_not_matching ) } . to raise_error ( Email :: Receiver :: ReplyUserNotMatchingError )
2014-11-25 11:44:59 -05:00
end
2016-01-18 18:57:55 -05:00
it " raises a TopicNotFoundError when the topic was deleted " do
topic . update_columns ( deleted_at : 1 . day . ago )
expect { process ( :reply_user_matching ) } . to raise_error ( Email :: Receiver :: TopicNotFoundError )
2015-12-09 12:44:01 -05:00
end
2016-01-18 18:57:55 -05:00
it " raises a TopicClosedError when the topic was closed " do
topic . update_columns ( closed : true )
expect { process ( :reply_user_matching ) } . to raise_error ( Email :: Receiver :: TopicClosedError )
2015-12-09 12:44:01 -05:00
end
2016-07-05 11:33:08 -04:00
it " does not raise TopicClosedError when performing a like action " do
topic . update_columns ( closed : true )
expect { process ( :like ) } . to change ( PostAction , :count )
end
2016-01-18 18:57:55 -05:00
it " raises an InvalidPost when there was an error while creating the post " do
expect { process ( :too_small ) } . to raise_error ( Email :: Receiver :: InvalidPost )
2014-11-25 11:44:59 -05:00
end
2016-01-18 18:57:55 -05:00
it " raises an InvalidPost when there are too may mentions " do
SiteSetting . max_mentions_per_post = 1
Fabricate ( :user , username : " user1 " )
Fabricate ( :user , username : " user2 " )
expect { process ( :too_many_mentions ) } . to raise_error ( Email :: Receiver :: InvalidPost )
2014-11-25 11:44:59 -05:00
end
2016-01-18 18:57:55 -05:00
it " raises an InvalidPostAction when they aren't allowed to like a post " do
topic . update_columns ( archived : true )
expect { process ( :like ) } . to raise_error ( Email :: Receiver :: InvalidPostAction )
2014-11-25 11:44:59 -05:00
end
2016-01-18 18:57:55 -05:00
it " works " do
expect { process ( :text_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is a text reply :) " )
expect ( topic . posts . last . via_email ) . to eq ( true )
expect ( topic . posts . last . cooked ) . not_to match ( / <br / )
2014-11-25 11:44:59 -05:00
2016-01-18 18:57:55 -05:00
expect { process ( :html_reply ) } . to change { topic . posts . count }
2017-04-26 10:49:06 -04:00
expect ( topic . posts . last . raw ) . to eq ( " This is a **HTML** reply ;) " )
2017-04-30 17:30:40 -04:00
end
2014-11-25 11:44:59 -05:00
2018-02-26 17:54:02 -05:00
it " automatically elides gmail quotes " do
SiteSetting . always_show_trimmed_content = true
expect { process ( :gmail_html_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is a **GMAIL** reply ;) \n \n <details class='elided'> \n <summary title='Show trimmed content'>& # 183;& # 183;& # 183;</summary> \n \n This is the *elided* part! \n \n </details> " )
end
2017-05-18 10:43:07 -04:00
it " doesn't process email with same message-id more than once " do
expect do
process ( :text_reply )
process ( :text_reply )
end . to change { topic . posts . count } . by ( 1 )
end
2017-04-30 17:30:40 -04:00
it " handles different encodings correctly " do
2016-01-18 18:57:55 -05:00
expect { process ( :hebrew_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " שלום! מה שלומך היום? " )
2014-11-25 11:44:59 -05:00
2016-01-18 18:57:55 -05:00
expect { process ( :chinese_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " 您好! 你今天好吗? " )
2016-03-11 12:51:53 -05:00
expect { process ( :reply_with_weird_encoding ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is a reply with a weird encoding. " )
2017-04-30 17:30:40 -04:00
expect { process ( :reply_with_8bit_encoding ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " hab vergessen kritische zeichen einzufügen: \n äöüÄÖÜß " )
2014-11-25 11:44:59 -05:00
end
2018-02-21 05:26:41 -05:00
it " prefers text over html when site setting is disabled " do
SiteSetting . incoming_email_prefer_html = false
2016-01-18 18:57:55 -05:00
expect { process ( :text_and_html_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is the *text* part. " )
2014-10-14 06:12:01 -04:00
end
2017-04-27 08:31:11 -04:00
it " prefers html over text when site setting is enabled " do
SiteSetting . incoming_email_prefer_html = true
expect { process ( :text_and_html_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( 'This is the **html** part.' )
end
it " uses text when prefer_html site setting is enabled but no html is available " do
SiteSetting . incoming_email_prefer_html = true
expect { process ( :text_reply ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is a text reply :) " )
end
2016-01-18 18:57:55 -05:00
it " removes the 'on <date>, <contact> wrote' quoting line " do
expect { process ( :on_date_contact_wrote ) } . to change { topic . posts . count }
2016-03-17 18:10:46 -04:00
expect ( topic . posts . last . raw ) . to eq ( " This is the actual reply. " )
2014-08-28 15:09:42 -04:00
end
2014-01-16 21:24:32 -05:00
2016-01-18 18:57:55 -05:00
it " removes the 'Previous Replies' marker " do
expect { process ( :previous_replies ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This will not include the previous discussion that is present in this email. " )
2014-08-26 20:08:53 -04:00
end
2016-01-18 18:57:55 -05:00
it " handles multiple paragraphs " do
expect { process ( :paragraphs ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " Do you like liquorice? \n \n I really like them. One could even say that I am *addicted* to liquorice. Anf if \n you can mix it up with some anise, then I'm in heaven ;) " )
2013-08-21 16:54:01 -04:00
end
2013-07-24 14:22:32 -04:00
2016-02-24 11:40:57 -05:00
it " handles invalid from header " do
2017-09-12 16:35:24 -04:00
expect { process ( :invalid_from_1 ) } . to change { topic . posts . count }
2016-02-24 11:40:57 -05:00
expect ( topic . posts . last . raw ) . to eq ( " This email was sent with an invalid from header field. " )
end
2017-09-12 16:35:24 -04:00
it " raises a NoSenderDetectedError when the From header doesn't contain an email address " do
expect { process ( :invalid_from_2 ) } . to raise_error ( Email :: Receiver :: NoSenderDetectedError )
end
2016-04-11 16:47:34 -04:00
it " doesn't raise an AutoGeneratedEmailError when the mail is auto generated but is whitelisted " do
SiteSetting . auto_generated_whitelist = " foo@bar.com|discourse@bar.com "
2016-04-20 15:29:27 -04:00
expect { process ( :auto_generated_whitelisted ) } . to change { topic . posts . count }
end
it " doesn't raise an AutoGeneratedEmailError when block_auto_generated_emails is disabled " do
SiteSetting . block_auto_generated_emails = false
expect { process ( :auto_generated_unblocked ) } . to change { topic . posts . count }
2016-04-11 16:47:34 -04:00
end
2016-06-26 13:25:45 -04:00
it " allows staged users to reply to a restricted category " do
user . update_columns ( staged : true )
category . email_in = " category@bar.com "
category . email_in_allow_strangers = true
category . set_permissions ( Group [ :trust_level_4 ] = > :full )
category . save
expect { process ( :staged_reply_restricted ) } . to change { topic . posts . count }
end
2016-01-20 04:25:25 -05:00
describe 'Unsubscribing via email' do
let ( :last_email ) { ActionMailer :: Base . deliveries . last }
describe 'unsubscribe_subject.eml' do
it 'sends an email asking the user to confirm the unsubscription' do
expect { process ( " unsubscribe_subject " ) } . to change { ActionMailer :: Base . deliveries . count } . by ( 1 )
expect ( last_email . to . length ) . to eq 1
expect ( last_email . from . length ) . to eq 1
expect ( last_email . from ) . to include " noreply@ #{ Discourse . current_hostname } "
expect ( last_email . to ) . to include " discourse@bar.com "
expect ( last_email . subject ) . to eq I18n . t ( :" unsubscribe_mailer.subject_template " ) . gsub ( " %{site_title} " , SiteSetting . title )
end
it 'does nothing unless unsubscribe_via_email is turned on' do
2017-07-07 02:09:14 -04:00
SiteSetting . unsubscribe_via_email = false
2016-01-20 04:25:25 -05:00
before_deliveries = ActionMailer :: Base . deliveries . count
expect { process ( " unsubscribe_subject " ) } . to raise_error { Email :: Receiver :: BadDestinationAddress }
expect ( before_deliveries ) . to eq ActionMailer :: Base . deliveries . count
end
end
describe 'unsubscribe_body.eml' do
it 'sends an email asking the user to confirm the unsubscription' do
expect { process ( " unsubscribe_body " ) } . to change { ActionMailer :: Base . deliveries . count } . by ( 1 )
expect ( last_email . to . length ) . to eq 1
expect ( last_email . from . length ) . to eq 1
expect ( last_email . from ) . to include " noreply@ #{ Discourse . current_hostname } "
expect ( last_email . to ) . to include " discourse@bar.com "
expect ( last_email . subject ) . to eq I18n . t ( :" unsubscribe_mailer.subject_template " ) . gsub ( " %{site_title} " , SiteSetting . title )
end
it 'does nothing unless unsubscribe_via_email is turned on' do
2017-07-07 02:09:14 -04:00
SiteSetting . unsubscribe_via_email = false
2016-01-20 04:25:25 -05:00
before_deliveries = ActionMailer :: Base . deliveries . count
expect { process ( " unsubscribe_body " ) } . to raise_error { Email :: Receiver :: InvalidPost }
expect ( before_deliveries ) . to eq ActionMailer :: Base . deliveries . count
end
end
2017-10-03 04:13:19 -04:00
it " raises an UnsubscribeNotAllowed and does not send an unsubscribe email " do
before_deliveries = ActionMailer :: Base . deliveries . count
expect { process ( :unsubscribe_new_user ) } . to raise_error { Email :: Receiver :: UnsubscribeNotAllowed }
expect ( before_deliveries ) . to eq ActionMailer :: Base . deliveries . count
end
2016-01-20 04:25:25 -05:00
end
2016-01-18 18:57:55 -05:00
it " handles inline reply " do
expect { process ( :inline_reply ) } . to change { topic . posts . count }
2017-07-31 05:29:39 -04:00
expect ( topic . posts . last . raw ) . to eq ( " And this is *my* reply :+1: " )
2013-07-24 14:22:32 -04:00
end
2016-01-18 18:57:55 -05:00
it " retrieves the first part of multiple replies " do
expect { process ( :inline_mixed_replies ) } . to change { topic . posts . count }
2016-01-29 19:29:31 -05:00
expect ( topic . posts . last . raw ) . to eq ( " > WAT <https://bar.com/users/wat> November 28 \n > \n > This is the previous post. \n \n And this is *my* reply :+1: \n \n > This is another post. \n \n And this is **another** reply. " )
2013-07-24 14:22:32 -04:00
end
2014-08-26 20:08:53 -04:00
2016-01-29 19:29:31 -05:00
it " strips mobile/webmail signatures " do
2016-01-18 18:57:55 -05:00
expect { process ( :iphone_signature ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is not the signature you're looking for. " )
2014-08-26 20:08:53 -04:00
end
2016-01-18 18:57:55 -05:00
it " strips 'original message' context " do
2016-03-17 18:10:46 -04:00
expect { process ( :original_message ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to eq ( " This is a reply :) " )
end
it " add the 'elided' part of the original message only for private messages " do
topic . update_columns ( category_id : nil , archetype : Archetype . private_message )
topic . allowed_users << user
topic . save
2016-01-18 18:57:55 -05:00
expect { process ( :original_message ) } . to change { topic . posts . count }
2017-12-05 19:47:31 -05:00
expect ( topic . posts . last . raw ) . to eq ( " This is a reply :) \n \n <details class='elided'> \n <summary title='Show trimmed content'>& # 183;& # 183;& # 183;</summary> \n \n ---Original Message--- \n This part should not be included \n \n </details> " )
2014-12-04 11:45:31 -05:00
end
2017-06-29 00:03:14 -04:00
it " doesn't include the 'elided' part of the original message when always_show_trimmed_content is disabled " do
SiteSetting . always_show_trimmed_content = false
expect { process ( :original_message ) } . to change { topic . posts . count } . from ( 1 ) . to ( 2 )
expect ( topic . posts . last . raw ) . to eq ( " This is a reply :) " )
end
it " adds the 'elided' part of the original message for public replies when always_show_trimmed_content is enabled " do
SiteSetting . always_show_trimmed_content = true
expect { process ( :original_message ) } . to change { topic . posts . count } . from ( 1 ) . to ( 2 )
2017-12-05 19:47:31 -05:00
expect ( topic . posts . last . raw ) . to eq ( " This is a reply :) \n \n <details class='elided'> \n <summary title='Show trimmed content'>& # 183;& # 183;& # 183;</summary> \n \n ---Original Message--- \n This part should not be included \n \n </details> " )
2017-06-29 00:03:14 -04:00
end
2017-05-03 16:54:26 -04:00
it " supports attached images in TEXT part " do
2018-02-21 05:26:41 -05:00
SiteSetting . incoming_email_prefer_html = false
2017-04-15 00:11:02 -04:00
SiteSetting . queue_jobs = true
2016-01-29 19:29:31 -05:00
expect { process ( :no_body_with_image ) } . to change { topic . posts . count }
2016-01-18 18:57:55 -05:00
expect ( topic . posts . last . raw ) . to match ( / <img / )
2013-07-24 14:22:32 -04:00
2016-01-29 19:29:31 -05:00
expect { process ( :inline_image ) } . to change { topic . posts . count }
2017-05-03 16:54:26 -04:00
expect ( topic . posts . last . raw ) . to match ( / Before \ s+<img.+> \ s+After / )
end
it " supports attached images in HTML part " do
SiteSetting . queue_jobs = true
SiteSetting . incoming_email_prefer_html = true
expect { process ( :inline_image ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to match ( / \ * \ *Before \ * \ * \ s+<img.+> \ s+ \ *After \ * / )
2014-10-25 10:36:59 -04:00
end
2016-01-29 19:29:31 -05:00
it " supports attachments " do
SiteSetting . authorized_extensions = " txt "
expect { process ( :attached_txt_file ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to match ( / text \ .txt / )
2017-11-07 13:17:33 -05:00
SiteSetting . authorized_extensions = " csv "
expect { process ( :attached_txt_file_2 ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to_not match ( / text \ .txt / )
2016-01-29 19:29:31 -05:00
end
2018-02-16 12:14:56 -05:00
it " supports emails with just an attachment " do
SiteSetting . authorized_extensions = " pdf "
expect { process ( :attached_pdf_file ) } . to change { topic . posts . count }
expect ( topic . posts . last . raw ) . to match ( / discourse \ .pdf / )
end
2016-01-18 18:57:55 -05:00
it " supports liking via email " do
expect { process ( :like ) } . to change ( PostAction , :count )
2014-10-25 10:36:59 -04:00
end
2016-01-18 18:57:55 -05:00
it " ensures posts aren't dated in the future " do
expect { process ( :from_the_future ) } . to change { topic . posts . count }
expect ( topic . posts . last . created_at ) . to be_within ( 1 . minute ) . of ( DateTime . now )
2014-10-27 02:58:31 -04:00
end
2017-11-11 11:27:28 -05:00
it " accepts emails with wrong reply key if the system knows about the forwareded email " do
2017-11-12 17:44:22 -05:00
Fabricate ( :incoming_email ,
raw : << ~ RAW ,
2017-11-13 09:20:36 -05:00
Return - Path : < discourse @bar . com >
From : Alice < discourse @bar . com >
To : dave @bar . com , reply + 4 f97315cc828096c9cb34c6f1a0d6fe8 @bar . com
CC : carol @bar . com , bob @bar . com
Subject : Hello world
Date : Fri , 15 Jan 2016 00 : 12 : 43 + 0100
Message - ID : < 10 @foo . bar . mail >
Mime - Version : 1 . 0
Content - Type : text / plain ; charset = UTF - 8
Content - Transfer - Encoding : quoted - printable
This post was created by email .
2017-11-12 17:44:22 -05:00
RAW
from_address : " discourse@bar.com " ,
to_addresses : " dave@bar.com;reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com " ,
cc_addresses : " carol@bar.com;bob@bar.com " ,
topic : topic ,
post : post ,
user : user )
expect { process ( :reply_user_not_matching_but_known ) } . to change { topic . posts . count }
2017-11-11 11:27:28 -05:00
end
2014-10-27 02:58:31 -04:00
end
2016-01-18 18:57:55 -05:00
context " new message to a group " do
2015-12-21 11:54:02 -05:00
2016-02-24 13:47:58 -05:00
let! ( :group ) { Fabricate ( :group , incoming_email : " team@bar.com|meat@bar.com " ) }
2013-06-25 14:05:14 -04:00
2016-01-18 18:57:55 -05:00
it " handles encoded display names " do
expect { process ( :encoded_display_name ) } . to change ( Topic , :count )
2014-08-26 20:08:53 -04:00
2016-01-18 18:57:55 -05:00
topic = Topic . last
2016-02-01 06:16:15 -05:00
expect ( topic . title ) . to eq ( " I need help " )
2016-01-18 18:57:55 -05:00
expect ( topic . private_message? ) . to eq ( true )
expect ( topic . allowed_groups ) . to include ( group )
2013-06-25 14:05:14 -04:00
2016-01-18 18:57:55 -05:00
user = topic . user
expect ( user . staged ) . to eq ( true )
2016-01-20 09:37:34 -05:00
expect ( user . username ) . to eq ( " random.name " )
2016-01-18 18:57:55 -05:00
expect ( user . name ) . to eq ( " Случайная Имя " )
2013-06-25 14:05:14 -04:00
end
2014-08-26 20:08:53 -04:00
2016-02-01 06:16:15 -05:00
it " handles email with no subject " do
expect { process ( :no_subject ) } . to change ( Topic , :count )
2017-01-19 17:01:51 -05:00
expect ( Topic . last . title ) . to eq ( " This topic needs a title " )
2016-02-01 06:16:15 -05:00
end
2016-01-20 17:08:27 -05:00
it " invites everyone in the chain but emails configured as 'incoming' (via reply, group or category) " do
2016-01-18 18:57:55 -05:00
expect { process ( :cc ) } . to change ( Topic , :count )
2017-10-06 10:37:28 -04:00
topic = Topic . last
emails = topic . allowed_users . joins ( :user_emails ) . pluck ( :" user_emails.email " )
expect ( emails ) . to contain_exactly ( " someone@else.com " , " discourse@bar.com " , " wat@bar.com " )
expect ( topic . topic_users . count ) . to eq ( 3 )
2014-03-28 09:57:12 -04:00
end
2016-05-16 15:45:34 -04:00
it " cap the number of staged users created per email " do
SiteSetting . maximum_staged_users_per_email = 1
expect { process ( :cc ) } . to change ( Topic , :count )
expect ( Topic . last . ordered_posts [ - 1 ] . post_type ) . to eq ( Post . types [ :moderator_action ] )
end
2017-07-31 18:03:04 -04:00
it " associates email replies using both 'In-Reply-To' and 'References' headers when 'find_related_post_with_key' is disabled " do
SiteSetting . find_related_post_with_key = false
2016-01-20 16:52:08 -05:00
expect { process ( :email_reply_1 ) } . to change ( Topic , :count )
topic = Topic . last
expect { process ( :email_reply_2 ) } . to change { topic . posts . count }
expect { process ( :email_reply_3 ) } . to change { topic . posts . count }
2016-01-20 17:08:27 -05:00
# Why 5 when we only processed 3 emails?
2016-01-20 16:52:08 -05:00
# - 3 of them are indeed "regular" posts generated from the emails
2016-01-20 17:08:27 -05:00
# - The 2 others are "small action" posts automatically added because
# we invited 2 users (two@foo.com and three@foo.com)
expect ( topic . posts . count ) . to eq ( 5 )
2016-01-20 16:52:08 -05:00
# trash all but the 1st post
topic . ordered_posts [ 1 .. - 1 ] . each ( & :trash! )
expect { process ( :email_reply_4 ) } . to change { topic . posts . count }
end
2016-02-29 16:39:24 -05:00
it " supports any kind of attachments when 'allow_all_attachments_for_group_messages' is enabled " do
SiteSetting . allow_all_attachments_for_group_messages = true
expect { process ( :attached_rb_file ) } . to change ( Topic , :count )
expect ( Post . last . raw ) . to match ( / discourse \ .rb / )
end
2017-01-09 16:59:30 -05:00
context " with forwarded emails enabled " do
before { SiteSetting . enable_forwarded_emails = true }
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
it " handles forwarded emails " do
expect { process ( :forwarded_email_1 ) } . to change ( Topic , :count )
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
forwarded_post , last_post = * Post . last ( 2 )
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
expect ( forwarded_post . user . email ) . to eq ( " some@one.com " )
expect ( last_post . user . email ) . to eq ( " ba@bar.com " )
2016-12-01 12:43:56 -05:00
2017-01-09 16:59:30 -05:00
expect ( forwarded_post . raw ) . to match ( / XoXo / )
expect ( last_post . raw ) . to match ( / can you have a look at this email below / )
expect ( last_post . post_type ) . to eq ( Post . types [ :regular ] )
end
it " handles weirdly forwarded emails " do
group . add ( Fabricate ( :user , email : " ba@bar.com " ) )
group . save
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
SiteSetting . enable_forwarded_emails = true
expect { process ( :forwarded_email_2 ) } . to change ( Topic , :count )
2016-12-01 12:43:56 -05:00
2017-01-09 16:59:30 -05:00
forwarded_post , last_post = * Post . last ( 2 )
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
expect ( forwarded_post . user . email ) . to eq ( " some@one.com " )
expect ( last_post . user . email ) . to eq ( " ba@bar.com " )
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
expect ( forwarded_post . raw ) . to match ( / XoXo / )
expect ( last_post . raw ) . to match ( / can you have a look at this email below / )
2016-12-01 12:34:47 -05:00
2017-01-09 16:59:30 -05:00
expect ( last_post . post_type ) . to eq ( Post . types [ :whisper ] )
end
# Who thought this was a good idea?!
it " doesn't blow up with localized email headers " do
expect { process ( :forwarded_email_3 ) } . to change ( Topic , :count )
end
2016-12-01 12:43:56 -05:00
2016-12-01 12:34:47 -05:00
end
2013-06-10 16:46:08 -04:00
end
2016-01-18 18:57:55 -05:00
context " new topic in a category " do
2015-12-15 18:43:05 -05:00
2016-02-24 13:47:58 -05:00
let! ( :category ) { Fabricate ( :category , email_in : " category@bar.com|category@foo.com " , email_in_allow_strangers : false ) }
2015-12-15 18:43:05 -05:00
2016-01-18 18:57:55 -05:00
it " raises a StrangersNotAllowedError when 'email_in_allow_strangers' is disabled " do
2016-02-22 13:57:53 -05:00
expect { process ( :new_user ) } . to raise_error ( Email :: Receiver :: StrangersNotAllowedError )
2014-02-27 07:44:21 -05:00
end
2016-01-18 18:57:55 -05:00
it " raises an InsufficientTrustLevelError when user's trust level isn't enough " do
2016-02-22 13:57:53 -05:00
Fabricate ( :user , email : " existing@bar.com " , trust_level : 3 )
2016-01-18 18:57:55 -05:00
SiteSetting . email_in_min_trust = 4
2016-02-22 13:57:53 -05:00
expect { process ( :existing_user ) } . to raise_error ( Email :: Receiver :: InsufficientTrustLevelError )
2014-02-24 11:36:53 -05:00
end
2016-02-22 13:57:53 -05:00
it " works " do
user = Fabricate ( :user , email : " existing@bar.com " , trust_level : SiteSetting . email_in_min_trust )
2016-01-18 18:57:55 -05:00
group = Fabricate ( :group )
2015-04-10 05:29:45 -04:00
2016-01-18 18:57:55 -05:00
group . add ( user )
group . save
2015-04-10 05:29:45 -04:00
2016-02-22 13:57:53 -05:00
category . set_permissions ( group = > :create_post )
2015-04-10 05:29:45 -04:00
category . save
2016-02-22 13:57:53 -05:00
# raises an InvalidAccess when the user doesn't have the privileges to create a topic
expect { process ( :existing_user ) } . to raise_error ( Discourse :: InvalidAccess )
2014-02-27 10:36:33 -05:00
2016-02-22 13:57:53 -05:00
category . update_columns ( email_in_allow_strangers : true )
# allows new user to create a topic
expect { process ( :new_user ) } . to change ( Topic , :count )
2015-12-10 17:49:16 -05:00
end
2017-06-29 00:03:14 -04:00
it " adds the 'elided' part of the original message when always_show_trimmed_content is enabled " do
SiteSetting . always_show_trimmed_content = true
2017-07-20 16:01:16 -04:00
Fabricate ( :user , email : " existing@bar.com " , trust_level : SiteSetting . email_in_min_trust )
2017-07-27 21:20:09 -04:00
expect { process ( :forwarded_email_to_category ) } . to change { Topic . count } . by ( 1 ) # Topic created
2017-06-29 00:03:14 -04:00
new_post , = Post . last
2017-07-27 21:20:09 -04:00
expect ( new_post . raw ) . to include ( " Hi everyone, can you have a look at the email below? " , " <summary title='Show trimmed content'>& # 183;& # 183;& # 183;</summary> " , " Discoursing much today? " )
2017-06-29 00:03:14 -04:00
end
2016-04-11 12:20:26 -04:00
it " works when approving is enabled " do
SiteSetting . approve_unless_trust_level = 4
Fabricate ( :user , email : " tl3@bar.com " , trust_level : TrustLevel [ 3 ] )
Fabricate ( :user , email : " tl4@bar.com " , trust_level : TrustLevel [ 4 ] )
category . set_permissions ( Group [ :trust_level_4 ] = > :full )
category . save
Group . refresh_automatic_group! ( :trust_level_4 )
expect { process ( :tl3_user ) } . to_not change ( Topic , :count )
expect { process ( :tl4_user ) } . to change ( Topic , :count )
end
2017-11-11 19:43:18 -05:00
it " ignores by case-insensitive title " do
2016-05-18 17:07:01 -04:00
SiteSetting . ignore_by_title = " foo "
expect { process ( :ignored ) } . to_not change ( Topic , :count )
end
2015-12-10 17:49:16 -05:00
end
2016-06-30 08:21:47 -04:00
context " new topic in a category that allows strangers " do
let! ( :category ) { Fabricate ( :category , email_in : " category@bar.com|category@foo.com " , email_in_allow_strangers : true ) }
it " lets an email in from a stranger " do
expect { process ( :new_user ) } . to change ( Topic , :count )
end
it " lets an email in from a high-TL user " do
Fabricate ( :user , email : " tl4@bar.com " , trust_level : TrustLevel [ 4 ] )
expect { process ( :tl4_user ) } . to change ( Topic , :count )
end
it " fails on email from a low-TL user " do
SiteSetting . email_in_min_trust = 4
Fabricate ( :user , email : " tl3@bar.com " , trust_level : TrustLevel [ 3 ] )
expect { process ( :tl3_user ) } . to raise_error ( Email :: Receiver :: InsufficientTrustLevelError )
end
end
2017-05-22 17:35:41 -04:00
context " # reply_by_email_address_regex " do
before do
SiteSetting . reply_by_email_address = nil
SiteSetting . alternative_reply_by_email_addresses = nil
end
it " is empty by default " do
expect ( Email :: Receiver . reply_by_email_address_regex ) . to eq ( / / )
end
it " uses 'reply_by_email_address' site setting " do
SiteSetting . reply_by_email_address = " foo+%{reply_key}@bar.com "
expect ( Email :: Receiver . reply_by_email_address_regex ) . to eq ( / foo \ +( \ h{32})@bar \ .com / )
end
it " uses 'alternative_reply_by_email_addresses' site setting " do
SiteSetting . alternative_reply_by_email_addresses = " alt.foo+%{reply_key}@bar.com "
expect ( Email :: Receiver . reply_by_email_address_regex ) . to eq ( / alt \ .foo \ +( \ h{32})@bar \ .com / )
end
it " combines both 'reply_by_email' settings " do
SiteSetting . reply_by_email_address = " foo+%{reply_key}@bar.com "
SiteSetting . alternative_reply_by_email_addresses = " alt.foo+%{reply_key}@bar.com "
expect ( Email :: Receiver . reply_by_email_address_regex ) . to eq ( / foo \ +( \ h{32})@bar \ .com|alt \ .foo \ +( \ h{32})@bar \ .com / )
end
end
2017-06-08 14:28:48 -04:00
context " check_address " do
before do
SiteSetting . reply_by_email_address = " foo+%{reply_key}@bar.com "
end
it " returns nil when the key is invalid " do
expect ( Email :: Receiver . check_address ( 'fake@fake.com' ) ) . to be_nil
expect ( Email :: Receiver . check_address ( 'foo+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com' ) ) . to be_nil
end
context " with a valid reply " do
it " returns the destination when the key is valid " do
Fabricate ( :email_log , reply_key : '4f97315cc828096c9cb34c6f1a0d6fe8' )
dest = Email :: Receiver . check_address ( 'foo+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com' )
expect ( dest ) . to be_present
expect ( dest [ :type ] ) . to eq ( :reply )
expect ( dest [ :obj ] ) . to be_present
end
end
end
2018-01-10 10:50:27 -05:00
context " staged users " do
2017-10-03 04:13:19 -04:00
before do
SiteSetting . enable_staged_users = true
end
2017-10-03 11:28:41 -04:00
shared_examples " no staged users " do | email_name , expected_exception |
2017-10-03 04:13:19 -04:00
it " does not create staged users " do
staged_user_count = User . where ( staged : true ) . count
2017-10-03 11:28:41 -04:00
expect { process ( email_name ) } . to raise_error ( expected_exception )
2017-10-03 04:13:19 -04:00
expect ( User . where ( staged : true ) . count ) . to eq ( staged_user_count )
end
end
context " when email address is screened " do
before do
ScreenedEmail . expects ( :should_block? ) . with ( " screened@mail.com " ) . returns ( true )
end
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :screened_email , Email :: Receiver :: ScreenedEmailError
2017-10-03 04:13:19 -04:00
end
context " when the mail is auto generated " do
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :auto_generated_header , Email :: Receiver :: AutoGeneratedEmailError
2017-10-03 04:13:19 -04:00
end
context " when email is a bounced email " do
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :bounced_email , Email :: Receiver :: BouncedEmailError
2017-10-03 04:13:19 -04:00
end
context " when the body is blank " do
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :no_body , Email :: Receiver :: NoBodyDetectedError
2017-10-03 04:13:19 -04:00
end
context " when unsubscribe via email is not allowed " do
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :unsubscribe_new_user , Email :: Receiver :: UnsubscribeNotAllowed
2017-10-03 04:13:19 -04:00
end
2017-10-03 05:23:18 -04:00
2018-01-10 10:50:27 -05:00
context " when From email address is not on whitelist " do
2017-10-03 05:23:18 -04:00
before do
SiteSetting . email_domains_whitelist = " example.com|bar.com "
end
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :blacklist_whitelist_email , Email :: Receiver :: EmailNotAllowed
2017-10-03 05:23:18 -04:00
end
2018-01-10 10:50:27 -05:00
context " when From email address is on blacklist " do
2017-10-03 05:23:18 -04:00
before do
SiteSetting . email_domains_blacklist = " email.com|mail.com "
end
2017-10-03 11:28:41 -04:00
include_examples " no staged users " , :blacklist_whitelist_email , Email :: Receiver :: EmailNotAllowed
end
2018-01-10 10:50:27 -05:00
context " blacklist and whitelist for To and Cc " do
before do
Fabricate ( :group , incoming_email : " some_group@bar.com " )
end
it " does not create staged users for email addresses not on whitelist " do
SiteSetting . email_domains_whitelist = " mail.com|example.com "
process ( :blacklist_whitelist_email )
expect ( User . find_by_email ( " alice@foo.com " ) ) . to be_nil
expect ( User . find_by_email ( " bob@foo.com " ) ) . to be_nil
expect ( User . find_by_email ( " carol@example.com " ) ) . to be_present
end
it " does not create staged users for email addresses on blacklist " do
SiteSetting . email_domains_blacklist = " email.com|foo.com "
process ( :blacklist_whitelist_email )
expect ( User . find_by_email ( " alice@foo.com " ) ) . to be_nil
expect ( User . find_by_email ( " bob@foo.com " ) ) . to be_nil
expect ( User . find_by_email ( " carol@example.com " ) ) . to be_present
end
end
2017-10-03 11:28:41 -04:00
context " when destinations aren't matching any of the incoming emails " do
include_examples " no staged users " , :bad_destinations , Email :: Receiver :: BadDestinationAddress
end
context " when email is sent to category " do
context " when email is sent by a new user and category does not allow strangers " do
let! ( :category ) { Fabricate ( :category , email_in : " category@foo.com " , email_in_allow_strangers : false ) }
include_examples " no staged users " , :new_user , Email :: Receiver :: StrangersNotAllowedError
end
context " when email has no date " do
let! ( :category ) { Fabricate ( :category , email_in : " category@foo.com " , email_in_allow_strangers : true ) }
include_examples " no staged users " , :no_date , Email :: Receiver :: InvalidPost
end
end
context " email is a reply " do
let ( :reply_key ) { " 4f97315cc828096c9cb34c6f1a0d6fe8 " }
let ( :category ) { Fabricate ( :category ) }
let ( :user ) { Fabricate ( :user , email : " discourse@bar.com " ) }
let ( :topic ) { create_topic ( category : category , user : user ) }
let ( :post ) { create_post ( topic : topic , user : user ) }
let! ( :email_log ) { Fabricate ( :email_log , reply_key : reply_key , user : user , topic : topic , post : post ) }
context " when the email address isn't matching the one we sent the notification to " do
include_examples " no staged users " , :reply_user_not_matching , Email :: Receiver :: ReplyUserNotMatchingError
end
end
context " replying without key is allowed " do
let! ( :group ) { Fabricate ( :group , incoming_email : " team@bar.com " ) }
let! ( :topic ) do
SiteSetting . find_related_post_with_key = false
process ( :email_reply_1 )
Topic . last
end
context " when the topic was deleted " do
before do
topic . update_columns ( deleted_at : 1 . day . ago )
end
include_examples " no staged users " , :email_reply_staged , Email :: Receiver :: TopicNotFoundError
end
context " when the topic was closed " do
before do
topic . update_columns ( closed : true )
end
include_examples " no staged users " , :email_reply_staged , Email :: Receiver :: TopicClosedError
end
context " when they aren't allowed to like a post " do
before do
topic . update_columns ( archived : true )
end
include_examples " no staged users " , :email_reply_like , Email :: Receiver :: InvalidPostAction
end
2017-10-03 05:23:18 -04:00
end
2017-10-31 10:13:23 -04:00
it " does not remove the incoming email record when staged users are deleted " do
expect { process ( :bad_destinations ) } . to change { IncomingEmail . count }
. and raise_error ( Email :: Receiver :: BadDestinationAddress )
expect ( IncomingEmail . last . message_id ) . to eq ( " 9@foo.bar.mail " )
end
2017-10-03 04:13:19 -04:00
end
2018-01-04 07:38:06 -05:00
context " mailing list mirror " do
let! ( :category ) { Fabricate ( :mailinglist_mirror_category ) }
2017-11-17 08:49:10 -05:00
before do
SiteSetting . block_auto_generated_emails = true
SiteSetting . find_related_post_with_key = true
end
it " should allow creating topic even when email is autogenerated " do
expect { process ( :mailinglist ) } . to change { Topic . count }
2018-01-03 09:29:06 -05:00
expect ( IncomingEmail . last . is_auto_generated ) . to eq ( false )
2017-11-17 08:49:10 -05:00
end
it " should allow replying without reply key " do
process ( :mailinglist )
topic = Topic . last
expect { process ( :mailinglist_reply ) } . to change { topic . posts . count }
end
2018-01-04 07:38:06 -05:00
2018-01-04 07:39:29 -05:00
it " should skip validations for staged users " do
Fabricate ( :user , email : " alice@foo.com " , staged : true )
expect { process ( :mailinglist_short_message ) } . to change { Topic . count }
end
it " should skip validations for regular users " do
Fabricate ( :user , email : " alice@foo.com " )
expect { process ( :mailinglist_short_message ) } . to change { Topic . count }
end
2018-01-04 07:38:06 -05:00
context " read-only category " do
before do
category . set_permissions ( everyone : :readonly )
category . save
Fabricate ( :user , email : " alice@foo.com " )
Fabricate ( :user , email : " bob@bar.com " )
end
it " should allow creating topic within read-only category " do
expect { process ( :mailinglist ) } . to change { Topic . count }
end
it " should allow replying within read-only category " do
process ( :mailinglist )
topic = Topic . last
expect { process ( :mailinglist_reply ) } . to change { topic . posts . count }
end
end
2017-11-17 08:49:10 -05:00
end
2013-06-10 16:46:08 -04:00
end