class FatFreeCRM::MailProcessor::Base
Constants
- KEYWORDS
Public Class Methods
new()
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 20 def initialize @archived = 0 @discarded = 0 @dry_run = false end
Public Instance Methods
run(dry_run = false)
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 52 def run(dry_run = false) log "Not discarding or archiving any new messages..." if @dry_run = dry_run connect! || (return nil) with_new_emails do |uid, email| # Subclasses must define a #process method that takes arguments: uid, email process(uid, email) archive(uid) end ensure log "messages processed=#{@archived + @discarded} archived=#{@archived} discarded=#{@discarded}" disconnect! end
setup()
click to toggle source
Setup imap folders in settings.
# File lib/fat_free_crm/mail_processor/base.rb, line 28 def setup log "connecting to #{@settings[:server]}..." connect!(setup: true) || (return nil) log "logged in to #{@settings[:server]}, checking folders..." folders = [@settings[:scan_folder]] folders << @settings[:move_to_folder] unless @settings[:move_to_folder].blank? folders << @settings[:move_invalid_to_folder] unless @settings[:move_invalid_to_folder].blank? # Open (or create) destination folder in read-write mode. folders.each do |folder| if @imap.list("", folder) log "folder #{folder} OK" else log "folder #{folder} missing, creating..." @imap.create(folder) end end rescue Exception => e warn "setup error #{e.inspect}" ensure disconnect! end
Private Instance Methods
archive(uid)
click to toggle source
Archive message (valid) action based on settings
# File lib/fat_free_crm/mail_processor/base.rb, line 136 def archive(uid) if @dry_run log "Not archiving message" else @imap.uid_copy(uid, @settings[:move_to_folder]) if @settings[:move_to_folder] @imap.uid_store(uid, "+FLAGS", [:Seen]) end @archived += 1 end
clean_invalid_utf8_bytes(text, src_encoding)
click to toggle source
Forces the encoding of the given string to UTF8 and replaces invalid characters. This is necessary as emails sometimes have invalid characters like MS “Smart Quotes.”
# File lib/fat_free_crm/mail_processor/base.rb, line 219 def clean_invalid_utf8_bytes(text, src_encoding) text.encode( 'UTF-8', src_encoding, invalid: :replace, undef: :replace, replace: '' ) end
connect!(options = {})
click to toggle source
Connects to the imap server with the loaded settings
# File lib/fat_free_crm/mail_processor/base.rb, line 69 def connect!(options = {}) log "connecting & logging in to #{@settings[:server]}..." @imap = Net::IMAP.new(@settings[:server], @settings[:port], @settings[:ssl]) @imap.login(@settings[:user], @settings[:password]) log "logged in to #{@settings[:server]}, checking folders..." @imap.select(@settings[:scan_folder]) unless options[:setup] @imap rescue Exception => e warn "Could not login to the IMAP server: #{e.inspect}" unless Rails.env == "test" nil end
discard(uid)
click to toggle source
Discard message (not valid) action based on settings
# File lib/fat_free_crm/mail_processor/base.rb, line 124 def discard(uid) if @dry_run log "Not discarding message" else @imap.uid_copy(uid, @settings[:move_invalid_to_folder]) if @settings[:move_invalid_to_folder] @imap.uid_store(uid, "+FLAGS", [:Deleted]) end @discarded += 1 end
disconnect!()
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 82 def disconnect! if @imap @imap.logout unless @imap.disconnected? begin @imap.disconnect rescue Exception nil end end end end
find_sender(email_address)
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 162 def find_sender(email_address) if @sender = User.find_by( '(lower(email) = :email OR lower(alt_email) = :email) AND suspended_at IS NULL', email: email_address.downcase ) # Set the PaperTrail user for versions (if user is found) PaperTrail.request.whodunnit = @sender.id.to_s end end
is_valid?(email)
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 147 def is_valid?(email) valid = email.content_type != "text/html" log("not a text message, discarding") unless valid valid end
log(message, email = nil)
click to toggle source
Centralized logging.
# File lib/fat_free_crm/mail_processor/base.rb, line 183 def log(message, email = nil) unless %w[test cucumber].include?(Rails.env) klass = self.class.to_s.split("::").last klass << " [Dry Run]" if @dry_run puts "[#{Time.now.rfc822}] #{klass}: #{message}" puts "[#{Time.now.rfc822}] #{klass}: From: #{email.from}, Subject: #{email.subject} (#{email.message_id})" if email end end
plain_text_body(email)
click to toggle source
Returns the plain-text version of an email, or strips html tags if only html is present.
# File lib/fat_free_crm/mail_processor/base.rb, line 195 def plain_text_body(email) # Extract all parts including nested parts = if email.multipart? email.parts.map { |p| p.multipart? ? p.parts : p }.flatten else charset = email.charset [email] end if text_part = parts.detect { |p| p.content_type.include?('text/plain') } text_body = text_part.body.to_s charset = text_part.charset if email.multipart? else html_part = parts.detect { |p| p.content_type.include?('text/html') } || email text_body = Premailer.new(html_part.body.to_s, with_html_string: true).to_plain_text charset = html_part.charset if email.multipart? end # Convert to UTF8 and standardize newline clean_invalid_utf8_bytes(text_body.strip.gsub("\r\n", "\n"), charset) end
sender_has_permissions_for?(asset)
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 173 def sender_has_permissions_for?(asset) return true if asset.access == "Public" return true if asset.user_id == @sender.id || asset.assigned_to == @sender.id return true if asset.access == "Shared" && Permission.exists('user_id = ? AND asset_id = ? AND asset_type = ?', @sender.id, asset.id, asset.class.to_s) false end
sent_from_known_user?(email)
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 154 def sent_from_known_user?(email) email_address = email.from.first known = !find_sender(email_address).nil? log("sent by unknown user #{email_address}, discarding") unless known known end
with_new_emails() { |uid, email| ... }
click to toggle source
# File lib/fat_free_crm/mail_processor/base.rb, line 96 def with_new_emails @imap.uid_search(%w[NOT SEEN]).each do |uid| begin email = Mail.new(@imap.uid_fetch(uid, 'RFC822').first.attr['RFC822']) log "fetched new message...", email if is_valid?(email) && sent_from_known_user?(email) yield(uid, email) else discard(uid) end rescue Exception => e if %w[test development].include?(Rails.env) warn e warn e.backtrace end log "error processing email: #{e.inspect}", email discard(uid) end if @dry_run log "Marking message as unread" @imap.uid_store(uid, "-FLAGS", [:Seen]) end end end