Skip to content

Instantly share code, notes, and snippets.

@yaplik
Created December 14, 2012 18:35
Show Gist options
  • Save yaplik/4287550 to your computer and use it in GitHub Desktop.
Save yaplik/4287550 to your computer and use it in GitHub Desktop.
Example SMTP Server for PV249
source :rubygems
gem "eventmachine"
#!/usr/bin/env ruby
# Example SMTP Server in Ruby for course FI:PV249
#
# @author Jiri Zapletal <yaplik@gmail.com>
# @license BSD
require 'bundler/setup'
Bundler.require(:default)
module SmtpProtocol
include EventMachine::Protocols::LineText2
def post_init
reset_state
send_line("220 mail.example.net SMTP Ruby Server")
end
def reset_state
@mail = nil
@rcpt = []
@data = ""
end
def send_line(data)
puts "[S] " + data
send_data(data + "\r\n")
end
def receive_line(line)
puts "[C] " + line
case
when m = /^HELO (.*)$/i.match(line)
send_line "250 Hello"
when m = /^EHLO (.*)$/i.match(line)
send_line "250-mail.example.net"
send_line "250-STARTTLS"
send_line "250 DSN"
when m = /^STARTTLS$/i.match(line)
send_line "220 2.0.0 Ready to start TLS"
start_tls
when m = /^MAIL FROM:(.*)$/i.match(line)
if @from != nil then
send_line "503 5.5.1 Error: nested MAIL command"
return
end
@from = m[1]
send_line "250 2.1.0 Ok"
when m = /^RCPT TO:(.*)/i.match(line)
if @from == nil then
send_line "503 5.5.1 Error: need MAIL command"
return
end
@rcpt << m[1]
send_line "250 2.1.5 Ok"
when m = /^RSET$/i.match(line)
reset_state
send_line "250 2.0.0 Ok"
when m = /^DATA$/i.match(line)
if @rcpt.count == 0 then
send_line "503 5.5.1 Error: need RCPT command"
return
end
send_line "354 End data with <CR><LF>.<CR><LF>"
set_text_mode
when m = /^QUIT$/i.match(line)
send_line "221 Bye"
close_connection_after_writing
else
puts "[error]", line
send_line "502 5.5.2 Error: command not recognized"
end
end
def receive_binary_data(data)
print "data", data.inspect
if /\r\n\.\r\n$/.match(data) then
@data += data[0..-5]
id = receive_mail(@from, @rcpt, @data)
send_line "250 2.0.0 Ok: queued as #{id}"
reset_state
set_line_mode
else
@data += data
end
end
def unbind
puts "[C Disconnected]"
end
def receive_mail(from, to, data)
puts "Email from #{from} to #{to.join(",")}"
return "123456"
end
end
EventMachine.run do
Signal.trap("INT") { EventMachine.stop }
Signal.trap("TERM") { EventMachine.stop }
EventMachine.start_server("0.0.0.0", 8025, SmtpProtocol)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment