FEATURE: new 'enable_forwarded_email' site setting
This commit is contained in:
parent
ece5442c54
commit
17f2be9f88
2
Gemfile
2
Gemfile
|
@ -66,7 +66,7 @@ gem 'aws-sdk', require: false
|
||||||
gem 'excon', require: false
|
gem 'excon', require: false
|
||||||
gem 'unf', require: false
|
gem 'unf', require: false
|
||||||
|
|
||||||
gem 'email_reply_trimmer', '0.1.4'
|
gem 'email_reply_trimmer', '0.1.5'
|
||||||
|
|
||||||
# note: for image_optim to correctly work you need to follow
|
# note: for image_optim to correctly work you need to follow
|
||||||
# https://github.com/toy/image_optim
|
# https://github.com/toy/image_optim
|
||||||
|
|
|
@ -80,7 +80,7 @@ GEM
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
domain_name (0.5.25)
|
domain_name (0.5.25)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
email_reply_trimmer (0.1.4)
|
email_reply_trimmer (0.1.5)
|
||||||
ember-data-source (1.0.0.beta.16.1)
|
ember-data-source (1.0.0.beta.16.1)
|
||||||
ember-source (~> 1.8)
|
ember-source (~> 1.8)
|
||||||
ember-handlebars-template (0.7.3)
|
ember-handlebars-template (0.7.3)
|
||||||
|
@ -411,7 +411,7 @@ DEPENDENCIES
|
||||||
certified
|
certified
|
||||||
discourse-qunit-rails
|
discourse-qunit-rails
|
||||||
discourse_fastimage (= 2.0.3)
|
discourse_fastimage (= 2.0.3)
|
||||||
email_reply_trimmer (= 0.1.4)
|
email_reply_trimmer (= 0.1.5)
|
||||||
ember-rails (= 0.18.5)
|
ember-rails (= 0.18.5)
|
||||||
ember-source (= 1.12.2)
|
ember-source (= 1.12.2)
|
||||||
excon
|
excon
|
||||||
|
|
|
@ -1246,6 +1246,8 @@ en:
|
||||||
attachment_content_type_blacklist: "List of keywords used to blacklist attachments based on the content type."
|
attachment_content_type_blacklist: "List of keywords used to blacklist attachments based on the content type."
|
||||||
attachment_filename_blacklist: "List of keywords used to blacklist attachments based on the filename."
|
attachment_filename_blacklist: "List of keywords used to blacklist attachments based on the filename."
|
||||||
|
|
||||||
|
enable_forwarded_emails: "[BETA] Allow users to create a topic by forwarding an email in."
|
||||||
|
|
||||||
manual_polling_enabled: "Push emails using the API for email replies."
|
manual_polling_enabled: "Push emails using the API for email replies."
|
||||||
pop3_polling_enabled: "Poll via POP3 for email replies."
|
pop3_polling_enabled: "Poll via POP3 for email replies."
|
||||||
pop3_polling_ssl: "Use SSL while connecting to the POP3 server. (Recommended)"
|
pop3_polling_ssl: "Use SSL while connecting to the POP3 server. (Recommended)"
|
||||||
|
|
|
@ -670,7 +670,7 @@ email:
|
||||||
attachment_filename_blacklist:
|
attachment_filename_blacklist:
|
||||||
type: list
|
type: list
|
||||||
default: "smime.p7s|signature.asc"
|
default: "smime.p7s|signature.asc"
|
||||||
|
enable_forwarded_emails: false
|
||||||
|
|
||||||
files:
|
files:
|
||||||
max_image_size_kb:
|
max_image_size_kb:
|
||||||
|
|
|
@ -38,7 +38,7 @@ module Email
|
||||||
|
|
||||||
def process!
|
def process!
|
||||||
return if is_blacklisted?
|
return if is_blacklisted?
|
||||||
@from_email, @from_display_name = parse_from_field
|
@from_email, @from_display_name = parse_from_field(@mail)
|
||||||
@incoming_email = find_or_create_incoming_email
|
@incoming_email = find_or_create_incoming_email
|
||||||
process_internal
|
process_internal
|
||||||
rescue => e
|
rescue => e
|
||||||
|
@ -74,7 +74,7 @@ module Email
|
||||||
raise InactiveUserError if !user.active && !user.staged
|
raise InactiveUserError if !user.active && !user.staged
|
||||||
raise BlockedUserError if user.blocked
|
raise BlockedUserError if user.blocked
|
||||||
|
|
||||||
body, @elided = select_body
|
body, elided = select_body
|
||||||
body ||= ""
|
body ||= ""
|
||||||
|
|
||||||
raise NoBodyDetectedError if body.blank? && attachments.empty?
|
raise NoBodyDetectedError if body.blank? && attachments.empty?
|
||||||
|
@ -90,6 +90,7 @@ module Email
|
||||||
elsif post = find_related_post
|
elsif post = find_related_post
|
||||||
create_reply(user: user,
|
create_reply(user: user,
|
||||||
raw: body,
|
raw: body,
|
||||||
|
elided: elided,
|
||||||
post: post,
|
post: post,
|
||||||
topic: post.topic,
|
topic: post.topic,
|
||||||
skip_validations: user.staged?)
|
skip_validations: user.staged?)
|
||||||
|
@ -98,7 +99,7 @@ module Email
|
||||||
|
|
||||||
destinations.each do |destination|
|
destinations.each do |destination|
|
||||||
begin
|
begin
|
||||||
process_destination(destination, user, body)
|
process_destination(destination, user, body, elided)
|
||||||
rescue => e
|
rescue => e
|
||||||
first_exception ||= e
|
first_exception ||= e
|
||||||
else
|
else
|
||||||
|
@ -237,16 +238,19 @@ module Email
|
||||||
reply.split(previous_replies_regex)[0]
|
reply.split(previous_replies_regex)[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_from_field
|
def parse_from_field(mail)
|
||||||
if @mail[:from].errors.blank?
|
if mail[:from].errors.blank?
|
||||||
address_field = @mail[:from].address_list.addresses.first
|
mail[:from].address_list.addresses.each do |address_field|
|
||||||
address_field.decoded
|
address_field.decoded
|
||||||
from_address = address_field.address
|
from_address = address_field.address
|
||||||
from_display_name = address_field.display_name.try(:to_s)
|
from_display_name = address_field.display_name.try(:to_s)
|
||||||
else
|
return [from_address.downcase, from_display_name] if from_address["@"]
|
||||||
from_address = @mail.from[/<([^>]+)>/, 1]
|
|
||||||
from_display_name = @mail.from[/^([^<]+)/, 1]
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
from_address = mail.from[/<([^>]+)>/, 1]
|
||||||
|
from_display_name = mail.from[/^([^<]+)/, 1]
|
||||||
|
|
||||||
[from_address.downcase, from_display_name]
|
[from_address.downcase, from_display_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -314,12 +318,17 @@ module Email
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_destination(destination, user, body)
|
def process_destination(destination, user, body, elided)
|
||||||
|
return if SiteSetting.enable_forwarded_emails &&
|
||||||
|
has_been_forwarded? &&
|
||||||
|
process_forwarded_email(destination, user)
|
||||||
|
|
||||||
case destination[:type]
|
case destination[:type]
|
||||||
when :group
|
when :group
|
||||||
group = destination[:obj]
|
group = destination[:obj]
|
||||||
create_topic(user: user,
|
create_topic(user: user,
|
||||||
raw: body,
|
raw: body,
|
||||||
|
elided: elided,
|
||||||
title: subject,
|
title: subject,
|
||||||
archetype: Archetype.private_message,
|
archetype: Archetype.private_message,
|
||||||
target_group_names: [group.name],
|
target_group_names: [group.name],
|
||||||
|
@ -347,11 +356,69 @@ module Email
|
||||||
|
|
||||||
create_reply(user: user,
|
create_reply(user: user,
|
||||||
raw: body,
|
raw: body,
|
||||||
|
elided: elided,
|
||||||
post: email_log.post,
|
post: email_log.post,
|
||||||
topic: email_log.post.topic)
|
topic: email_log.post.topic)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_been_forwarded?
|
||||||
|
subject[/^[[:blank]]*(re|fwd?)[[:blank]]?:/i] && embedded_email_raw.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def embedded_email_raw
|
||||||
|
return @embedded_email_raw if @embedded_email_raw
|
||||||
|
text = fix_charset(@mail.multipart? ? @mail.text_part : @mail)
|
||||||
|
@embedded_email_raw, @before_embedded = EmailReplyTrimmer.extract_embedded_email(text)
|
||||||
|
@embedded_email_raw
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_forwarded_email(destination, user)
|
||||||
|
embedded = Mail.new(@embedded_email_raw)
|
||||||
|
email, display_name = parse_from_field(embedded)
|
||||||
|
embedded_user = find_or_create_user(email, display_name)
|
||||||
|
raw = embedded.decoded
|
||||||
|
title = embedded.subject.presence || subject
|
||||||
|
|
||||||
|
case destination[:type]
|
||||||
|
when :group
|
||||||
|
group = destination[:obj]
|
||||||
|
post = create_topic(user: embedded_user,
|
||||||
|
raw: raw,
|
||||||
|
title: title,
|
||||||
|
archetype: Archetype.private_message,
|
||||||
|
target_group_names: [group.name],
|
||||||
|
is_group_message: true,
|
||||||
|
skip_validations: true,
|
||||||
|
created_at: embedded.date)
|
||||||
|
|
||||||
|
when :category
|
||||||
|
category = destination[:obj]
|
||||||
|
|
||||||
|
return false if user.staged? && !category.email_in_allow_strangers
|
||||||
|
return false if !user.has_trust_level?(SiteSetting.email_in_min_trust)
|
||||||
|
|
||||||
|
post = create_topic(user: embedded_user,
|
||||||
|
raw: raw,
|
||||||
|
title: title,
|
||||||
|
category: category.id,
|
||||||
|
skip_validations: embedded_user.staged?,
|
||||||
|
created_at: embedded.date)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if post && post.topic && @before_embedded.present?
|
||||||
|
create_reply(user: user,
|
||||||
|
raw: @before_embedded,
|
||||||
|
post: post,
|
||||||
|
topic: post.topic,
|
||||||
|
post_type: Post.types[:whisper])
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def reply_by_email_address_regex
|
def reply_by_email_address_regex
|
||||||
@reply_by_email_address_regex ||= begin
|
@reply_by_email_address_regex ||= begin
|
||||||
reply_addresses = [
|
reply_addresses = [
|
||||||
|
@ -483,16 +550,17 @@ module Email
|
||||||
options[:raw_email] = @raw_email
|
options[:raw_email] = @raw_email
|
||||||
|
|
||||||
# ensure posts aren't created in the future
|
# ensure posts aren't created in the future
|
||||||
options[:created_at] = [@mail.date, DateTime.now].min
|
options[:created_at] ||= @mail.date
|
||||||
|
options[:created_at] = DateTime.now if options[:created_at] > DateTime.now
|
||||||
|
|
||||||
is_private_message = options[:archetype] == Archetype.private_message ||
|
is_private_message = options[:archetype] == Archetype.private_message ||
|
||||||
options[:topic].try(:private_message?)
|
options[:topic].try(:private_message?)
|
||||||
|
|
||||||
# only add elided part in messages
|
# only add elided part in messages
|
||||||
if @elided.present? && is_private_message
|
if options[:elided].present? && is_private_message
|
||||||
options[:raw] << "\n\n" << "<details class='elided'>" << "\n"
|
options[:raw] << "\n\n" << "<details class='elided'>" << "\n"
|
||||||
options[:raw] << "<summary title='#{I18n.t('emails.incoming.show_trimmed_content')}'>···</summary>" << "\n"
|
options[:raw] << "<summary title='#{I18n.t('emails.incoming.show_trimmed_content')}'>···</summary>" << "\n"
|
||||||
options[:raw] << @elided << "\n"
|
options[:raw] << options[:elided] << "\n"
|
||||||
options[:raw] << "</details>" << "\n"
|
options[:raw] << "</details>" << "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -508,6 +576,8 @@ module Email
|
||||||
add_other_addresses(result.post.topic, user)
|
add_other_addresses(result.post.topic, user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
result.post
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_other_addresses(topic, sender)
|
def add_other_addresses(topic, sender)
|
||||||
|
@ -518,6 +588,7 @@ module Email
|
||||||
address_field.decoded
|
address_field.decoded
|
||||||
email = address_field.address.downcase
|
email = address_field.address.downcase
|
||||||
display_name = address_field.display_name.try(:to_s)
|
display_name = address_field.display_name.try(:to_s)
|
||||||
|
next unless email["@"]
|
||||||
if should_invite?(email)
|
if should_invite?(email)
|
||||||
user = find_or_create_user(email, display_name)
|
user = find_or_create_user(email, display_name)
|
||||||
if user && can_invite?(topic, user)
|
if user && can_invite?(topic, user)
|
||||||
|
|
Loading…
Reference in New Issue