class LeadmailDelivery attr_reader :settings def initialize(settings) @settings = settings end def deliver!(message) payload = build_payload(message) response = http_client.post('/emails/send', payload) unless response.success? raise LeadmailDeliveryError, "LeadMail API error: #{response.status} - #{response.body}" end response_data = JSON.parse(response.body) message.header['X-LeadMail-Log-ID'] = response_data.dig('data', 'log_id') Rails.logger.info("Email sent via LeadMail: log_id=#{response_data.dig('data', 'log_id')}, to=#{message.to.inspect}") response rescue StandardError => e Rails.logger.error("LeadMail delivery failed: #{e.message}\nPayload: #{payload.inspect}") raise end private def build_payload(message) { from: extract_from(message), to: extract_recipients(message.to), cc: extract_recipients(message.cc), bcc: extract_recipients(message.bcc), reply_to: extract_reply_to(message), subject: message.subject, html_body: html_body(message), text_body: text_body(message), attachments: extract_attachments(message), options: { on_verification_failure: 'strip', allow_disposable: false } }.compact end def extract_from(message) from_address = message.from&.first from_display = message[:from]&.display_names&.first { email: from_address, name: from_display }.compact end def extract_recipients(addresses) return nil if addresses.blank? Array(addresses).map { |email| { email: email } } end def extract_reply_to(message) reply_to_address = message.reply_to&.first return nil if reply_to_address.blank? { email: reply_to_address } end def html_body(message) return message.html_part.body.to_s if message.html_part.present? return message.body.to_s if message.content_type&.start_with?('text/html') nil end def text_body(message) return message.text_part.body.to_s if message.text_part.present? return message.body.to_s if message.content_type&.start_with?('text/plain') nil end def extract_attachments(message) return nil if message.attachments.blank? message.attachments.map do |attachment| { filename: attachment.filename, mime_type: attachment.mime_type || 'application/octet-stream', content: Base64.strict_encode64(attachment.body.to_s) } end end def http_client @http_client ||= Faraday.new( url: settings[:api_url], headers: { 'Authorization' => "Bearer #{settings[:token]}", 'Content-Type' => 'application/json' } ) end end class LeadmailDeliveryError < StandardError; end