Skip to content

Commit 433b4ef

Browse files
committed
MailSendException includes all messages as failed messages in case of a connect failure (SPR-7245)
1 parent 2f4453a commit 433b4ef

File tree

3 files changed

+100
-39
lines changed

3 files changed

+100
-39
lines changed

org.springframework.context.support/src/main/java/org/springframework/mail/MailSendException.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2008 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -60,15 +60,29 @@ public MailSendException(String msg, Throwable cause) {
6060
* messages that failed as keys, and the thrown exceptions as values.
6161
* <p>The messages should be the same that were originally passed
6262
* to the invoked send method.
63+
* @param msg the detail message
64+
* @param cause the root cause from the mail API in use
6365
* @param failedMessages Map of failed messages as keys and thrown
6466
* exceptions as values
6567
*/
66-
public MailSendException(Map<Object, Exception> failedMessages) {
67-
super(null);
68+
public MailSendException(String msg, Throwable cause, Map<Object, Exception> failedMessages) {
69+
super(msg, cause);
6870
this.failedMessages = new LinkedHashMap<Object, Exception>(failedMessages);
6971
this.messageExceptions = failedMessages.values().toArray(new Exception[failedMessages.size()]);
7072
}
7173

74+
/**
75+
* Constructor for registration of failed messages, with the
76+
* messages that failed as keys, and the thrown exceptions as values.
77+
* <p>The messages should be the same that were originally passed
78+
* to the invoked send method.
79+
* @param failedMessages Map of failed messages as keys and thrown
80+
* exceptions as values
81+
*/
82+
public MailSendException(Map<Object, Exception> failedMessages) {
83+
this(null, null, failedMessages);
84+
}
85+
7286

7387
/**
7488
* Return a Map with the failed messages as keys, and the thrown exceptions
@@ -111,7 +125,12 @@ public String getMessage() {
111125
return super.getMessage();
112126
}
113127
else {
114-
StringBuilder sb = new StringBuilder("Failed messages: ");
128+
StringBuilder sb = new StringBuilder();
129+
String baseMessage = super.getMessage();
130+
if (baseMessage != null) {
131+
sb.append(baseMessage).append(". ");
132+
}
133+
sb.append("Failed messages: ");
115134
for (int i = 0; i < this.messageExceptions.length; i++) {
116135
Exception subEx = this.messageExceptions[i];
117136
sb.append(subEx.toString());
@@ -129,8 +148,8 @@ public String toString() {
129148
return super.toString();
130149
}
131150
else {
132-
StringBuilder sb = new StringBuilder(getClass().getName());
133-
sb.append("; nested exceptions (").append(this.messageExceptions.length).append(") are:");
151+
StringBuilder sb = new StringBuilder(super.toString());
152+
sb.append("; message exceptions (").append(this.messageExceptions.length).append(") are:");
134153
for (int i = 0; i < this.messageExceptions.length; i++) {
135154
Exception subEx = this.messageExceptions[i];
136155
sb.append('\n').append("Failed message ").append(i + 1).append(": ");
@@ -146,7 +165,7 @@ public void printStackTrace(PrintStream ps) {
146165
super.printStackTrace(ps);
147166
}
148167
else {
149-
ps.println(getClass().getName() + "; nested exception details (" +
168+
ps.println(super.toString() + "; message exception details (" +
150169
this.messageExceptions.length + ") are:");
151170
for (int i = 0; i < this.messageExceptions.length; i++) {
152171
Exception subEx = this.messageExceptions[i];
@@ -162,7 +181,7 @@ public void printStackTrace(PrintWriter pw) {
162181
super.printStackTrace(pw);
163182
}
164183
else {
165-
pw.println(getClass().getName() + "; nested exception details (" +
184+
pw.println(super.toString() + "; message exception details (" +
166185
this.messageExceptions.length + ") are:");
167186
for (int i = 0; i < this.messageExceptions.length; i++) {
168187
Exception subEx = this.messageExceptions[i];

org.springframework.context.support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2008 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Properties;
27-
2827
import javax.activation.FileTypeMap;
2928
import javax.mail.AuthenticationFailedException;
3029
import javax.mail.MessagingException;
@@ -383,40 +382,60 @@ public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailExce
383382
*/
384383
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
385384
Map<Object, Exception> failedMessages = new LinkedHashMap<Object, Exception>();
385+
386+
Transport transport;
386387
try {
387-
Transport transport = getTransport(getSession());
388+
transport = getTransport(getSession());
388389
transport.connect(getHost(), getPort(), getUsername(), getPassword());
389-
try {
390-
for (int i = 0; i < mimeMessages.length; i++) {
391-
MimeMessage mimeMessage = mimeMessages[i];
392-
try {
393-
if (mimeMessage.getSentDate() == null) {
394-
mimeMessage.setSentDate(new Date());
395-
}
396-
String messageId = mimeMessage.getMessageID();
397-
mimeMessage.saveChanges();
398-
if (messageId != null) {
399-
// Preserve explicitly specified message id...
400-
mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId);
401-
}
402-
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
390+
}
391+
catch (AuthenticationFailedException ex) {
392+
throw new MailAuthenticationException(ex);
393+
}
394+
catch (MessagingException ex) {
395+
// Effectively, all messages failed...
396+
for (int i = 0; i < mimeMessages.length; i++) {
397+
Object original = (originalMessages != null ? originalMessages[i] : mimeMessages[i]);
398+
failedMessages.put(original, ex);
399+
}
400+
throw new MailSendException("Mail server connection failed", ex, failedMessages);
401+
}
402+
403+
try {
404+
for (int i = 0; i < mimeMessages.length; i++) {
405+
MimeMessage mimeMessage = mimeMessages[i];
406+
try {
407+
if (mimeMessage.getSentDate() == null) {
408+
mimeMessage.setSentDate(new Date());
403409
}
404-
catch (MessagingException ex) {
405-
Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
406-
failedMessages.put(original, ex);
410+
String messageId = mimeMessage.getMessageID();
411+
mimeMessage.saveChanges();
412+
if (messageId != null) {
413+
// Preserve explicitly specified message id...
414+
mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId);
407415
}
416+
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
417+
}
418+
catch (MessagingException ex) {
419+
Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
420+
failedMessages.put(original, ex);
408421
}
409422
}
410-
finally {
423+
}
424+
finally {
425+
try {
411426
transport.close();
412427
}
428+
catch (MessagingException ex) {
429+
if (!failedMessages.isEmpty()) {
430+
throw new MailSendException("Failed to close server connection after message failures", ex,
431+
failedMessages);
432+
}
433+
else {
434+
throw new MailSendException("Failed to close server connection after message sending", ex);
435+
}
436+
}
413437
}
414-
catch (AuthenticationFailedException ex) {
415-
throw new MailAuthenticationException(ex);
416-
}
417-
catch (MessagingException ex) {
418-
throw new MailSendException("Mail server connection failed", ex);
419-
}
438+
420439
if (!failedMessages.isEmpty()) {
421440
throw new MailSendException(failedMessages);
422441
}

org.springframework.context.support/src/test/java/org/springframework/mail/javamail/JavaMailSenderTests.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2006 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
2222
import java.util.Date;
2323
import java.util.List;
2424
import java.util.Properties;
25-
2625
import javax.activation.FileTypeMap;
2726
import javax.mail.Address;
2827
import javax.mail.Message;
@@ -381,8 +380,29 @@ public void testFailedMailServerConnect() throws Exception {
381380
}
382381
catch (MailSendException ex) {
383382
// expected
383+
ex.printStackTrace();
384384
assertTrue(ex.getFailedMessages() != null);
385-
assertTrue(ex.getFailedMessages().isEmpty());
385+
assertEquals(1, ex.getFailedMessages().size());
386+
assertSame(simpleMessage1, ex.getFailedMessages().keySet().iterator().next());
387+
assertSame(ex.getCause(), ex.getFailedMessages().values().iterator().next());
388+
}
389+
}
390+
391+
public void testFailedMailServerClose() throws Exception {
392+
MockJavaMailSender sender = new MockJavaMailSender();
393+
sender.setHost("");
394+
sender.setUsername("username");
395+
sender.setPassword("password");
396+
SimpleMailMessage simpleMessage1 = new SimpleMailMessage();
397+
try {
398+
sender.send(simpleMessage1);
399+
fail("Should have thrown MailSendException");
400+
}
401+
catch (MailSendException ex) {
402+
// expected
403+
ex.printStackTrace();
404+
assertTrue(ex.getFailedMessages() != null);
405+
assertEquals(0, ex.getFailedMessages().size());
386406
}
387407
}
388408

@@ -515,6 +535,9 @@ public void connect(String host, int port, String username, String password) thr
515535

516536
@Override
517537
public synchronized void close() throws MessagingException {
538+
if ("".equals(connectedHost)) {
539+
throw new MessagingException("close failure");
540+
}
518541
this.closeCalled = true;
519542
}
520543

@@ -531,7 +554,7 @@ public void sendMessage(Message message, Address[] addresses) throws MessagingEx
531554
if (message.getSentDate() == null) {
532555
throw new MessagingException("No sentDate specified");
533556
}
534-
if (message.getSubject() != null && message.getSubject().indexOf("custom") != -1) {
557+
if (message.getSubject() != null && message.getSubject().contains("custom")) {
535558
assertEquals(new Date(2005, 3, 1), message.getSentDate());
536559
}
537560
this.sentMessages.add(message);

0 commit comments

Comments
 (0)