[#25936] [Bug:1.9] [rubygems] $LOAD_PATH includes bin directory — Nobuyoshi Nakada <nobu@...>

Hi,

10 messages 2009/10/05

[#25943] Disabling tainting — Tony Arcieri <tony@...>

Would it make sense to have a flag passed to the interpreter on startup that

16 messages 2009/10/05

[#26028] [Bug #2189] Math.atanh(1) & Math.atanh(-1) should not raise an error — Marc-Andre Lafortune <redmine@...>

Bug #2189: Math.atanh(1) & Math.atanh(-1) should not raise an error

14 messages 2009/10/10

[#26222] [Bug #2250] IO::for_fd() objects' finalization dangerously closes underlying fds — Mike Pomraning <redmine@...>

Bug #2250: IO::for_fd() objects' finalization dangerously closes underlying fds

11 messages 2009/10/22

[#26244] [Bug #2258] Kernel#require inside rb_require() inside rb_protect() inside SysV context fails — Suraj Kurapati <redmine@...>

Bug #2258: Kernel#require inside rb_require() inside rb_protect() inside SysV context fails

24 messages 2009/10/22

[#26361] [Feature #2294] [PATCH] ruby_bind_stack() to embed Ruby in coroutine — Suraj Kurapati <redmine@...>

Feature #2294: [PATCH] ruby_bind_stack() to embed Ruby in coroutine

42 messages 2009/10/27

[#26371] [Bug #2295] segmentation faults — tomer doron <redmine@...>

Bug #2295: segmentation faults

16 messages 2009/10/27

[ruby-core:26150] Patch: Let Net::SMTP continu when at least one RCPT is accepted

From: Kero van Gelder <ruby-core@...>
Date: 2009-10-18 17:17:07 UTC
List: ruby-core #26150
Hi all,

While writing an SMTP daemon in Ruby, one of my tests
(that uses Ruby's existing Net::SMTP library) failed.
I was testing that my daemon will deliver mail when
only some RCPTs specified by the client were accepted.

Ruby's Net::SMTP quits when the first Unknown User is
encountered. I think Net::SMTP should continue with
other RCPTs, then use DATA to let the mail be delivered
to existing users.

I think this should be so, because
 - RFC821 mentions clearly in the second paragraph in section 2
   "if not, it responds with a reply rejecting that recipient
   (but not the whole mail transaction)", and
 - RFC2821 leaves this in the middle, but still gives
   an example in section  D.1 A Typical SMTP Transaction Scenario
   "C: RCPT TO:<Jones@foo.com>
      S: 250 OK
      C: RCPT TO:<Green@foo.com>
      S: 550 No such user here
      C: RCPT TO:<Brown@foo.com>
      S: 250 OK"

So, I wrote code to accomplish this.
Please find a patch attached.

Comments welcome, especially on the Errors constructed and returned.
They are in plain text; I can imagine making the unknown and ok
users explicit (arrays within the exception), so that code that uses
Net::SMTP has an easier time determining which emails were not sent.

Bye,
Kero.

PS: patch applies to both ruby_1_8 branch and trunk
___
How can I change the world if I can't even change myself?
  -- Faithless, Salva Mea

Attachments (1)

smtp_rcptto.patch (3.24 KB, text/x-diff)
Index: lib/net/smtp.rb
===================================================================
--- lib/net/smtp.rb	(revision 25392)
+++ lib/net/smtp.rb	(working copy)
@@ -50,7 +50,12 @@
     include SMTPError
   end
 
-  # Represents a fatal SMTP error (error code 5xx, except for 500)
+  # Represents SMTP error code 550, user unknown
+  class SMTPUnknownUser < ProtoFatalError
+    include SMTPError
+  end
+  
+  # Represents a fatal SMTP error (error code 5xx, except for 500 and 550)
   class SMTPFatalError < ProtoFatalError
     include SMTPError
   end
@@ -452,6 +457,7 @@
     # * Net::SMTPAuthenticationError
     # * Net::SMTPServerBusy
     # * Net::SMTPSyntaxError
+    # * Net::SMTPUnknownUser
     # * Net::SMTPFatalError
     # * Net::SMTPUnknownError
     # * IOError
@@ -513,6 +519,7 @@
     # * Net::SMTPAuthenticationError
     # * Net::SMTPServerBusy
     # * Net::SMTPSyntaxError
+    # * Net::SMTPUnknownUser
     # * Net::SMTPFatalError
     # * Net::SMTPUnknownError
     # * IOError
@@ -643,6 +650,7 @@
     #
     # * Net::SMTPServerBusy
     # * Net::SMTPSyntaxError
+    # * Net::SMTPUnknownUser
     # * Net::SMTPFatalError
     # * Net::SMTPUnknownError
     # * IOError
@@ -651,8 +659,10 @@
     def send_message(msgstr, from_addr, *to_addrs)
       raise IOError, 'closed session' unless @socket
       mailfrom from_addr
-      rcptto_list to_addrs
-      data msgstr
+      ok_users, unknown_users = rcptto_list to_addrs.flatten
+      res = data msgstr
+      raise SMTPUnknownUser, "Unknown users: #{unknown_users.join', '}, mail delivered to #{ok_users.join', '}"  if not unknown_users.empty?
+      res
     end
 
     alias send_mail send_message
@@ -697,6 +707,7 @@
     #
     # * Net::SMTPServerBusy
     # * Net::SMTPSyntaxError
+    # * Net::SMTPUnknownUser
     # * Net::SMTPFatalError
     # * Net::SMTPUnknownError
     # * IOError
@@ -705,8 +716,10 @@
     def open_message_stream(from_addr, *to_addrs, &block)   # :yield: stream
       raise IOError, 'closed session' unless @socket
       mailfrom from_addr
-      rcptto_list to_addrs
-      data(&block)
+      ok_users, unknown_users = rcptto_list to_addrs.flatten
+      res = data(&block)
+      raise SMTPUnknownUser, "Failed to deliver for #{unknown_users.join', '}, succesful for #{ok_users.join', '}"  if not unknown_users.empty?
+      res
     end
 
     alias ready open_message_stream   # obsolete
@@ -830,9 +843,19 @@
 
     def rcptto_list(to_addrs)
       raise ArgumentError, 'mail destination not given' if to_addrs.empty?
-      to_addrs.flatten.each do |addr|
-        rcptto addr
+      unknown_users = []
+      to_addrs.each do |addr|
+        begin
+          rcptto addr
+        rescue SMTPUnknownUser
+          unknown_users << addr
+        end
       end
+      if unknown_users.length == to_addrs.flatten.length
+        raise SMTPUnknownUser, "Unknown users: #{unknown_users.join', '}"
+      else
+        [to_addrs - unknown_users, unknown_users]
+      end
     end
 
     def rcptto(to_addr)
@@ -997,6 +1020,7 @@
         when /\A4/  then SMTPServerBusy
         when /\A50/ then SMTPSyntaxError
         when /\A53/ then SMTPAuthenticationError
+        when /\A550/ then SMTPUnknownUser
         when /\A5/  then SMTPFatalError
         else             SMTPUnknownError
         end

In This Thread

Prev Next