class SesProxy::SmtpServer
Public Class Methods
running?()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 188 def self.running? !!@server end
start(host, port)
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 175 def self.start(host, port) trap(:QUIT) { stop } @host = host @server = EM.start_server host, port, self end
stop()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 181 def self.stop if @server EM.stop_server @server @server = nil end end
Public Instance Methods
get_server_domain()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 21 def get_server_domain @host || "mock.smtp.server.local" end
get_server_greeting()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 25 def get_server_greeting "smtp ses greetings" end
message()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 66 def message @message || "" end
process_data_line(ln)
click to toggle source
Allow EM::Protocols::SmtpServer#receive_message to return an Array so that cases other than succeed/fail can be handled. If an Array is returned it is expected to have two elements, the response code and the message (e.g. [451, “Temp Failure”]). Does not break backward compatibility.
# File lib/ses_proxy/smtp_server.rb, line 195 def process_data_line ln if ln == "." if @databuffer.length > 0 receive_data_chunk @databuffer @databuffer.clear end succeeded = proc { send_data "250 Message accepted\r\n" reset_protocol_state } failed = proc { send_data "550 Message rejected\r\n" reset_protocol_state } d = receive_message if d.respond_to?(:set_deferred_status) d.callback(&succeeded) d.errback(&failed) elsif d.kind_of?(Array) send_data d.join(' ') + "\r\n" reset_protocol_state else (d ? succeeded : failed).call end @state.delete :data else # slice off leading . if any ln.slice!(0...1) if ln[0] == ?. @databuffer << ln if @databuffer.length > @@parms[:chunksize] receive_data_chunk @databuffer @databuffer.clear end end end
receive_data_chunk(data)
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 53 def receive_data_chunk(data) @message = "#{@message}\n#{data.join("\n")}" true end
receive_ehlo_domain(domain)
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 170 def receive_ehlo_domain(domain) @ehlo_domain = domain true end
receive_message()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 78 def receive_message return false unless verified mail = Mail.read_from_string(message + "\n") #https://github.com/mikel/mail/issues/612#issuecomment-35564404 bounced = Bounce.where({:email=>{"$in"=>recipients}, :count=>{"$gte"=>2}, :retry_at=>{"$gte"=>Time.now}}).map(&:email) #Remove bounced addresses actual_recipients = mail.to_addrs - bounced actual_cc_addrs = mail.cc_addrs - bounced actual_bcc_addrs = recipients - (mail.to_addrs + mail.cc_addrs) - bounced #Remove blacklisted domains if SesProxy::Conf.get[:blacklisted_domains] and SesProxy::Conf.get[:blacklisted_domains].any? bld = SesProxy::Conf.get[:blacklisted_domains] _proc = proc {|address| address unless bld.include?(address.split('@').last)} actual_recipients.collect!(&_proc).compact! actual_cc_addrs.collect!(&_proc).compact! actual_bcc_addrs.collect!(&_proc).compact! end #Remove blacklisted regexp if SesProxy::Conf.get[:blacklisted_regexp] and SesProxy::Conf.get[:blacklisted_regexp].any? blr = SesProxy::Conf.get[:blacklisted_regexp] _proc = proc {|address| address unless blr.map{|regexp| Regexp.new(regexp).match(address)}.compact.any? } actual_recipients.collect!(&_proc).compact! actual_cc_addrs.collect!(&_proc).compact! actual_bcc_addrs.collect!(&_proc).compact! end original_number = recipients.size filtered_number = actual_recipients.size + actual_cc_addrs.size + actual_bcc_addrs.size record = RecipientsNumber.new({ :original=>original_number, :filtered=>filtered_number, :created_at => Time.now, :updated_at => Time.now }) record.save! if actual_recipients.any? mail.to = actual_recipients.uniq.join(",") mail.cc = actual_cc_addrs.uniq.join(",") mail.bcc = actual_bcc_addrs.uniq.join(",") mail['X-SES-Proxy'] = 'True' unless SesProxy::Conf.get[:collect_sent_mails].eql? false record = Email.new({ :sender => sender, :recipients => actual_recipients.uniq.join(","), :subject => mail.subject, :body => mail.decode_body, :system => mail['X-Sender-System']||"Unknown", :created_at => Time.now, :updated_at => Time.now }) record.save! end begin if SesProxy::Conf.get[:aws][:ses] and SesProxy::Conf.get[:aws][:ses][:username] and SesProxy::Conf.get[:aws][:ses][:password] mail.deliver! else ses.send_raw_email(mail.to_s) end rescue Exception => e print "Error! " puts e.message return false end else puts "No valid recipients! #{mail.to_addrs}" end if not original_number.eql? filtered_number unless SesProxy::Conf.get[:collect_bounced_mails].eql? false mail.to = (recipients&bounced).uniq.join(",") mail.cc = (mail.cc_addrs&bounced).uniq.join(",") mail.bcc = (mail.bcc_addrs&bounced).uniq.join(",") record = BouncedEmail.new({ :sender => sender, :recipients => (recipients&bounced).uniq.join(","), :subject => mail.subject, :body => mail.decode_body, :system => mail['X-Sender-System']||"Unknown", :created_at => Time.now, :updated_at => Time.now }) record.save! end end if actual_recipients.empty? and SesProxy::Conf.get[:raise_error_if_no_recipients].eql?(true) return [550, "Message rejected because of all recipients are bounced!"] else return true end end
receive_plain_auth(user, password)
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 29 def receive_plain_auth(user, password) @verified = SesProxy::Conf.get[:smtp_auth][:user].eql?(user) and SesProxy::Conf.get[:smtp_auth][:password].eql?(password) end
receive_recipient(recipient)
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 48 def receive_recipient(recipient) recipients << recipient.gsub(/[<>]/,'') true end
receive_sender(sender)
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 33 def receive_sender(sender) sender = sender.gsub(/[<>]/,'') @sender = sender domains = VerifiedSender.where({:type=>'domain'}).map(&:ses_identity) email_addresses = VerifiedSender.where({:type=>'email'}).map(&:ses_identity) if domains.empty? or email_addresses.empty? resp = VerifiedSender.update_identities ses.client domains = resp[:domains].map(&:ses_identity) email_addresses = resp[:emails].map(&:ses_identity) end ok = (email_addresses.include?(sender) or domains.include?(sender.split('@').last)) puts "Invalid sender!" unless ok return ok end
recipients()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 58 def recipients @recipients ||= [] end
sender()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 62 def sender @sender || "" end
ses()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 74 def ses @ses ||= AWS::SimpleEmailService.new(SesProxy::Conf.get[:aws]) end
verified()
click to toggle source
# File lib/ses_proxy/smtp_server.rb, line 70 def verified @verified || false end