# frozen_string_literal: true require 'dotenv/load' require 'midi-smtp-server' require 'mail' require 'bunny' # Server class class BettermailProxy < MidiSmtpServer::Smtpd def stop(wait_seconds_before_close: nil, gracefully: nil) super() @bunny_conn&.close end def bunny if @bunny.nil? @bunny_conn = Bunny.new @bunny_conn.start ch = @bunny_conn.create_channel ch.direct(ENV['RABBIT_CHANNEL']) ch.queue(ENV['RABBIT_MAIL_QUEUE']) @bunny = ch.default_exchange end @bunny end # update local welcome and helo response def on_connect_event(ctx) ctx[:server][:local_response] = 'Client connected' ctx[:server][:helo_response] = 'Welcome to the BetterMail proxy - an SMTP drop in replacement' end def on_message_data_headers_event(ctx) # check and append all headers ctx[:message][:data] << "X-bettermail: Received by proxy at #{Time.now}" << ctx[:message][:crlf] end # check the authentication # if any value returned, that will be used for ongoing processing # otherwise the original value will be used for authorization_id def on_auth_event(ctx, authorization_id, authentication_id, authentication) # to proceed this test use commands ... # auth plain # > AGFkbWluaXN0cmF0b3IAcGFzc3dvcmQ= # auth login # > YWRtaW5pc3RyYXRvcg== # > cGFzc3dvcmQ= # if authorization_id == '' && authentication_id == 'administrator' && authentication == 'password' # # yes # return 'supervisor' # end # # otherwise exit with authentication exception # raise MidiSmtpServer::Smtpd535Exception logger.debug("Authenticated id: #{authentication_id} with authentication: #{authentication} from: #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]}") authentication_id end # get each message after DATA . def on_message_data_event(ctx) # Just decode message once to make sure, that this message ist readable mail = Mail.read_from_string(ctx[:message][:data]) logger.info('Message good. Sending to queue for processing') bunny.publish(mail.to_s, :headers => { 'x-smtp' => mail.header.to_s }, :routing_key => ENV["RABBIT_MAIL_QUEUE"]) logger.info('Done') end end # Create a new server instance for listening at localhost interfaces 127.0.0.1:2525 # and accepting a maximum of 4 simultaneous connections per default service = BettermailProxy.new( ports: ENV['PROXY_PORTS'], hosts: ENV['PROXY_HOSTS'], max_processings: 10, auth_mode: :AUTH_REQUIRED, tls_mode: :TLS_REQUIRED, tls_cert_path: './ssl/cert.pem', tls_key_path: './ssl/key.pem' ) service_name='BetterMail::SMTPProxy' # Create a new server instance for listening at localhost interfaces 127.0.0.1:2525 # and accepting a maximum of 4 simultaneous connections per default # save flag for Ctrl-C pressed flag_status_ctrl_c_pressed = false # try to gracefully shutdown on Ctrl-C trap('INT') do # print an empty line right after ^C puts # notify flag about Ctrl-C was pressed flag_status_ctrl_c_pressed = true # signal exit to app exit(0) end # Output for debug puts("Starting #{service_name}") # setup exit code at_exit do # check to shutdown connection if service # Output for debug puts('Ctrl-C interrupted, exit now...') if flag_status_ctrl_c_pressed # info about shutdown puts("Shutdown #{service_name}...") # stop all threads and connections gracefully service.stop end # Output for debug puts "#{service_name} stopped!" end # Start the server service.start # Run on server forever service.join