Hi!

The attached patch implements code 551 as described in RFC 2821 section 3.4.

The idea is that the originator MTA is told via DSN which address is the final
destination of this email, instead of transparently forwarding it.

The following code is returned by server:

  551 User not local; please try <[EMAIL PROTECTED]>

The main advantage with this is that it circumvents problems originated with SPF
and forwarding.

In order to activate it, system users just need to:

  echo [EMAIL PROTECTED] > ~/.preforward

-- 
Robert Millan
diff -ur qpsmtpd-0.32.old/lib/Qpsmtpd/Constants.pm 
qpsmtpd-0.32/lib/Qpsmtpd/Constants.pm
--- qpsmtpd-0.32.old/lib/Qpsmtpd/Constants.pm   2006-02-26 13:22:16.000000000 
+0100
+++ qpsmtpd-0.32/lib/Qpsmtpd/Constants.pm       2006-06-18 18:08:21.285787752 
+0200
@@ -23,6 +23,7 @@
        DENYHARD => 903,   # 550 + disconnect  (deprecated in 0.29)
        DENY_DISCONNECT     => 903, # 550 + disconnect
        DENYSOFT_DISCONNECT => 904, # 450 + disconnect
+       PREFORWARD => 905, # 551
        DECLINED => 909,
        DONE     => 910,
 );
diff -ur qpsmtpd-0.32.old/lib/Qpsmtpd/DSN.pm qpsmtpd-0.32/lib/Qpsmtpd/DSN.pm
--- qpsmtpd-0.32.old/lib/Qpsmtpd/DSN.pm 2006-02-26 13:22:16.000000000 +0100
+++ qpsmtpd-0.32/lib/Qpsmtpd/DSN.pm     2006-06-18 18:07:11.175446144 +0200
@@ -172,7 +172,7 @@
 
 sub addr_unspecified { shift->_dsn(shift,shift,DENYSOFT,1,0); }
 
-=item no_such_user, addr_bad_dest_mbox
+=item no_such_user, addr_bad_dest_mbox, user_not_local
 
 X.1.1
 default: DENY
@@ -181,6 +181,7 @@
 
 sub no_such_user         { shift->_dsn(shift,(shift||"No such 
user"),DENY,1,1); }
 sub addr_bad_dest_mbox   { shift->_dsn(shift,shift,DENY,1,1); }
+sub user_not_local       { shift->_dsn(shift,shift,PREFORWARD,1,1); }
 
 =item addr_bad_dest_system 
 
diff -ur qpsmtpd-0.32.old/lib/Qpsmtpd/SMTP.pm qpsmtpd-0.32/lib/Qpsmtpd/SMTP.pm
--- qpsmtpd-0.32.old/lib/Qpsmtpd/SMTP.pm        2006-02-26 13:22:16.000000000 
+0100
+++ qpsmtpd-0.32/lib/Qpsmtpd/SMTP.pm    2006-06-18 18:06:53.639112072 +0200
@@ -355,6 +355,9 @@
     $self->respond(421, $msg);
     $self->disconnect;
   }
+  elsif ($rc == PREFORWARD) {
+    $self->respond(551, $msg);
+  }
   elsif ($rc == OK) {
     $self->respond(250, $rcpt->format . ", recipient ok");
     return $self->transaction->add_recipient($rcpt);
diff -ur qpsmtpd-0.32.old/plugins/rcpt_ok qpsmtpd-0.32/plugins/rcpt_ok
--- qpsmtpd-0.32.old/plugins/rcpt_ok    2006-02-26 13:22:16.000000000 +0100
+++ qpsmtpd-0.32/plugins/rcpt_ok        2006-06-18 18:39:03.695698872 +0200
@@ -3,6 +3,7 @@
 # It should be configured to be run _LAST_!
 #
 use Qpsmtpd::DSN;
+use File::HomeDir;
 
 sub hook_rcpt {
   my ($self, $transaction, $recipient) = @_;
@@ -16,6 +17,14 @@
   my $user = $recipient->user;
   $host = $self->qp->config("me")
     if ($host eq "" && (lc $user eq "postmaster" || lc $user eq "abuse"));
+
+  # Check for ~/.preforward
+  if (open (PREFWD, home(lc($user)) . "/.preforward")) {
+    my ($prefwd) = <PREFWD>;
+    close(PREFWD);
+    chomp ($prefwd);
+    return Qpsmtpd::DSN->user_not_local("User not local; please try 
<$prefwd>");
+  }
   
   # Check if this recipient host is allowed
   for my $allowed (@rcpt_hosts) {

Reply via email to