class EmailFetchAndProcess

Wrap up the logic to iterate through a bunch of fetch and handle jobs. This is the simplest thing that can work code. It could be generalized a lot pretty easily.

Constants

VERSION

Attributes

destination[RW]

Public Class Methods

new(args = {}) click to toggle source
# File lib/email-fetch-and-process.rb, line 57
def initialize(args = {})
  @args = default_args.merge args
  @destination = '/tmp'
end

Public Instance Methods

default_args() click to toggle source
# File lib/email-fetch-and-process.rb, line 62
def default_args
  {
    host: '127.0.0.1',
    port: 993,
    tls: true,
    id: nil,
    password: nil,
    mailbox: 'INBOX'
  }
end
handle_parts(parts, job, msg_ids) click to toggle source
# File lib/email-fetch-and-process.rb, line 80
def handle_parts(parts, job, msg_ids)
  parts.each do |part|
    if !part.parts.empty?
      handle_parts(part.parts, job, msg_ids)
    else
      begin
        name = if job.filename.to_s.empty?
                 part.header[:content_disposition].filename || part.filename rescue part.filename
               else
                 job.filename
               end
        name = Mail::Encodings.decode_encode(name, :decode) if name rescue name
      rescue StandardError => e
        puts e, e.backtrace.inspect
        next
      end
      next unless name

      @body_index += 1
      attachment = part
      final_destination = job.destination || @destination
      attachment_path = File.expand_path(File.join(final_destination, name))
      attachment_path = nil unless attachment_path =~ /^#{final_destination}/
      next unless final_destination != attachment_path

      if attachment && attachment_path
        file_path = File.join([final_destination, job.subdirectory, name].compact)
        atch = attachment.body.to_s
        FileUtils.mkdir_p File.dirname(file_path) unless FileTest.exist? File.dirname(file_path)
        File.open(file_path, 'wb+') do |fh|
          fh.write atch.respond_to?(:each) ? atch.join : atch
        end
        sha_new = `/usr/bin/shasum "#{file_path}"`.split(/\s+/).first
        sha_old = nil
        FileTest.exist?("#{file_path}.sha") &&
          File.open("#{file_path}.sha", 'r') { |fh| sha_old = fh.read.chomp }
        if sha_new != sha_old
          command_to_run = job.action.gsub(/FILEPATH/, Shellwords.escape(file_path)).
            gsub(/DESTINATION/, Shellwords.escape(final_destination))
          system(command_to_run) &&
            File.open("#{file_path}.sha", 'w+') { |fh| fh.write sha_new }
        end
      end
    end
  end
end
imap_connection() click to toggle source
# File lib/email-fetch-and-process.rb, line 73
def imap_connection
  imap = Net::IMAP.new(@args[:host], port: @args[:port], ssl: { verify_mode: OpenSSL::SSL::VERIFY_NONE })
  imap.login(@args[:id], @args[:password])
  imap.examine(@args[:mailbox])
  imap
end
run(jobs = []) click to toggle source
# File lib/email-fetch-and-process.rb, line 127
def run(jobs = [])
  @imap = imap_connection

  jobs.each do |job|
    msg_ids = if job.multiple_fetch_terms?
                all_ids = []
                job.fetch.each { |j| all_ids += @imap.search(j) }
                all_ids
              else
                @imap.search(job.fetch)
              end
    next if msg_ids.nil? || msg_ids.empty?

    begin
      msgs = @imap.fetch(msg_ids, %w[ENVELOPE RFC822])
      msg = msgs.max_by { |m| Time.parse(m['attr']['ENVELOPE'].date) }.attr['RFC822']

      @body_index = 1
    rescue StandardError => err
      puts "Error: #{err}\n#{err.backtrace.join("\n")}"
      @imap = imap_connection
      next
    end
    body = Mail.read_from_string msg
    handle_parts(body.attachments, job, msg_ids) unless body.attachments.empty?
  end

  @imap.close
end