Skip to content

Instantly share code, notes, and snippets.

@araipiyo
Created June 1, 2014 15:07
Show Gist options
  • Save araipiyo/f212d92bee1ad9afcf1d to your computer and use it in GitHub Desktop.
Save araipiyo/f212d92bee1ad9afcf1d to your computer and use it in GitHub Desktop.
Simpliest mock SMTP server
require 'socket'
require 'nkf'
DEBUG = false
#KANJI = nil
KANJI = '-s'
def data(sock)
s = ""
sock.print "354 End data with <CR><LF>.<CR><LF>\r\n"
while(line = sock.gets)
puts line if DEBUG
break if line =~ /^\.\r?\n?$/
s += line
end
s
end
def parse_message(s)
(header, body) = s.gsub(/\r\n/,"\n").split(/\n\n/,2)
headers = {}
header.gsub(/\n[\s\t]+/, ' ').split(/\n/).each { |line|
(k,v) = line.split(/: +/,2)
headers[k] = v
}
[headers, body]
end
def write(io, from, to, headers, body)
io.puts "envelope-from: #{from}"
io.puts "envelope-to: #{to.join '; '}"
io.puts "---"
headers.each { |k,v| io.puts "#{k}: #{v}" }
io.puts "\n\n"
io.puts body
io.puts "==="
end
def session(sock)
sock.print "220 localhost SMTP mockmail\r\n"
from = nil
to = []
body = nil
while(line = sock.gets)
line.chomp!
puts line if DEBUG
sock.print case line
when /HELO/: "250 localhost\r\n"
when /RSET/: "250 Ok\r\n"
when /VRFY/:
/VRFY [^\s]/ =~ line
"252 #{$1}\r\n"
when /MAIL FROM/:
/MAIL FROM:\s*\<?([^\s<>]+)\>?/ =~ line
from = $1
puts from if DEBUG
"250 Ok\r\n"
when /RCPT TO/:
/RCPT TO:\s*\<?([^\s\r\n\t\f<>]+)\>?/ =~ line
to << $1
puts to if DEBUG
"250 Ok\r\n"
when /DATA/:
message = data(sock)
"250 Ok\r\n"
when /QUIT/:
sock.print "221 Bye\r\n"
break
else "500 Err\r\n"
end
end
(headers, body) = parse_message(message)
if KANJI
headers.each { |k,v| headers[k] = NKF.nkf(KANJI,v) }
end
if headers['Content-Transfer-Encoding'] == 'base64'
body = body.unpack('m')[0]
body = NKF.nkf(KANJI,body) if KANJI
end
write(STDOUT, from, to, headers, body)
open("mockmail.txt", "a") { |f|
write(f, from, to, headers, body)
}
sock.close
end
def main
begin
server = TCPServer.new('localhost',25)
Thread.start {
loop { sleep 1 }
}
loop do
Thread.start(server.accept) { |sock|
begin
session(sock)
rescue Exception => e
p e
end
}
end
rescue Interrupt => i
puts "ending..."
end
end
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment