noel        2003/02/20 18:22:21

  Modified:    src/java/org/apache/james/transport/mailets Tag:
                        branch_2_1_fcs RemoteDelivery.java
  Log:
  (1) Fixed error where a connection error could cause discarded outgoing messages.  
(2) Fixed handling of SendFailedException for temporary/permanent exceptions.  This 
should also be the code necessary to support mail.smtp.sendpartial.  Added some log 
statements related to the recipient sets to aid in debugging.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.33.4.5  +178 -125  
jakarta-james/src/java/org/apache/james/transport/mailets/RemoteDelivery.java
  
  Index: RemoteDelivery.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/RemoteDelivery.java,v
  retrieving revision 1.33.4.4
  retrieving revision 1.33.4.5
  diff -u -r1.33.4.4 -r1.33.4.5
  --- RemoteDelivery.java       20 Feb 2003 07:37:48 -0000      1.33.4.4
  +++ RemoteDelivery.java       21 Feb 2003 02:22:21 -0000      1.33.4.5
  @@ -50,9 +50,6 @@
    *
    * as well as other places.
    *
  - * @author Serge Knystautas <[EMAIL PROTECTED]>
  - * @author Federico Barbieri <[EMAIL PROTECTED]>
  - *
    * This is $Revision$
    */
   public class RemoteDelivery extends GenericMailet implements Runnable {
  @@ -66,6 +63,8 @@
       private long delayTime = 21600000; // default is 6*60*60*1000 millis (6 hours)
       private int maxRetries = 5; // default number of retries
       private long smtpTimeout = 600000;  //default number of ms to timeout on smtp 
delivery
  +    private boolean sendPartial = false; // If false then ANY address errors will 
cause the transmission to fail
  +    private int connectionTimeout = 60000;  // The amount of time JavaMail will 
wait before giving up on a socket connect()
       private int deliveryThreadCount = 1; // default number of delivery threads
       private String gatewayServer = null; // the server to send all email to
       private String gatewayPort = null;  //the port of the gateway server to send 
all email to
  @@ -99,8 +98,19 @@
           } catch (Exception e) {
               log("Invalid timeout setting: " + getInitParameter("timeout"));
           }
  +
  +        try {
  +            if (getInitParameter("connectiontimeout") != null) {
  +                connectionTimeout = 
Integer.parseInt(getInitParameter("connectiontimeout"));
  +            }
  +        } catch (Exception e) {
  +            log("Invalid timeout setting: " + getInitParameter("timeout"));
  +        }
  +        sendPartial = (getInitParameter("sendpartial") == null) ? false : new 
Boolean(getInitParameter("sendpartial")).booleanValue();
  +
           gatewayServer = getInitParameter("gateway");
           gatewayPort = getInitParameter("gatewayPort");
  +
           ComponentManager compMgr = 
(ComponentManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
           String outgoingPath = getInitParameter("outgoing");
           if (outgoingPath == null) {
  @@ -146,8 +156,8 @@
        * throw an exception.
        *
        * Creation date: (2/24/00 11:25:00 PM)
  -     * @param Mail org.apache.mailet.Mail
  -     * @param Session javax.mail.Session
  +     * @param mail org.apache.james.core.MailImpl
  +     * @param session javax.mail.Session
        * @return boolean Whether the delivery was successful and the message can be 
deleted
        */
       private boolean deliver(MailImpl mail, Session session) {
  @@ -166,6 +176,11 @@
                   addr[j] = rcpt.toInternetAddress();
               }
   
  +            if (addr.length <= 0) {
  +                log("No recipients specified... not sure how this could have 
happened.");
  +                return true;
  +            }
  +
               //Figure out which servers to try to send to.  This collection
               //  will hold all the possible target servers
               Collection targetServers = null;
  @@ -179,9 +194,9 @@
                       log("No mail server found for: " + host);
                       StringBuffer exceptionBuffer =
                           new StringBuffer(128)
  -                            .append("There are no DNS entries for the hostname ")
  -                            .append(host)
  -                            .append(".  I cannot determine where to send this 
message.");
  +                        .append("There are no DNS entries for the hostname ")
  +                        .append(host)
  +                        .append(".  I cannot determine where to send this 
message.");
                       return failMessage(mail, new 
MessagingException(exceptionBuffer.toString()), false);
                   }
               } else {
  @@ -191,102 +206,109 @@
   
               MessagingException lastError = null;
   
  -            if (addr.length > 0) {
  -                Iterator i = targetServers.iterator();
  -                while ( i.hasNext()) {
  -                    try {
  -                        String outgoingMailServer = i.next().toString ();
  -                        StringBuffer logMessageBuffer =
  -                            new StringBuffer(256)
  -                                    .append("Attempting delivery of ")
  -                                    .append(mail.getName())
  -                                    .append(" to host ")
  -                                    .append(outgoingMailServer)
  -                                    .append(" to addresses ")
  -                                    .append(Arrays.asList(addr));
  -                        log(logMessageBuffer.toString());
  -                        URLName urlname = new URLName("smtp://" + 
outgoingMailServer);
  -
  -                        Properties props = session.getProperties();
  -                        if (mail.getSender() == null) {
  -                            props.put("mail.smtp.from", "<>");
  -                        } else {
  -                            String sender = mail.getSender().toString();
  -                            props.put("mail.smtp.from", sender);
  -                        }
  +            Iterator i = targetServers.iterator();
  +            while ( i.hasNext()) {
  +                try {
  +                    String outgoingMailServer = i.next().toString ();
  +                    StringBuffer logMessageBuffer =
  +                        new StringBuffer(256)
  +                        .append("Attempting delivery of ")
  +                        .append(mail.getName())
  +                        .append(" to host ")
  +                        .append(outgoingMailServer)
  +                        .append(" to addresses ")
  +                        .append(Arrays.asList(addr));
  +                    log(logMessageBuffer.toString());
  +                    URLName urlname = new URLName("smtp://" + outgoingMailServer);
  +
  +                    Properties props = session.getProperties();
  +                    if (mail.getSender() == null) {
  +                        props.put("mail.smtp.from", "<>");
  +                    } else {
  +                        String sender = mail.getSender().toString();
  +                        props.put("mail.smtp.from", sender);
  +                    }
   
  -                        //Many of these properties are only in later JavaMail 
versions
  -                        //"mail.smtp.ehlo"  //default true
  -                        //"mail.smtp.auth"  //default false
  -                        //"mail.smtp.dsn.ret"  //default to nothing... appended as 
RET= after MAIL FROM line.
  -                        //"mail.smtp.dsn.notify" //default to nothing...appended as 
NOTIFY= after RCPT TO line.
  +                    //Many of these properties are only in later JavaMail versions
  +                    //"mail.smtp.ehlo"  //default true
  +                    //"mail.smtp.auth"  //default false
  +                    //"mail.smtp.dsn.ret"  //default to nothing... appended as RET= 
after MAIL FROM line.
  +                    //"mail.smtp.dsn.notify" //default to nothing...appended as 
NOTIFY= after RCPT TO line.
   
  -                        Transport transport = null;
  +                    Transport transport = null;
  +                    try {
  +                        transport = session.getTransport(urlname);
                           try {
  -                            transport = session.getTransport(urlname);
  -                            try {
  -                                transport.connect();
  -                            } catch (MessagingException me) {
  -                                // Any error on connect should cause the mailet to 
attempt
  -                                // to connect to the next SMTP server associated 
with this MX record,
  -                                // assuming the number of retries hasn't been 
exceeded.
  -                                if (failMessage(mail, me, false)) {
  -                                    return true;
  -                                } else {
  -                                    continue;
  -                                }
  -                            }
  -                            transport.sendMessage(message, addr);
  -                        } finally {
  -                            if (transport != null) {
  -                                transport.close();
  -                                transport = null;
  +                            transport.connect();
  +                        } catch (MessagingException me) {
  +                            // Any error on connect should cause the mailet to 
attempt
  +                            // to connect to the next SMTP server associated with 
this MX record,
  +                            // assuming the number of retries hasn't been exceeded.
  +                            if (failMessage(mail, me, false)) {
  +                                return true;
  +                            } else {
  +                                continue;
                               }
                           }
  -                        logMessageBuffer =
  -                            new StringBuffer(256)
  -                                    .append("Mail (")
  -                                    .append(mail.getName())
  -                                    .append(") sent successfully to ")
  -                                    .append(outgoingMailServer);
  -                        log(logMessageBuffer.toString());
  -                        return true;
  -                    } catch (MessagingException me) {
  -                        //MessagingException are horribly difficult to figure out 
what actually happened.
  -                        StringBuffer exceptionBuffer =
  -                            new StringBuffer(256)
  -                                    .append("Exception delivering message (")
  -                                    .append(mail.getName())
  -                                    .append(") - ")
  -                                    .append(me.getMessage());
  -                        log(exceptionBuffer.toString());
  -                        if ((me.getNextException() != null) &&
  -                            (me.getNextException() instanceof java.io.IOException)) 
{
  -                            //This is more than likely a temporary failure
  -
  -                            // If it's an IO exception with no nested exception, 
it's probably
  -                            // some socket or weird I/O related problem.
  -                            lastError = me;
  -                            continue;
  +                        transport.sendMessage(message, addr);
  +                    } finally {
  +                        if (transport != null) {
  +                            transport.close();
  +                            transport = null;
                           }
  -                        // This was not a connection or I/O error particular to one
  -                        // SMTP server of an MX set.  Instead, it is almost 
certainly
  -                        // a protocol level error.  In this case we assume that this
  -                        // is an error we'd encounter with any of the SMTP servers
  -                        // associated with this MX record, and we pass the exception
  -                        // to the code in the outer block that determines its 
severity.
  -                        throw me;
                       }
  -                } // end while
  -                //If we encountered an exception while looping through, send the 
last exception we got
  -                if (lastError != null) {
  -                    throw lastError;
  +                    logMessageBuffer =
  +                                      new StringBuffer(256)
  +                                      .append("Mail (")
  +                                      .append(mail.getName())
  +                                      .append(") sent successfully to ")
  +                                      .append(outgoingMailServer);
  +                    log(logMessageBuffer.toString());
  +                    return true;
  +                } catch (MessagingException me) {
  +                    //MessagingException are horribly difficult to figure out what 
actually happened.
  +                    StringBuffer exceptionBuffer =
  +                        new StringBuffer(256)
  +                        .append("Exception delivering message (")
  +                        .append(mail.getName())
  +                        .append(") - ")
  +                        .append(me.getMessage());
  +                    log(exceptionBuffer.toString());
  +                    if ((me.getNextException() != null) &&
  +                          (me.getNextException() instanceof java.io.IOException)) {
  +                        //This is more than likely a temporary failure
  +
  +                        // If it's an IO exception with no nested exception, it's 
probably
  +                        // some socket or weird I/O related problem.
  +                        lastError = me;
  +                        continue;
  +                    }
  +                    // This was not a connection or I/O error particular to one
  +                    // SMTP server of an MX set.  Instead, it is almost certainly
  +                    // a protocol level error.  In this case we assume that this
  +                    // is an error we'd encounter with any of the SMTP servers
  +                    // associated with this MX record, and we pass the exception
  +                    // to the code in the outer block that determines its severity.
  +                    throw me;
                   }
  -            } else {
  -                log("No recipients specified... not sure how this could have 
happened.");
  +            } // end while
  +            //If we encountered an exception while looping through,
  +            //throw the last MessagingException we caught.  We only
  +            //do this if we were unable to send the message to any
  +            //server.  If sending eventually succeeded, we exit
  +            //deliver() though the return at the end of the try
  +            //block.
  +            if (lastError != null) {
  +                throw lastError;
               }
           } catch (SendFailedException sfe) {
  +            boolean deleteMessage = false;
  +            Collection recipients = mail.getRecipients();
  +
               //Would like to log all the types of email addresses
  +            if (isDebug) log("Recipients: " + recipients);
  +
  +            /*
               if (sfe.getValidSentAddresses() != null) {
                   Address[] validSent = sfe.getValidSentAddresses();
                   Collection recipients = mail.getRecipients();
  @@ -301,10 +323,12 @@
                       }
                   }
               }
  -            // The rest of the recipients failed for one reason or another.
  -            // let failMessage handle it -- 5xx codes are permanent, others 
temporary.
  +            */
   
               /*
  +             * The rest of the recipients failed for one reason or
  +             * another.
  +             * 
                * SendFailedException actually handles this for us.  For
                * example, if you send a message that has multiple invalid
                * addresses, you'll get a top-level SendFailedException
  @@ -314,56 +338,82 @@
                * the content of the nested exceptions is implementation
                * dependent.]
                *
  -             * For an immediate fix, we will simply go one level down.
  -             * THIS IS ONLY TEMPORARY.
  -             *
  -             * Proposal:
  -             *
  -             * By the time we get here, we've removed the valid sent
  -             * addresses from the message (see the code right above).
  -             *
                * sfe.getInvalidAddresses() should be considered permanent. 
                * sfe.getValidUnsentAddresses() should be considered temporary.
                *
                * JavaMail v1.3 properly populates those collections based
                * upon the 4xx and 5xx response codes.
                *
  -             * failMessage could re-spool for ValidUnsetAddresses, and
  -             * bounce InvalidAddresses.
  -             * 
                */
  -            //Assume it is a permanent exception, or prove ourselves otherwise
  -            boolean permanent = true;
  -            switch (sfe.getMessage().charAt(0)) {
  -                case '4':
  -                    permanent = false;
  -                    break;
  -                case '5':
  -                    permanent = true;
  -                    break;
  -                default:
  -                    Exception nested = sfe.getNextException();
  -                    if (nested != null) {
  -                        permanent = ('5' == nested.getMessage().charAt(0));
  +
  +            if (sfe.getInvalidAddresses() != null) {
  +                Address[] address = sfe.getInvalidAddresses();
  +                if (address.length > 0) {
  +                    recipients.clear();
  +                    for (int i = 0; i < address.length; i++) {
  +                        try {
  +                            recipients.add(new MailAddress(address[i].toString()));
  +                        } catch (ParseException pe) {
  +                            // this should never happen ... we should have
  +                            // caught malformed addresses long before we
  +                            // got to this code.
  +                            log("Can't parse invalid address: " + pe.getMessage());
  +                        }
                       }
  +                    if (isDebug) log("Invalid recipients: " + recipients);
  +                    deleteMessage = failMessage(mail, sfe, true);
  +                }
               }
  -            return failMessage(mail, sfe, permanent);
  +
  +            if (sfe.getValidUnsentAddresses() != null) {
  +                Address[] address = sfe.getValidUnsentAddresses();
  +                if (address.length > 0) {
  +                    recipients.clear();
  +                    for (int i = 0; i < address.length; i++) {
  +                        try {
  +                            recipients.add(new MailAddress(address[i].toString()));
  +                        } catch (ParseException pe) {
  +                            // this should never happen ... we should have
  +                            // caught malformed addresses long before we
  +                            // got to this code.
  +                            log("Can't parse unsent address: " + pe.getMessage());
  +                        }
  +                    }
  +                    if (isDebug) log("Unsent recipients: " + recipients);
  +                    deleteMessage = failMessage(mail, sfe, false);
  +                }
  +            }
  +
  +            return deleteMessage;
           } catch (MessagingException ex) {
               // We should do a better job checking this... if the failure is a 
general
               // connect exception, this is less descriptive than more specific SMTP 
command
               // failure... have to lookup and see what are the various Exception
               // possibilities
   
  -            //Unable to deliver message after numerous tries... fail accordingly
  +            // Unable to deliver message after numerous tries... fail accordingly
  +
  +            // We check whether this is a 5xx error message, which
  +            // indicates a permanent failure (like account doesn't exist
  +            // or mailbox is full or domain is setup wrong).
  +            // We fail permanently if this was a 5xx error
               return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
           }
  -        return true;
  +
  +        /* If we get here, we've exhausted the loop of servers without
  +         * sending the message or throwing an exception.  One case
  +         * where this might happen is if we get a MessagingException on
  +         * each transport.connect(), e.g., if there is only one server
  +         * and we get a connect exception.  Return FALSE to keep run()
  +         * from deleting the message.
  +         */
  +        return false;
       }
   
       /**
        * Insert the method's description here.
        * Creation date: (2/25/00 1:14:18 AM)
  -     * @param mail org.apache.mailet.MailImpl
  +     * @param mail org.apache.james.core.MailImpl
        * @param exception java.lang.Exception
        * @param boolean permanent
        * @return boolean Whether the message failed fully and can be deleted
  @@ -485,7 +535,6 @@
        * messagecontainer ... that will handle storing it in the outgoing queue if 
needed.
        *
        * @param mail org.apache.mailet.Mail
  -     * @return org.apache.mailet.MessageContainer
        */
       public void service(Mail genericmail) throws AddressException {
           MailImpl mail = (MailImpl)genericmail;
  @@ -594,6 +643,10 @@
           props.put("mail.smtp.ehlo", "false");
           //Sets timeout on going connections
           props.put("mail.smtp.timeout", smtpTimeout + "");
  +
  +        //props.put("mail.smtp.connectiontimeout", connectionTimeout + "");
  +        //props.put("mail.smtp.sendpartial",String.valueOf(sendPartial));
  +
           //Set the hostname we'll use as this server
           if (getMailetContext().getAttribute(Constants.HELLO_NAME) != null) {
               props.put("mail.smtp.localhost", (String) 
getMailetContext().getAttribute(Constants.HELLO_NAME));
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to