From: Brian Candler Date: 2005-04-01T19:07:54+09:00 Subject: Re: ruby lib that will receive email --J2SCkAp4GZ/dPZZf Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Apr 01, 2005 at 09:45:33AM +0900, "Pea, Botp" wrote: > //> the net/smtp only sends mail. Is there any email ruby lib out there > //> that can receive email? I just want to capture inbound > //mail; no worry > //> on where to save it. > // > //Net::POP and Net::IMAP in Ruby's standard library? > // > > hmmm.. pop/imap retrieves email fr the server. It pulls the email already > arrived at the server. I want something like _that server (so then i can > pop/imap/orwhatever fr it). I'd like one of these too, to go into a Unit testing framework for a mail system. A sort of mock SMTP server. If you write this, please release it :-) I think if you have a look at the architecture of Exim, you might get some good ideas. For example, Exim has ACLs which are triggered at various points (e.g. MAIL FROM, RCPT TO) to make a decision as to whether to accept or reject the message at that point. These could be Proc callbacks or instances of an ACL object that you provide. But a fully-fledged MTA in Ruby, complete with message queues and periodic retries, isn't something that I need; just something which accepts mail via SMTP, and stores it (even in RAM). If it were ever put onto the open Internet it would at least have to have a way to decide whether the recipient address is known or not, and accept/reject as appropriate. Regards, Brian. P.S. I have a nice threaded server pattern you can use - see attached. --J2SCkAp4GZ/dPZZf Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="foo.rb" require 'socket' module Net module_function # Accept connections on a port, and for each one start a new thread # and run the given block in the context of the socket. Returns the Thread # object for the listener. # # FIXME: # - have a limit on total number of concurrent connects # - have a limit on connections from a single IP, or from a /24 # (to avoid the trivial DoS that the first limit creates) def tcpserver(*args, &blk) Thread.new do opt = args.pop server = TCPServer.new(opt[:bindaddr] || "0.0.0.0", opt[:port]) logger = opt[:logger] || $stderr while session = server.accept # subtlety: copy 'session' into a block-local variable because # it will change when the next session is accepted Thread.new(session) do |s| begin s.instance_eval(*args,&blk) rescue Exception => e logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace[0]}\n" ensure s.close end end end end end end # module Net if __FILE__ == $0 # simple test t = Net::tcpserver(:port=>2225) do print "220 localhost ESMTP\r\n" while line = gets case line when /^quit/i break when /^crash/i raise Errno::EPERM, "dammit!" else print "500 unrecognized command\r\n" end end print "221 goodbye\r\n" end t.join # server runs until Ctrl-C #sleep 10; t.kill # or: server runs for fixed time period end --J2SCkAp4GZ/dPZZf--