Author: noel Date: Sat Jun 4 10:21:55 2005 New Revision: 180006 URL: http://svn.apache.org/viewcvs?rev=180006&view=rev Log: First attempt to leverage JavaMail 1.3.2 STMP reply code improvements to better detect and handle transfer issues. Use <debug> true </debug> if you want to diagnose what is happening.
Modified: james/server/trunk/src/java/org/apache/james/transport/mailets/RemoteDelivery.java Modified: james/server/trunk/src/java/org/apache/james/transport/mailets/RemoteDelivery.java URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/transport/mailets/RemoteDelivery.java?rev=180006&r1=180005&r2=180006&view=diff ============================================================================== --- james/server/trunk/src/java/org/apache/james/transport/mailets/RemoteDelivery.java (original) +++ james/server/trunk/src/java/org/apache/james/transport/mailets/RemoteDelivery.java Sat Jun 4 10:21:55 2005 @@ -46,6 +46,10 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.ParseException; +import com.sun.mail.smtp.SMTPSendFailedException; +import com.sun.mail.smtp.SMTPAddressFailedException; +import com.sun.mail.smtp.SMTPAddressSucceededException; + import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.configuration.DefaultConfiguration; @@ -347,6 +351,46 @@ } } + /* + * private method to log the extended SendFailedException introduced in JavaMail 1.3.2. + */ + private void logSendFailedException(SendFailedException sfe) { + if (isDebug) { + MessagingException me = (MessagingException)sfe; + if (me instanceof SMTPSendFailedException) { + SMTPSendFailedException ssfe = (SMTPSendFailedException)me; + log("SMTP SEND FAILED:"); + log(ssfe.toString()); + log(" Command: " + ssfe.getCommand()); + log(" RetCode: " + ssfe.getReturnCode()); + log(" Response: " + ssfe.getMessage()); + } else { + log("Send failed: " + me.toString()); + } + Exception ne; + while ((ne = me.getNextException()) != null && ne instanceof MessagingException) { + me = (MessagingException)ne; + if (me instanceof SMTPAddressFailedException) { + SMTPAddressFailedException e = (SMTPAddressFailedException)me; + log("ADDRESS FAILED:"); + log(e.toString()); + log(" Address: " + e.getAddress()); + log(" Command: " + e.getCommand()); + log(" RetCode: " + e.getReturnCode()); + log(" Response: " + e.getMessage()); + } else if (me instanceof SMTPAddressSucceededException) { + log("ADDRESS SUCCEEDED:"); + SMTPAddressSucceededException e = (SMTPAddressSucceededException)me; + log(e.toString()); + log(" Address: " + e.getAddress()); + log(" Command: " + e.getCommand()); + log(" RetCode: " + e.getReturnCode()); + log(" Response: " + e.getMessage()); + } + } + } + } + /** * We can assume that the recipients of this message are all going to the same * mail server. We will now rely on the DNS server to do DNS MX record lookup @@ -414,7 +458,7 @@ .append(outgoingMailServer.getHostName()) .append(" at ") .append(outgoingMailServer.getHost()) - .append(" to addresses ") + .append(" for addresses ") .append(Arrays.asList(addr)); log(logMessageBuffer.toString()); @@ -459,17 +503,41 @@ .append(") sent successfully to ") .append(outgoingMailServer.getHostName()) .append(" at ") - .append(outgoingMailServer.getHost()); + .append(outgoingMailServer.getHost()) + .append(" for ") + .append(mail.getRecipients()); log(logMessageBuffer.toString()); return true; } catch (SendFailedException sfe) { + logSendFailedException(sfe); + + if (sfe.getValidSentAddresses() != null) { + Address[] validSent = sfe.getValidSentAddresses(); + if (validSent.length > 0) { + StringBuffer logMessageBuffer = + new StringBuffer(256) + .append("Mail (") + .append(mail.getName()) + .append(") sent successfully for ") + .append(Arrays.asList(validSent)); + log(logMessageBuffer.toString()); + } + } + + /* SMTPSendFailedException introduced in JavaMail 1.3.2, and provides detailed protocol reply code for the operation */ + if (sfe instanceof SMTPSendFailedException) { + SMTPSendFailedException ssfe = (SMTPSendFailedException) sfe; + // if 5xx, terminate this delivery attempt by re-throwing the exception. + if (ssfe.getReturnCode() >= 500 && ssfe.getReturnCode() <= 599) throw sfe; + } + if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) { if (isDebug) log("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers"); lastError = sfe; continue; } else { - // There are no valid addresses left to send, so rethrow + // There are no valid addresses left to send, so rethrow throw sfe; } } catch (MessagingException me) { @@ -509,18 +577,14 @@ throw lastError; } } catch (SendFailedException sfe) { - boolean deleteMessage = false; + logSendFailedException(sfe); + Collection recipients = mail.getRecipients(); - //Would like to log all the types of email addresses - if (isDebug) log("Recipients: " + recipients); + boolean deleteMessage = false; /* - * 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 + * If you send a message that has multiple invalid * addresses, you'll get a top-level SendFailedException * that that has the valid, valid-unsent, and invalid * address lists, with all of the server response messages @@ -532,10 +596,34 @@ * sfe.getValidUnsentAddresses() should be considered temporary. * * JavaMail v1.3 properly populates those collections based - * upon the 4xx and 5xx response codes. + * upon the 4xx and 5xx response codes to RCPT TO. Some + * servers, such as Yahoo! don't respond to the RCPT TO, + * and provide a 5xx reply after DATA. In that case, we + * will pick up the failure from SMTPSendFailedException. * */ + /* SMTPSendFailedException introduced in JavaMail 1.3.2, and provides detailed protocol reply code for the operation */ + if (sfe instanceof SMTPSendFailedException) { + // If we got an SMTPSendFailedException, use its RetCode to determine default permanent/temporary failure + SMTPSendFailedException ssfe = (SMTPSendFailedException) sfe; + deleteMessage = (ssfe.getReturnCode() >= 500 && ssfe.getReturnCode() <= 599); + } else { + // Sometimes we'll get a normal SendFailedException with nested SMTPAddressFailedException, so use the latter RetCode + MessagingException me = (MessagingException)sfe; + Exception ne; + while ((ne = me.getNextException()) != null && ne instanceof MessagingException) { + me = (MessagingException)ne; + if (me instanceof SMTPAddressFailedException) { + SMTPAddressFailedException ssfe = (SMTPAddressFailedException)me; + deleteMessage = (ssfe.getReturnCode() >= 500 && ssfe.getReturnCode() <= 599); + } + } + } + + // log the original set of intended recipients + if (isDebug) log("Recipients: " + recipients); + if (sfe.getInvalidAddresses() != null) { Address[] address = sfe.getInvalidAddresses(); if (address.length > 0) { @@ -570,7 +658,12 @@ } } if (isDebug) log("Unsent recipients: " + recipients); - deleteMessage = failMessage(mail, sfe, false); + if (sfe instanceof SMTPSendFailedException) { + SMTPSendFailedException ssfe = (SMTPSendFailedException) sfe; + deleteMessage = failMessage(mail, sfe, ssfe.getReturnCode() >= 500 && ssfe.getReturnCode() <= 599); + } else { + deleteMessage = failMessage(mail, sfe, false); + } } } @@ -621,7 +714,7 @@ .append(mail.getName()) .append(": "); out.print(logBuffer.toString()); - ex.printStackTrace(out); + if (isDebug) ex.printStackTrace(out); log(sout.toString()); if (!permanent) { if (!mail.getState().equals(Mail.ERROR)) { @@ -717,7 +810,6 @@ } } out.println(); - out.println("The original message is attached."); log("Sending failure message " + mail.getName()); try { --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]