git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@704528 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -425,6 +425,10 @@ Other changes: | |||||
| used by MailLogger. | used by MailLogger. | ||||
| Bugzilla Report 27211. | Bugzilla Report 27211. | ||||
| * a new attribute of <mail> allows the task to succeed if it can | |||||
| reach at least one given recipient. | |||||
| Bugzilla Report 36446. | |||||
| Changes from Ant 1.7.0 TO Ant 1.7.1 | Changes from Ant 1.7.0 TO Ant 1.7.1 | ||||
| ============================================= | ============================================= | ||||
| @@ -172,6 +172,13 @@ | |||||
| <td valign="top">Email subject line.</td> | <td valign="top">Email subject line.</td> | ||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">ignoreInvalidRecipients</td> | |||||
| <td valign="top">Boolean. Whether the task should try to send | |||||
| the message to as many recipients as possible and should only | |||||
| fail if neither is reachable. <em>Since Ant 1.8.0</em>.</td> | |||||
| <td align="center" valign="top">No, default is false</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Note regarding the attributes containing email addresses</h3> | <h3>Note regarding the attributes containing email addresses</h3> | ||||
| @@ -103,6 +103,9 @@ public class EmailTask extends Task { | |||||
| /** indicate if the user wishes SSL-TLS */ | /** indicate if the user wishes SSL-TLS */ | ||||
| private boolean ssl = false; | private boolean ssl = false; | ||||
| /** ignore invalid recipients? */ | |||||
| private boolean ignoreInvalidRecipients = false; | |||||
| /** | /** | ||||
| * Set the user for SMTP auth; this requires JavaMail. | * Set the user for SMTP auth; this requires JavaMail. | ||||
| * @param user the String username. | * @param user the String username. | ||||
| @@ -402,6 +405,19 @@ public class EmailTask extends Task { | |||||
| return includeFileNames; | return includeFileNames; | ||||
| } | } | ||||
| /** | |||||
| * Whether invalid recipients should be ignored (but a warning | |||||
| * will be logged) instead of making the task fail. | |||||
| * | |||||
| * <p>Even with this property set to true the task will still fail | |||||
| * if the mail couldn't be sent to any recipient at all.</p> | |||||
| * | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| public void setIgnoreInvalidRecipients(boolean b) { | |||||
| ignoreInvalidRecipients = b; | |||||
| } | |||||
| /** | /** | ||||
| * Send an email. | * Send an email. | ||||
| */ | */ | ||||
| @@ -532,6 +548,7 @@ public class EmailTask extends Task { | |||||
| mailer.setTask(this); | mailer.setTask(this); | ||||
| mailer.setIncludeFileNames(includeFileNames); | mailer.setIncludeFileNames(includeFileNames); | ||||
| mailer.setHeaders(headers); | mailer.setHeaders(headers); | ||||
| mailer.setIgnoreInvalidRecipients(ignoreInvalidRecipients); | |||||
| // send the email | // send the email | ||||
| mailer.send(); | mailer.send(); | ||||
| @@ -48,6 +48,7 @@ public abstract class Mailer { | |||||
| protected boolean includeFileNames = false; | protected boolean includeFileNames = false; | ||||
| protected Vector headers = null; | protected Vector headers = null; | ||||
| // CheckStyle:VisibilityModifier ON | // CheckStyle:VisibilityModifier ON | ||||
| private boolean ignoreInvalidRecipients = false; | |||||
| /** | /** | ||||
| * Set the mail server. | * Set the mail server. | ||||
| @@ -205,6 +206,28 @@ public abstract class Mailer { | |||||
| public abstract void send() | public abstract void send() | ||||
| throws BuildException; | throws BuildException; | ||||
| /** | |||||
| * Whether invalid recipients should be ignored (but a warning | |||||
| * will be logged) instead of making the task fail. | |||||
| * | |||||
| * <p>Even with this property set to true the task will still fail | |||||
| * if the mail couldn't be sent to any recipient at all.</p> | |||||
| * | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| public void setIgnoreInvalidRecipients(boolean b) { | |||||
| ignoreInvalidRecipients = b; | |||||
| } | |||||
| /** | |||||
| * Whether invalid recipients should be ignored. | |||||
| * | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| protected boolean shouldIgnoreInvalidRecipients() { | |||||
| return ignoreInvalidRecipients; | |||||
| } | |||||
| /** | /** | ||||
| * Return the current Date in a format suitable for a SMTP date | * Return the current Date in a format suitable for a SMTP date | ||||
| * header. | * header. | ||||
| @@ -38,19 +38,22 @@ import java.security.Security; | |||||
| import javax.activation.DataHandler; | import javax.activation.DataHandler; | ||||
| import javax.activation.FileDataSource; | import javax.activation.FileDataSource; | ||||
| import javax.mail.Message; | |||||
| import javax.mail.Session; | |||||
| import javax.mail.Transport; | |||||
| import javax.mail.Authenticator; | import javax.mail.Authenticator; | ||||
| import javax.mail.Address; | |||||
| import javax.mail.Message; | |||||
| import javax.mail.MessagingException; | import javax.mail.MessagingException; | ||||
| import javax.mail.PasswordAuthentication; | import javax.mail.PasswordAuthentication; | ||||
| import javax.mail.internet.MimeMessage; | |||||
| import javax.mail.SendFailedException; | |||||
| import javax.mail.Session; | |||||
| import javax.mail.Transport; | |||||
| import javax.mail.internet.AddressException; | |||||
| import javax.mail.internet.InternetAddress; | |||||
| import javax.mail.internet.MimeBodyPart; | import javax.mail.internet.MimeBodyPart; | ||||
| import javax.mail.internet.MimeMessage; | |||||
| import javax.mail.internet.MimeMultipart; | import javax.mail.internet.MimeMultipart; | ||||
| import javax.mail.internet.InternetAddress; | |||||
| import javax.mail.internet.AddressException; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | |||||
| /** | /** | ||||
| * Uses the JavaMail classes to send Mime format email. | * Uses the JavaMail classes to send Mime format email. | ||||
| @@ -60,6 +63,9 @@ import org.apache.tools.ant.BuildException; | |||||
| public class MimeMailer extends Mailer { | public class MimeMailer extends Mailer { | ||||
| private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; | private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; | ||||
| private static final String GENERIC_ERROR = | |||||
| "Problem while sending mime mail:"; | |||||
| /** Default character set */ | /** Default character set */ | ||||
| private static final String DEFAULT_CHARSET | private static final String DEFAULT_CHARSET | ||||
| = System.getProperty("file.encoding"); | = System.getProperty("file.encoding"); | ||||
| @@ -237,11 +243,36 @@ public class MimeMailer extends Mailer { | |||||
| attachments.addBodyPart(body); | attachments.addBodyPart(body); | ||||
| } | } | ||||
| msg.setContent(attachments); | msg.setContent(attachments); | ||||
| Transport.send(msg); | |||||
| try { | |||||
| Transport.send(msg); | |||||
| } catch (SendFailedException sfe) { | |||||
| if (!shouldIgnoreInvalidRecipients()) { | |||||
| throw new BuildException(GENERIC_ERROR, sfe); | |||||
| } else if (sfe.getValidSentAddresses() == null | |||||
| || sfe.getValidSentAddresses().length == 0) { | |||||
| throw new BuildException("Couldn't reach any recipient", | |||||
| sfe); | |||||
| } else { | |||||
| Address[] invalid = sfe.getInvalidAddresses(); | |||||
| if (invalid == null) { | |||||
| invalid = new Address[0]; | |||||
| } | |||||
| for (int i = 0; i < invalid.length; i++) { | |||||
| didntReach(invalid[i], "invalid", sfe); | |||||
| } | |||||
| Address[] validUnsent = sfe.getValidUnsentAddresses(); | |||||
| if (validUnsent == null) { | |||||
| validUnsent = new Address[0]; | |||||
| } | |||||
| for (int i = 0; i < validUnsent.length; i++) { | |||||
| didntReach(validUnsent[i], "valid", sfe); | |||||
| } | |||||
| } | |||||
| } | |||||
| } catch (MessagingException e) { | } catch (MessagingException e) { | ||||
| throw new BuildException("Problem while sending mime mail:", e); | |||||
| throw new BuildException(GENERIC_ERROR, e); | |||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| throw new BuildException("Problem while sending mime mail:", e); | |||||
| throw new BuildException(GENERIC_ERROR, e); | |||||
| } | } | ||||
| } | } | ||||
| @@ -274,6 +305,17 @@ public class MimeMailer extends Mailer { | |||||
| return token.nextToken(); | return token.nextToken(); | ||||
| } | } | ||||
| private void didntReach(Address addr, String category, | |||||
| MessagingException ex) { | |||||
| String msg = "Failed to send mail to " + category + " address " | |||||
| + addr + " because of " + ex.getMessage(); | |||||
| if (task != null) { | |||||
| task.log(msg, Project.MSG_WARN); | |||||
| } else { | |||||
| System.err.println(msg); | |||||
| } | |||||
| } | |||||
| static class SimpleAuthenticator extends Authenticator { | static class SimpleAuthenticator extends Authenticator { | ||||
| private String user = null; | private String user = null; | ||||
| private String password = null; | private String password = null; | ||||
| @@ -24,6 +24,7 @@ import java.io.IOException; | |||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.mail.MailMessage; | import org.apache.tools.mail.MailMessage; | ||||
| /** | /** | ||||
| @@ -44,6 +45,7 @@ class PlainMailer extends Mailer { | |||||
| mailMessage.from(from.toString()); | mailMessage.from(from.toString()); | ||||
| Enumeration e; | Enumeration e; | ||||
| boolean atLeastOneRcptReached = false; | |||||
| e = replyToList.elements(); | e = replyToList.elements(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| @@ -51,15 +53,36 @@ class PlainMailer extends Mailer { | |||||
| } | } | ||||
| e = toList.elements(); | e = toList.elements(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| mailMessage.to(e.nextElement().toString()); | |||||
| String to = e.nextElement().toString(); | |||||
| try { | |||||
| mailMessage.to(to); | |||||
| atLeastOneRcptReached = true; | |||||
| } catch (IOException ex) { | |||||
| badRecipient(to, ex); | |||||
| } | |||||
| } | } | ||||
| e = ccList.elements(); | e = ccList.elements(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| mailMessage.cc(e.nextElement().toString()); | |||||
| String to = e.nextElement().toString(); | |||||
| try { | |||||
| mailMessage.cc(to); | |||||
| atLeastOneRcptReached = true; | |||||
| } catch (IOException ex) { | |||||
| badRecipient(to, ex); | |||||
| } | |||||
| } | } | ||||
| e = bccList.elements(); | e = bccList.elements(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| mailMessage.bcc(e.nextElement().toString()); | |||||
| String to = e.nextElement().toString(); | |||||
| try { | |||||
| mailMessage.bcc(to); | |||||
| atLeastOneRcptReached = true; | |||||
| } catch (IOException ex) { | |||||
| badRecipient(to, ex); | |||||
| } | |||||
| } | |||||
| if (!atLeastOneRcptReached) { | |||||
| throw new BuildException("Couldn't reach any recipient"); | |||||
| } | } | ||||
| if (subject != null) { | if (subject != null) { | ||||
| mailMessage.setSubject(subject); | mailMessage.setSubject(subject); | ||||
| @@ -135,5 +158,19 @@ class PlainMailer extends Mailer { | |||||
| finstr.close(); | finstr.close(); | ||||
| } | } | ||||
| } | } | ||||
| private void badRecipient(String rcpt, IOException reason) { | |||||
| String msg = "Failed to send mail to " + rcpt; | |||||
| if (shouldIgnoreInvalidRecipients()) { | |||||
| msg += " because of :" + reason.getMessage(); | |||||
| if (task != null) { | |||||
| task.log(msg, Project.MSG_WARN); | |||||
| } else { | |||||
| System.err.println(msg); | |||||
| } | |||||
| } else { | |||||
| throw new BuildException(msg, reason); | |||||
| } | |||||
| } | |||||
| } | } | ||||