mirror of
https://github.com/discourse/discourse.git
synced 2024-11-24 07:34:18 +08:00
4086ee551e
Whenever we got a bounced email in the Email::Receiver we previously would just set bounced: true on the EmailLog and discard the status/diagnostic code. This commit changes this flow to store the bounce error code (defined in the RFC at https://www.iana.org/assignments/smtp-enhanced-status-codes/smtp-enhanced-status-codes.xhtml) not just in the Email::Receiver, but also via webhook events from other mail services and from SNS. This commit does not surface the bounce error in the UI, we can do that later if necessary.
147 lines
3.7 KiB
Ruby
147 lines
3.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class EmailLog < ActiveRecord::Base
|
|
CRITICAL_EMAIL_TYPES ||= Set.new %w{
|
|
account_created
|
|
admin_login
|
|
confirm_new_email
|
|
confirm_old_email
|
|
confirm_old_email_add
|
|
forgot_password
|
|
notify_old_email
|
|
notify_old_email_add
|
|
signup
|
|
signup_after_approval
|
|
}
|
|
|
|
belongs_to :user
|
|
belongs_to :post
|
|
belongs_to :smtp_group, class_name: 'Group'
|
|
|
|
validates :email_type, :to_address, presence: true
|
|
|
|
scope :bounced, -> { where(bounced: true) }
|
|
|
|
scope :addressed_to_user, ->(user) do
|
|
where(<<~SQL, user_id: user.id)
|
|
EXISTS(
|
|
SELECT 1
|
|
FROM user_emails
|
|
WHERE user_emails.user_id = :user_id AND
|
|
(email_logs.to_address = user_emails.email OR
|
|
email_logs.cc_addresses ILIKE '%' || user_emails.email || '%')
|
|
)
|
|
SQL
|
|
end
|
|
|
|
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?
|
|
end
|
|
|
|
def topic
|
|
@topic ||= self.topic_id.present? ? Topic.find_by(id: self.topic_id) : self.post&.topic
|
|
end
|
|
|
|
def self.unique_email_per_post(post, user)
|
|
return yield unless post && user
|
|
|
|
DistributedMutex.synchronize("email_log_#{post.id}_#{user.id}") do
|
|
if where(post_id: post.id, user_id: user.id).exists?
|
|
nil
|
|
else
|
|
yield
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.reached_max_emails?(user, email_type = nil)
|
|
return false if SiteSetting.max_emails_per_day_per_user == 0 || CRITICAL_EMAIL_TYPES.include?(email_type)
|
|
|
|
count = where('created_at > ?', 1.day.ago)
|
|
.where(user_id: user.id)
|
|
.count
|
|
|
|
count >= SiteSetting.max_emails_per_day_per_user
|
|
end
|
|
|
|
def self.count_per_day(start_date, end_date)
|
|
where("created_at BETWEEN ? AND ?", start_date, end_date)
|
|
.group("DATE(created_at)")
|
|
.order("DATE(created_at)")
|
|
.count
|
|
end
|
|
|
|
def self.for(reply_key)
|
|
self.find_by(reply_key: reply_key)
|
|
end
|
|
|
|
def self.last_sent_email_address
|
|
self.where(email_type: "signup")
|
|
.order(created_at: :desc)
|
|
.limit(1)
|
|
.pluck(:to_address)
|
|
.first
|
|
end
|
|
|
|
def bounce_key
|
|
super&.delete('-')
|
|
end
|
|
|
|
def cc_users
|
|
return [] if !self.cc_user_ids
|
|
@cc_users ||= User.where(id: self.cc_user_ids)
|
|
end
|
|
|
|
def cc_addresses_split
|
|
@cc_addresses_split ||= self.cc_addresses&.split(";") || []
|
|
end
|
|
|
|
def as_mail_message
|
|
return if self.raw.blank?
|
|
@mail_message ||= Mail.new(self.raw)
|
|
end
|
|
|
|
def raw_headers
|
|
return if self.raw.blank?
|
|
as_mail_message.header.raw_source
|
|
end
|
|
|
|
def raw_body
|
|
return if self.raw.blank?
|
|
as_mail_message.body
|
|
end
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: email_logs
|
|
#
|
|
# id :integer not null, primary key
|
|
# to_address :string not null
|
|
# email_type :string not null
|
|
# user_id :integer
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# post_id :integer
|
|
# bounce_key :uuid
|
|
# bounced :boolean default(FALSE), not null
|
|
# message_id :string
|
|
# smtp_group_id :integer
|
|
# cc_addresses :text
|
|
# cc_user_ids :integer is an Array
|
|
# raw :text
|
|
# topic_id :integer
|
|
# bounce_error_code :string
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_email_logs_on_bounce_key (bounce_key) UNIQUE WHERE (bounce_key IS NOT NULL)
|
|
# index_email_logs_on_bounced (bounced)
|
|
# index_email_logs_on_created_at (created_at)
|
|
# index_email_logs_on_message_id (message_id)
|
|
# index_email_logs_on_post_id (post_id)
|
|
# index_email_logs_on_topic_id (topic_id) WHERE (topic_id IS NOT NULL)
|
|
# index_email_logs_on_user_id (user_id)
|
|
#
|