/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/




package org.apache.james.protocols.smtp.core.fastfail;

import org.apache.james.protocols.smtp.SMTPRetCode;
import org.apache.james.protocols.smtp.SMTPSession;
import org.apache.james.protocols.smtp.dsn.DSNStatus;
import org.apache.james.protocols.smtp.hook.HookResult;
import org.apache.james.protocols.smtp.hook.HookReturnCode;
import org.apache.james.protocols.smtp.hook.RcptHook;
import org.apache.mailet.MailAddress;


/**
 * Handler which want todo an recipient check should extend this
 *
 */
public abstract class AbstractValidRcptHandler implements RcptHook {

    
    /**
     * @see org.apache.james.protocols.smtp.hook.RcptHook#doRcpt(org.apache.james.protocols.smtp.SMTPSession, org.apache.mailet.MailAddress, org.apache.mailet.MailAddress)
     */
    public HookResult doRcpt(SMTPSession session, MailAddress sender, MailAddress rcpt) {
        
        if (!session.isRelayingAllowed()) {
            if (isValidRecipient(session, rcpt) == false) {
                //user not exist
                session.getLogger().info("Rejected message. Unknown user: " + rcpt.toString());
                return new HookResult(HookReturnCode.DENY,SMTPRetCode.MAILBOX_PERM_UNAVAILABLE, DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_MAILBOX) + " Unknown user: " + rcpt.toString());
            }
        } else {
            session.getLogger().debug("Sender allowed");
        }
        return new HookResult(HookReturnCode.DECLINED);
    }
    
  
    /**
     * Return true if email for the given recipient should get accepted
     * 
     * @param recipient
     * @return isValid
     */
    protected abstract boolean isValidRecipient(SMTPSession session, MailAddress recipient);
}

@@ -2035,24 +2035,56 @@
 ess rcpt) %7B%0A
+        boolean reject = false;%0A
         %0A   
@@ -2096,9 +2096,8 @@
 if (
-!
 sess
@@ -2139,93 +2139,736 @@
     
-if (isValidRecipient(session, rcpt) == false) %7B%0A                //user not exist%0A    
+// check if the domain is local, if so we still want to check if the recipient is valid or not as we want to fail fast in such cases%0A            if (isLocalDomain(session, rcpt.getDomain())) %7B%0A                if (isValidRecipient(session, rcpt) == false) %7B%0A                    reject = true;%0A                %7D%0A            %7D%0A        %7D else %7B%0A            if (isLocalDomain(session, rcpt.getDomain()) == false) %7B%0A                session.getLogger().debug(%22Unknown domain %22 + rcpt.getDomain() + %22 so reject it%22);%0A%0A            %7D else %7B%0A                if (isValidRecipient(session, rcpt) == false) %7B%0A                    reject= true;%0A                %7D%0A            %7D%0A        %7D%0A       %0A        if (reject) %7B%0A          //user not exist%0A
     
@@ -2947,36 +2947,32 @@
 pt.toString());%0A
-    
             retu
@@ -3154,30 +3154,16 @@
 ing());%0A
-            %7D%0A
         
@@ -3179,71 +3179,8 @@
     
-        session.getLogger().debug(%22Sender allowed%22);%0A        %7D%0A
     
@@ -3231,16 +3231,26 @@
 LINED);%0A
+        %7D%0A
     %7D%0A  
@@ -3491,10 +3491,227 @@
 pient);%0A
+    %0A    /**%0A     * Return true if the domain is local%0A     * %0A     * @param session%0A     * @param domain%0A     * @return local%0A     */%0A    protected abstract boolean isLocalDomain(SMTPSession session, String domain);%0A
 %7D%0A

Make sure the domain is not local before skip valid rcpt checks for sessions which are allowed to relay. See PROTOCOLS-17