mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 19:33:44 +08:00
1de8361d2e
Currently processing emails that are blank or have a nil value for the mail will cause several errors. This update allows emails with blank body or missing sender to log the blank email error to the mail logs rather than throwing an error.
188 lines
6.3 KiB
Ruby
188 lines
6.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Email
|
|
class Processor
|
|
attr_reader :receiver
|
|
|
|
def initialize(mail, opts = {})
|
|
@mail = mail
|
|
@opts = opts
|
|
end
|
|
|
|
def self.process!(mail, opts = {})
|
|
Email::Processor.new(mail, opts).process!
|
|
end
|
|
|
|
def process!
|
|
begin
|
|
@receiver = Email::Receiver.new(@mail, @opts)
|
|
@receiver.process!
|
|
rescue RateLimiter::LimitExceeded
|
|
if @opts[:retry_on_rate_limit]
|
|
Jobs.enqueue(:process_email, mail: @mail, source: @opts[:source])
|
|
else
|
|
raise
|
|
end
|
|
rescue => e
|
|
return handle_bounce(e) if @receiver&.is_bounce?
|
|
|
|
log_email_process_failure(@mail, e)
|
|
incoming_email = @receiver.try(:incoming_email)
|
|
rejection_message = handle_failure(@mail, e)
|
|
if rejection_message.present?
|
|
set_incoming_email_rejection_message(incoming_email, rejection_message.body.to_s)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def handle_bounce(e)
|
|
# never reply to bounced emails
|
|
log_email_process_failure(@mail, e)
|
|
set_incoming_email_rejection_message(
|
|
@receiver.incoming_email,
|
|
I18n.t("emails.incoming.errors.bounced_email_error"),
|
|
)
|
|
end
|
|
|
|
def handle_failure(mail_string, e)
|
|
message_template =
|
|
case e
|
|
when Email::Receiver::NoSenderDetectedError
|
|
return nil
|
|
when Email::Receiver::FromReplyByAddressError
|
|
return nil
|
|
when Email::Receiver::EmptyEmailError
|
|
:email_reject_empty
|
|
when Email::Receiver::NoBodyDetectedError
|
|
:email_reject_empty
|
|
when Email::Receiver::UserNotFoundError
|
|
:email_reject_user_not_found
|
|
when Email::Receiver::ScreenedEmailError
|
|
:email_reject_screened_email
|
|
when Email::Receiver::EmailNotAllowed
|
|
:email_reject_not_allowed_email
|
|
when Email::Receiver::AutoGeneratedEmailError
|
|
:email_reject_auto_generated
|
|
when Email::Receiver::InactiveUserError
|
|
:email_reject_inactive_user
|
|
when Email::Receiver::SilencedUserError
|
|
:email_reject_silenced_user
|
|
when Email::Receiver::BadDestinationAddress
|
|
:email_reject_bad_destination_address
|
|
when Email::Receiver::StrangersNotAllowedError
|
|
:email_reject_strangers_not_allowed
|
|
when Email::Receiver::InsufficientTrustLevelError
|
|
:email_reject_insufficient_trust_level
|
|
when Email::Receiver::ReplyUserNotMatchingError
|
|
:email_reject_reply_user_not_matching
|
|
when Email::Receiver::TopicNotFoundError
|
|
:email_reject_topic_not_found
|
|
when Email::Receiver::TopicClosedError
|
|
:email_reject_topic_closed
|
|
when Email::Receiver::InvalidPost
|
|
:email_reject_invalid_post
|
|
when Email::Receiver::TooShortPost
|
|
:email_reject_post_too_short
|
|
when Email::Receiver::UnsubscribeNotAllowed
|
|
:email_reject_invalid_post
|
|
when ActiveRecord::Rollback
|
|
:email_reject_invalid_post
|
|
when Email::Receiver::InvalidPostAction
|
|
:email_reject_invalid_post_action
|
|
when Discourse::InvalidAccess
|
|
:email_reject_invalid_access
|
|
when Email::Receiver::OldDestinationError
|
|
:email_reject_old_destination
|
|
when Email::Receiver::ReplyNotAllowedError
|
|
:email_reject_reply_not_allowed
|
|
when Email::Receiver::ReplyToDigestError
|
|
:email_reject_reply_to_digest
|
|
when Email::Receiver::TooManyRecipientsError
|
|
:email_reject_too_many_recipients
|
|
else
|
|
:email_reject_unrecognized_error
|
|
end
|
|
|
|
template_args = {}
|
|
client_message = nil
|
|
|
|
# there might be more information available in the exception
|
|
if message_template == :email_reject_invalid_post && e.message.size > 6
|
|
message_template = :email_reject_invalid_post_specified
|
|
template_args[:post_error] = e.message
|
|
end
|
|
|
|
if message_template == :email_reject_post_too_short
|
|
template_args[:count] = SiteSetting.min_post_length
|
|
end
|
|
|
|
if message_template == :email_reject_unrecognized_error
|
|
msg = "Unrecognized error type (#{e.class}: #{e.message}) when processing incoming email"
|
|
msg += "\n\nBacktrace:\n#{e.backtrace.map { |l| " #{l}" }.join("\n")}"
|
|
msg += "\n\nMail:\n#{mail_string}"
|
|
|
|
Rails.logger.error(msg)
|
|
end
|
|
|
|
if message_template == :email_reject_old_destination
|
|
template_args[:short_url] = e.message
|
|
template_args[:number_of_days] = SiteSetting.disallow_reply_by_email_after_days
|
|
end
|
|
|
|
if message_template == :email_reject_too_many_recipients
|
|
template_args[:recipients_count] = e.recipients_count
|
|
template_args[:max_recipients_count] = SiteSetting.maximum_recipients_per_new_group_email
|
|
end
|
|
|
|
if message_template
|
|
# inform the user about the rejection
|
|
message = Mail::Message.new(mail_string)
|
|
template_args[:former_title] = message.subject
|
|
template_args[:destination] = message.to
|
|
template_args[:site_name] = SiteSetting.title
|
|
|
|
client_message =
|
|
RejectionMailer.send_rejection(message_template, message.from, template_args)
|
|
|
|
# only send one rejection email per day to the same email address
|
|
if can_send_rejection_email?(message.from, message_template)
|
|
Email::Sender.new(client_message, message_template).send
|
|
end
|
|
end
|
|
|
|
client_message
|
|
end
|
|
|
|
def can_send_rejection_email?(email, type)
|
|
return false if @receiver&.sent_to_mailinglist_mirror?
|
|
return true if type == :email_reject_unrecognized_error
|
|
|
|
key = "rejection_email:#{email}:#{type}:#{Date.today}"
|
|
|
|
if Discourse.redis.setnx(key, "1")
|
|
Discourse.redis.expire(key, 25.hours)
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
def set_incoming_email_rejection_message(incoming_email, message)
|
|
if incoming_email
|
|
incoming_email.update!(
|
|
rejection_message: message,
|
|
raw: Email::Cleaner.new(incoming_email.raw, rejected: true).execute,
|
|
)
|
|
end
|
|
end
|
|
|
|
def log_email_process_failure(mail_string, exception)
|
|
if SiteSetting.log_mail_processing_failures
|
|
Rails.logger.warn("Email can not be processed: #{exception}\n\n#{mail_string}")
|
|
end
|
|
end
|
|
end
|
|
end
|