class Stockboy::Providers::IMAP
Read data from a file attachment in IMAP
email
Job
template DSL
¶ ↑
provider :imap do host "imap.example.com" username "arthur@example.com" password "424242" mailbox "INBOX" subject "Daily Report" since Date.today file_name /report-[0-9]+\.csv/ end
Public Class Methods
Initialize a new IMAP
reader
Stockboy::Provider::new
# File lib/stockboy/providers/imap.rb, line 131 def initialize(opts={}, &block) super(opts, &block) @host = opts[:host] @username = opts[:username] @password = opts[:password] @mailbox = opts[:mailbox] @subject = opts[:subject] @from = opts[:from] @since = opts[:since] @search = opts[:search] @attachment = opts[:attachment] @file_smaller = opts[:file_smaller] @file_larger = opts[:file_larger] @pick = opts[:pick] || :last DSL.new(self).instance_eval(&block) if block_given? @open_client = nil end
Public Instance Methods
Clear received data and allow for selecting a new item from the server
Stockboy::Provider#clear
# File lib/stockboy/providers/imap.rb, line 200 def clear super @message_key = nil @data_time = nil @data_size = nil end
Direct access to the configured Net::IMAP
connection
@example
provider.client do |imap| imap.search("FLAGGED") end
# File lib/stockboy/providers/imap.rb, line 156 def client raise(ArgumentError, "no block given") unless block_given? first_connection = @open_client.nil? if first_connection @open_client = ::Net::IMAP.new(host) @open_client.login(username, password) @open_client.examine(mailbox) end yield @open_client rescue ::Net::IMAP::Error errors << "IMAP connection error" ensure if first_connection && @open_client @open_client.disconnect @open_client = nil end end
# File lib/stockboy/providers/imap.rb, line 234 def default_search_options {subject: subject, from: from, since: since}.reject { |k,v| v.nil? } end
Purge the email from the mailbox corresponding to the [#message_key]
This can only be called after selecting the message_key
to confirm the selected item, or after fetching the data.
# File lib/stockboy/providers/imap.rb, line 179 def delete_data picked_message_key? or raise Stockboy::OutOfSequence, "must confirm #message_key or calling #data" client do |imap| logger.info "Deleting message #{inspect_message_key}" imap.uid_store(message_key, "+FLAGS", [:Deleted]) imap.expunge end end
Search the selected mailbox for matching messages
By default, the configured options are used, @param [Hash, Array, String] options
Override default configured search options
@example
provider.find_messages(subject: "Daily Report", before: Date.today) provider.find_messages(["SUBJECT", "Daily Report", "BEFORE", "21-DEC-12"]) provider.find_messages("FLAGGED BEFORE 21-DEC-12")
# File lib/stockboy/providers/imap.rb, line 218 def find_messages(options=nil) client { |imap| imap.sort(['DATE'], search_keys(options), 'UTF-8') } end
IMAP
message id for the email that contains the selected data to process
# File lib/stockboy/providers/imap.rb, line 192 def message_key return @message_key if @message_key message_ids = find_messages(default_search_options) @message_key = pick_from(message_ids) unless message_ids.empty? end
Normalize a hash of search options into an array of IMAP
search keys
@param [Hash] options If none are given, the configured options are used @return [Array]
# File lib/stockboy/providers/imap.rb, line 227 def search_keys(options=nil) case options when Array, String then options else SearchOptions.new(options || default_search_options).to_imap end end
Private Instance Methods
# File lib/stockboy/providers/imap.rb, line 240 def fetch_data client do |imap| open_message(message_key) do |mail| open_attachment(mail) do |part| logger.debug "Getting file from #{inspect_message_key}" @data = part @data_time = normalize_imap_datetime(mail.date) logger.debug "Got file from #{inspect_message_key}" end end end !@data.nil? end
# File lib/stockboy/providers/imap.rb, line 325 def inspect_message_key "#{username}:#{host} message_uid #{message_key}" end
If activesupport is loaded, it mucks with DateTime#to_time to return self when it has a utc_offset. Handle both to always return a Time.utc.
# File lib/stockboy/providers/imap.rb, line 296 def normalize_imap_datetime(datetime) datetime.respond_to?(:getutc) ? datetime.getutc.to_time : datetime.to_time.utc end
# File lib/stockboy/providers/imap.rb, line 264 def open_attachment(mail) file = mail.attachments.detect { |part| validate_attachment(part) } validate_file(file) if file or return yield file.decoded if valid? file end
# File lib/stockboy/providers/imap.rb, line 254 def open_message(id) return unless id client do |imap| imap_message = imap.fetch(id, 'RFC822').first or return mail = ::Mail.new(imap_message.attr['RFC822']) yield mail if block_given? mail end end
# File lib/stockboy/providers/imap.rb, line 278 def picked_message_key? !!@message_key end
# File lib/stockboy/providers/imap.rb, line 321 def read_data_size(data_file) @data_size ||= data_file.body.raw_source.bytesize end
# File lib/stockboy/providers/imap.rb, line 271 def validate errors << "host must be specified" if host.blank? errors << "username must be specified" if username.blank? errors << "password must be specified" if password.blank? errors.empty? end
# File lib/stockboy/providers/imap.rb, line 282 def validate_attachment(part) case attachment when String part.filename == attachment when Regexp part.filename =~ attachment else true end end
# File lib/stockboy/providers/imap.rb, line 301 def validate_file(data_file) return errors << "No matching attachments" unless data_file validate_file_smaller(data_file) validate_file_larger(data_file) end
# File lib/stockboy/providers/imap.rb, line 314 def validate_file_larger(data_file) read_data_size(data_file) if file_larger && data_size < file_larger errors << "File size smaller than #{file_larger}" end end
# File lib/stockboy/providers/imap.rb, line 307 def validate_file_smaller(data_file) read_data_size(data_file) if file_smaller && data_size > file_smaller errors << "File size larger than #{file_smaller}" end end