# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ class FailedEmail < ApplicationModel def reprocess(params = {}) ticket, _article, _user, _mail = Channel::EmailParser.new.process_with_timeout(params, data) raise __('Unknown error: Could not create a ticket from this email.') if !ticket destroy ticket rescue => e self.retries += 1 self.parsing_error = e save! message = "Can't reprocess failed email '#{id}'. This was attempt # #{retries}." puts "ERROR: #{message}" # rubocop:disable Rails/Output puts "ERROR: #{e.inspect}" # rubocop:disable Rails/Output Rails.logger.error message Rails.logger.error e false end def parsing_error=(input) message = case input when StandardError "#{input.inspect}\n#{input.backtrace&.join("\n")}" else input end write_attribute :parsing_error, message end def self.by_filepath(filepath) id = Pathname .new(filepath) .basename .to_s .delete_suffix('.eml') return if id.include?('.') find_by(id:) end def self.reprocess_all(params = {}) reorder(id: :desc) .in_batches .each_record .select { |elem| elem.reprocess(params) } .map { |elem| "#{elem.id}.eml" } end def self.generate_path Rails.root.join('tmp', "failed-email-#{SecureRandom.uuid}") end def self.export_all(path = generate_path) in_batches .each_record .map { |elem| elem.export(path) } end def export(path = self.class.generate_path) FileUtils.mkdir_p(path) full_path = path.join("#{id}.eml") File.binwrite full_path, data full_path end def self.import_all(path) Dir .each_child(path) .filter_map do |filename| next if !filename.ends_with?('.eml') import(path.join(filename)) end end def self.import(filepath) failed_email = FailedEmail.by_filepath(filepath.basename) return if !failed_email new_data = File.binread filepath if new_data != failed_email.data failed_email.data = new_data failed_email.parsing_error = nil failed_email.save! end return if !failed_email.reprocess filepath.unlink filepath end end