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); | |||||
} | |||||
} | |||||
} | } | ||||