add support for incoming emails in CC/BCC fields

This commit is contained in:
Régis Hanol 2015-12-10 23:49:16 +01:00
parent 6c2dee29a8
commit 93d1cc6294
5 changed files with 58 additions and 25 deletions

View File

@ -14,9 +14,7 @@ module Jobs
def execute(args)
@args = args
if SiteSetting.pop3_polling_enabled?
poll_pop3
end
poll_pop3 if SiteSetting.pop3_polling_enabled?
end
def handle_mail(mail)
@ -31,7 +29,6 @@ module Jobs
end
def handle_failure(mail_string, e)
Rails.logger.warn("Email can not be processed: #{e}\n\n#{mail_string}") if SiteSetting.log_mail_processing_failures
template_args = {}
@ -90,14 +87,14 @@ module Jobs
connection.start(SiteSetting.pop3_polling_username, SiteSetting.pop3_polling_password) do |pop|
unless pop.mails.empty?
pop.each do |mail|
handle_mail(mail)
end
pop.each { |mail| handle_mail(mail) }
end
pop.finish
end
rescue Net::POPAuthenticationError => e
Discourse.handle_job_exception(e, error_context(@args, "Signing in to poll incoming email"))
rescue Net::POPError => e
Discourse.handle_job_exception(e, error_context(@args, "Generic POP error"))
end
end

View File

@ -10,19 +10,25 @@ class EmailLog < ActiveRecord::Base
after_create do
# Update last_emailed_at if the user_id is present and email was sent
User.where(id: user_id).update_all("last_emailed_at = CURRENT_TIMESTAMP") if user_id.present? and !skipped
User.where(id: user_id).update_all("last_emailed_at = CURRENT_TIMESTAMP") if user_id.present? && !skipped
end
def self.count_per_day(start_date, end_date)
where('created_at >= ? and created_at < ? AND skipped = false', start_date, end_date).group('date(created_at)').order('date(created_at)').count
sent.where("created_at BETWEEN ? AND ?", start_date, end_date)
.group("DATE(created_at)")
.order("DATE(created_at)")
.count
end
def self.for(reply_key)
EmailLog.find_by(reply_key: reply_key)
self.find_by(reply_key: reply_key)
end
def self.last_sent_email_address
where(email_type: 'signup').order('created_at DESC').first.try(:to_address)
self.where(email_type: "signup")
.order(created_at: :desc)
.first
.try(:to_address)
end
end

View File

@ -34,7 +34,8 @@ module Email
body = parse_body(message)
dest_info = { type: :invalid, obj: nil }
message.to.each do |to_address|
# 'smtp_envelope_to' is a combination of: to, cc and bcc fields
message.smtp_envelope_to.each do |to_address|
dest_info = check_address(to_address)
break if dest_info[:type] != :invalid
end
@ -51,7 +52,6 @@ module Email
case dest_info[:type]
when :group
raise BadDestinationAddress unless SiteSetting.email_in
group = dest_info[:obj]
if @user.blank?
@ -68,7 +68,6 @@ module Email
create_new_topic(archetype: Archetype.private_message, target_group_names: [group.name])
when :category
raise BadDestinationAddress unless SiteSetting.email_in
category = dest_info[:obj]
if @user.blank? && category.email_in_allow_strangers
@ -108,11 +107,14 @@ module Email
end
def check_address(address)
group = Group.find_by_email(address)
return { type: :group, obj: group } if group
# only check groups/categories when 'email_in' is enabled
if SiteSetting.email_in
group = Group.find_by_email(address)
return { type: :group, obj: group } if group
category = Category.find_by_email(address)
return { type: :category, obj: category } if category
category = Category.find_by_email(address)
return { type: :category, obj: category } if category
end
regex = Regexp.escape(SiteSetting.reply_by_email_address)
regex = regex.gsub(Regexp.escape('%{reply_key}'), "(.*)")

View File

@ -474,16 +474,17 @@ This is a link http://example.com"
end
def fill_email(mail, from, to, body = nil, subject = nil)
def fill_email(mail, from, to, body = nil, subject = nil, cc = nil)
result = mail.gsub("FROM", from).gsub("TO", to)
result.gsub!(/Hey.*/m, body) if body
result.sub!(/We .*/, subject) if subject
result.sub!("CC", cc.presence || "")
result
end
def process_email(opts)
incoming_email = fixture_file("emails/valid_incoming.eml")
email = fill_email(incoming_email, opts[:from], opts[:to], opts[:body], opts[:subject])
email = fill_email(incoming_email, opts[:from], opts[:to], opts[:body], opts[:subject], opts[:cc])
Email::Receiver.new(email).process
end
@ -532,15 +533,15 @@ greatest show ever created. Everyone should watch it.
end
describe "processes an email to a category" do
let(:to) { "some@email.com" }
before do
SiteSetting.email_in = true
SiteSetting.email_in_min_trust = TrustLevel[4].to_s
end
it "correctly can target categories" do
to = "some@email.com"
Fabricate(:category, email_in_allow_strangers: false, email_in: to)
SiteSetting.email_in_min_trust = TrustLevel[4].to_s
# no email in for user
expect{
@ -614,7 +615,7 @@ greatest show ever created. Everyone should watch it.
}.to raise_error(Email::Receiver::UserNotFoundError)
end
it "creates a topic for allowed category" do
it "creates a topic for matching category" do
Fabricate(:category, email_in_allow_strangers: true, email_in: email_in)
process_email(from: user_email, to: email_in, body: body)
@ -636,7 +637,7 @@ greatest show ever created. Everyone should watch it.
SiteSetting.allow_staged_accounts = true
end
it "creates a message for allowed group" do
it "creates a message for matching group" do
Fabricate(:group, incoming_email: incoming_email)
process_email(from: user_email, to: incoming_email, body: body)
@ -652,4 +653,31 @@ greatest show ever created. Everyone should watch it.
end
describe "supports incoming mail in CC fields" do
let(:incoming_email) { "foo@bar.com" }
let(:user_email) { "#{SecureRandom.hex(32)}@foobar.com" }
let(:body) { "This is a message to\n\na group via CC ;)" }
before do
SiteSetting.email_in = true
SiteSetting.allow_staged_accounts = true
end
it "creates a message for matching group" do
Fabricate(:group, incoming_email: incoming_email)
process_email(from: user_email, to: "some@email.com", body: body, cc: incoming_email)
staged_account = User.find_by_email(user_email)
expect(staged_account).to be
expect(staged_account.staged).to be(true)
post = staged_account.posts.order(id: :desc).first
expect(post).to be
expect(post.raw).to eq(body)
expect(post.topic.private_message?).to eq(true)
end
end
end

Binary file not shown.