مراية لـ
https://github.com/postalserver/postal.git
تم المزامنة 2026-03-04 14:54:08 +00:00
refactor: refactors message dequeueing (#2810)
هذا الالتزام موجود في:
190
app/lib/message_dequeuer/outgoing_message_processor.rb
Normal file
190
app/lib/message_dequeuer/outgoing_message_processor.rb
Normal file
@@ -0,0 +1,190 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module MessageDequeuer
|
||||
class OutgoingMessageProcessor < Base
|
||||
|
||||
def process
|
||||
catch_stops do
|
||||
check_domain
|
||||
check_rcpt_to
|
||||
add_tag
|
||||
hold_if_credential_is_set_to_hold
|
||||
hold_if_recipient_on_suppression_list
|
||||
parse_content
|
||||
inspect_message
|
||||
fail_if_spam
|
||||
add_outgoing_headers
|
||||
check_send_limits
|
||||
increment_live_stats
|
||||
hold_if_server_development_mode
|
||||
send_message_to_sender
|
||||
add_recipient_to_suppression_list_on_too_many_hard_fails
|
||||
remove_recipient_from_suppression_list_on_success
|
||||
log_sender_result
|
||||
finish_processing
|
||||
end
|
||||
rescue StandardError => e
|
||||
handle_exception(e)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_domain
|
||||
return if queued_message.message.domain
|
||||
|
||||
log "message has no domain, hard failing"
|
||||
create_delivery "HardFail", details: "Message's domain no longer exist"
|
||||
remove_from_queue
|
||||
stop_processing
|
||||
end
|
||||
|
||||
def check_rcpt_to
|
||||
return unless queued_message.message.rcpt_to.blank?
|
||||
|
||||
log "message has no 'to' address, hard failing"
|
||||
create_delivery "HardFail", details: "Message doesn't have an RCPT to"
|
||||
remove_from_queue
|
||||
stop_processing
|
||||
end
|
||||
|
||||
def add_tag
|
||||
return if queued_message.message.tag
|
||||
return unless tag = queued_message.message.headers["x-postal-tag"]
|
||||
|
||||
log "added tag: #{tag.last}"
|
||||
queued_message.message.update(tag: tag.last)
|
||||
end
|
||||
|
||||
def hold_if_credential_is_set_to_hold
|
||||
return if queued_message.manual?
|
||||
return if queued_message.message.credential.nil?
|
||||
return unless queued_message.message.credential.hold?
|
||||
|
||||
log "credential wants us to hold messages, holding"
|
||||
create_delivery "Held", details: "Credential is configured to hold all messages authenticated by it."
|
||||
remove_from_queue
|
||||
stop_processing
|
||||
end
|
||||
|
||||
def hold_if_recipient_on_suppression_list
|
||||
return if queued_message.manual?
|
||||
return unless sl = queued_message.server.message_db.suppression_list.get(:recipient, queued_message.message.rcpt_to)
|
||||
|
||||
log "recipient is on the suppression list, holding"
|
||||
create_delivery "Held", details: "Recipient (#{queued_message.message.rcpt_to}) is on the suppression list (reason: #{sl['reason']})"
|
||||
remove_from_queue
|
||||
stop_processing
|
||||
end
|
||||
|
||||
def parse_content
|
||||
return unless queued_message.message.should_parse?
|
||||
|
||||
log "parsing message content as it hasn't been parsed before"
|
||||
queued_message.message.parse_content
|
||||
end
|
||||
|
||||
def inspect_message
|
||||
return if queued_message.message.inspected
|
||||
return unless queued_message.server.outbound_spam_threshold
|
||||
|
||||
log "inspecting message"
|
||||
queued_message.message.inspect_message
|
||||
return unless queued_message.message.inspected
|
||||
|
||||
if queued_message.message.spam_score >= queued_message.server.outbound_spam_threshold
|
||||
queued_message.message.update(spam: true)
|
||||
end
|
||||
|
||||
log "message inspected successfully", spam: queued_message.message.spam?, spam_score: queued_message.message.spam_score
|
||||
end
|
||||
|
||||
def fail_if_spam
|
||||
return unless queued_message.message.spam
|
||||
|
||||
log "message is spam (#{queued_message.message.spam_score}), hard failing", server_threshold: queued_message.server.outbound_spam_threshold
|
||||
create_delivery "HardFail",
|
||||
details: "Message is likely spam. Threshold is #{queued_message.server.outbound_spam_threshold} and " \
|
||||
"the message scored #{queued_message.message.spam_score}."
|
||||
remove_from_queue
|
||||
stop_processing
|
||||
end
|
||||
|
||||
def add_outgoing_headers
|
||||
return if queued_message.message.has_outgoing_headers?
|
||||
|
||||
queued_message.message.add_outgoing_headers
|
||||
end
|
||||
|
||||
def check_send_limits
|
||||
if queued_message.server.send_limit_exceeded?
|
||||
# If we're over the limit, we're going to be holding this message
|
||||
log "server send limit has been exceeded, holding", send_limit: queued_message.server.send_limit
|
||||
queued_message.server.update_columns(send_limit_exceeded_at: Time.now, send_limit_approaching_at: nil)
|
||||
create_delivery "Held", details: "Message held because send limit (#{queued_message.server.send_limit}) has been reached."
|
||||
remove_from_queue
|
||||
stop_processing
|
||||
elsif queued_message.server.send_limit_approaching?
|
||||
# If we're approaching the limit, just say we are but continue to process the message
|
||||
queued_message.server.update_columns(send_limit_approaching_at: Time.now, send_limit_exceeded_at: nil)
|
||||
else
|
||||
queued_message.server.update_columns(send_limit_approaching_at: nil, send_limit_exceeded_at: nil)
|
||||
end
|
||||
end
|
||||
|
||||
def send_message_to_sender
|
||||
@result = @state.send_result
|
||||
return if @result
|
||||
|
||||
sender = @state.sender_for(Postal::SMTPSender,
|
||||
queued_message.message.recipient_domain,
|
||||
queued_message.ip_address)
|
||||
|
||||
@result = sender.send_message(queued_message.message)
|
||||
return unless @result.connect_error
|
||||
|
||||
@state.send_result = @result
|
||||
end
|
||||
|
||||
def add_recipient_to_suppression_list_on_too_many_hard_fails
|
||||
return unless @result.type == "HardFail"
|
||||
|
||||
recent_hard_fails = queued_message.server.message_db.select(:messages,
|
||||
where: {
|
||||
rcpt_to: queued_message.message.rcpt_to,
|
||||
status: "HardFail",
|
||||
timestamp: { greater_than: 24.hours.ago.to_f }
|
||||
},
|
||||
count: true)
|
||||
return if recent_hard_fails < 1
|
||||
|
||||
added = queued_message.server.message_db.suppression_list.add(:recipient, queued_message.message.rcpt_to,
|
||||
reason: "too many hard fails")
|
||||
return unless added
|
||||
|
||||
log "Added #{queued_message.message.rcpt_to} to suppression list because #{recent_hard_fails} hard fails in 24 hours"
|
||||
@additional_delivery_details = "Recipient added to suppression list (too many hard fails)"
|
||||
end
|
||||
|
||||
def remove_recipient_from_suppression_list_on_success
|
||||
return unless @result.type == "Sent"
|
||||
|
||||
removed = queued_message.server.message_db.suppression_list.remove(:recipient, queued_message.message.rcpt_to)
|
||||
return unless removed
|
||||
|
||||
log "removed #{queued_message.message.rcpt_to} from suppression list"
|
||||
@additional_delivery_details = "Recipient removed from suppression list"
|
||||
end
|
||||
|
||||
def finish_processing
|
||||
if @result.retry
|
||||
queued_message.retry_later(@result.retry.is_a?(Integer) ? @result.retry : nil)
|
||||
log "message requeued for trying later", retry_after: queued_message.retry_after
|
||||
stop_processing
|
||||
end
|
||||
|
||||
log "message processing complete"
|
||||
remove_from_queue
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
المرجع في مشكلة جديدة
حظر مستخدم