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.
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