require 'socket' # # minimal smtp server for DataPipeline::Email tests: EHLO, AUTH LOGIN, MAIL, RCPT, DATA, QUIT # server = TestSmtpServer.new # server.mails -> [{ from:, to: [...], data:, auth: [user, password] }] # class TestSmtpServer attr_reader :mails def initialize @mails = [] @server = TCPServer.new('127.0.0.1', 0) @thread = Thread.new { loop { serve(@server.accept) } } end def port = @server.addr[1] def stop @thread.kill @server.close end private def serve client mail = { to: [] } client.write "220 test ESMTP\r\n" while (line = client.gets) case line when /\AEHLO/i then client.write "250-test\r\n250 AUTH LOGIN PLAIN\r\n" when /\AAUTH LOGIN/i client.write "334 VXNlcm5hbWU6\r\n" user = client.gets.unpack1('m') client.write "334 UGFzc3dvcmQ6\r\n" mail[:auth] = [user, client.gets.unpack1('m')] client.write "235 ok\r\n" when /\AMAIL FROM:<(.*)>/i then mail[:from] = $1; client.write "250 ok\r\n" when /\ARCPT TO:<(.*)>/i then mail[:to] << $1; client.write "250 ok\r\n" when /\ADATA/i client.write "354 go\r\n" data = +'' while (part = client.gets) && part != ".\r\n" data << part end mail[:data] = data @mails << mail mail = { to: [] } client.write "250 queued\r\n" when /\AQUIT/i then client.write "221 bye\r\n"; break else client.write "250 ok\r\n" end end rescue StandardError => e warn "TestSmtpServer: #{e.class}: #{e.message}" ensure client.close end end