مراية لـ
https://github.com/postalserver/postal.git
تم المزامنة 2025-12-01 05:43:04 +00:00
135 أسطر
4.2 KiB
Ruby
135 أسطر
4.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class HTTPSender < BaseSender
|
|
|
|
def initialize(endpoint, options = {})
|
|
super()
|
|
@endpoint = endpoint
|
|
@options = options
|
|
@log_id = SecureRandom.alphanumeric(8).upcase
|
|
end
|
|
|
|
def send_message(message)
|
|
start_time = Time.now
|
|
result = SendResult.new
|
|
result.log_id = @log_id
|
|
|
|
request_options = {}
|
|
request_options[:sign] = true
|
|
request_options[:timeout] = @endpoint.timeout || 5
|
|
case @endpoint.encoding
|
|
when "BodyAsJSON"
|
|
request_options[:json] = parameters(message, flat: false).to_json
|
|
when "FormData"
|
|
request_options[:params] = parameters(message, flat: true)
|
|
end
|
|
|
|
log "Sending request to #{@endpoint.url}"
|
|
response = Postal::HTTP.post(@endpoint.url, request_options)
|
|
result.secure = !!response[:secure] # rubocop:disable Style/DoubleNegation
|
|
result.details = "Received a #{response[:code]} from #{@endpoint.url}"
|
|
log " -> Received: #{response[:code]}"
|
|
if response[:body]
|
|
log " -> Body: #{response[:body][0, 255]}"
|
|
result.output = response[:body].to_s[0, 500].strip
|
|
end
|
|
if response[:code] >= 200 && response[:code] < 300
|
|
# This is considered a success
|
|
result.type = "Sent"
|
|
elsif response[:code] >= 500 && response[:code] < 600
|
|
# This is temporary. They might fix their server so it should soft fail.
|
|
result.type = "SoftFail"
|
|
result.retry = true
|
|
elsif response[:code].negative?
|
|
# Connection/SSL etc... errors
|
|
result.type = "SoftFail"
|
|
result.retry = true
|
|
result.connect_error = true
|
|
elsif response[:code] == 429
|
|
# Rate limit exceeded, treat as a hard fail and don't send bounces
|
|
result.type = "HardFail"
|
|
result.suppress_bounce = true
|
|
else
|
|
# This is permanent. Any other error isn't cool with us.
|
|
result.type = "HardFail"
|
|
end
|
|
result.time = (Time.now - start_time).to_f.round(2)
|
|
result
|
|
end
|
|
|
|
private
|
|
|
|
def log(text)
|
|
Postal.logger.info text, id: @log_id, component: "http-sender"
|
|
end
|
|
|
|
def parameters(message, options = {})
|
|
case @endpoint.format
|
|
when "Hash"
|
|
hash = {
|
|
id: message.id,
|
|
rcpt_to: message.rcpt_to,
|
|
mail_from: message.mail_from,
|
|
token: message.token,
|
|
subject: message.subject,
|
|
message_id: message.message_id,
|
|
timestamp: message.timestamp.to_f,
|
|
size: message.size,
|
|
spam_status: message.spam_status,
|
|
bounce: message.bounce,
|
|
received_with_ssl: message.received_with_ssl,
|
|
to: message.headers["to"]&.last,
|
|
cc: message.headers["cc"]&.last,
|
|
from: message.headers["from"]&.last,
|
|
date: message.headers["date"]&.last,
|
|
in_reply_to: message.headers["in-reply-to"]&.last,
|
|
references: message.headers["references"]&.last,
|
|
html_body: message.html_body,
|
|
attachment_quantity: message.attachments.size,
|
|
auto_submitted: message.headers["auto-submitted"]&.last,
|
|
reply_to: message.headers["reply-to"]
|
|
}
|
|
|
|
if @endpoint.strip_replies
|
|
hash[:plain_body], hash[:replies_from_plain_body] = ReplySeparator.separate(message.plain_body)
|
|
else
|
|
hash[:plain_body] = message.plain_body
|
|
end
|
|
|
|
if @endpoint.include_attachments?
|
|
if options[:flat]
|
|
message.attachments.each_with_index do |a, i|
|
|
hash["attachments[#{i}][filename]"] = a.filename
|
|
hash["attachments[#{i}][content_type]"] = a.content_type
|
|
hash["attachments[#{i}][size]"] = a.body.to_s.bytesize.to_s
|
|
hash["attachments[#{i}][data]"] = Base64.encode64(a.body.to_s)
|
|
end
|
|
else
|
|
hash[:attachments] = message.attachments.map do |a|
|
|
{
|
|
filename: a.filename,
|
|
content_type: a.mime_type,
|
|
size: a.body.to_s.bytesize,
|
|
data: Base64.encode64(a.body.to_s)
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
hash
|
|
when "RawMessage"
|
|
{
|
|
id: message.id,
|
|
rcpt_to: message.rcpt_to,
|
|
mail_from: message.mail_from,
|
|
message: Base64.encode64(message.raw_message),
|
|
base64: true,
|
|
size: message.size.to_i
|
|
}
|
|
else
|
|
{}
|
|
end
|
|
end
|
|
|
|
end
|