1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2025-11-30 21:32:30 +00:00
الملفات
postal/app/lib/message_dequeuer/outgoing_message_processor.rb
2024-02-23 22:51:36 +00:00

191 أسطر
7.0 KiB
Ruby

# 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(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