123 lines
3.5 KiB
Ruby
123 lines
3.5 KiB
Ruby
# 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 <message> .
|
|
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
|