Skip to content

Commit b7faef0

Browse files
committed
JavaMailSenderImpl catches Exception instead of MessagingException and checks for reconnect in case of message batches
Issue: SPR-12298
1 parent 12a2813 commit b7faef0

File tree

2 files changed

+73
-39
lines changed

2 files changed

+73
-39
lines changed

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

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 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.
@@ -330,7 +330,7 @@ public MimeMessage createMimeMessage(InputStream contentStream) throws MailExcep
330330
try {
331331
return new MimeMessage(getSession(), contentStream);
332332
}
333-
catch (MessagingException ex) {
333+
catch (Exception ex) {
334334
throw new MailParseException("Could not parse raw MIME content", ex);
335335
}
336336
}
@@ -385,35 +385,40 @@ public void send(MimeMessagePreparator... mimeMessagePreparators) throws MailExc
385385
* in case of failure when sending a message
386386
*/
387387
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
388-
String username = getUsername();
389-
String password = getPassword();
390-
if ("".equals(username)) { // probably from a placeholder
391-
username = null;
392-
if ("".equals(password)) { // in conjunction with "" username, this means no password to use
393-
password = null;
394-
}
395-
}
396-
397388
Map<Object, Exception> failedMessages = new LinkedHashMap<Object, Exception>();
398-
Transport transport;
399-
try {
400-
transport = getTransport(getSession());
401-
transport.connect(getHost(), getPort(), username, password);
402-
}
403-
catch (AuthenticationFailedException ex) {
404-
throw new MailAuthenticationException(ex);
405-
}
406-
catch (MessagingException ex) {
407-
// Effectively, all messages failed...
408-
for (int i = 0; i < mimeMessages.length; i++) {
409-
Object original = (originalMessages != null ? originalMessages[i] : mimeMessages[i]);
410-
failedMessages.put(original, ex);
411-
}
412-
throw new MailSendException("Mail server connection failed", ex, failedMessages);
413-
}
389+
Transport transport = null;
414390

415391
try {
416392
for (int i = 0; i < mimeMessages.length; i++) {
393+
394+
// Check transport connection first...
395+
if (transport == null || !transport.isConnected()) {
396+
if (transport != null) {
397+
try {
398+
transport.close();
399+
}
400+
catch (Exception ex) {
401+
// Ignore - we're reconnecting anyway
402+
}
403+
transport = null;
404+
}
405+
try {
406+
transport = connectTransport();
407+
}
408+
catch (AuthenticationFailedException ex) {
409+
throw new MailAuthenticationException(ex);
410+
}
411+
catch (Exception ex) {
412+
// Effectively, all remaining messages failed...
413+
for (int j = i; j < mimeMessages.length; j++) {
414+
Object original = (originalMessages != null ? originalMessages[j] : mimeMessages[j]);
415+
failedMessages.put(original, ex);
416+
}
417+
throw new MailSendException("Mail server connection failed", ex, failedMessages);
418+
}
419+
}
420+
421+
// Send message via current transport...
417422
MimeMessage mimeMessage = mimeMessages[i];
418423
try {
419424
if (mimeMessage.getSentDate() == null) {
@@ -427,17 +432,19 @@ protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) thr
427432
}
428433
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
429434
}
430-
catch (MessagingException ex) {
435+
catch (Exception ex) {
431436
Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
432437
failedMessages.put(original, ex);
433438
}
434439
}
435440
}
436441
finally {
437442
try {
438-
transport.close();
443+
if (transport != null) {
444+
transport.close();
445+
}
439446
}
440-
catch (MessagingException ex) {
447+
catch (Exception ex) {
441448
if (!failedMessages.isEmpty()) {
442449
throw new MailSendException("Failed to close server connection after message failures", ex,
443450
failedMessages);
@@ -453,11 +460,39 @@ protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) thr
453460
}
454461
}
455462

463+
/**
464+
* Obtain and connect a Transport from the underlying JavaMail Session,
465+
* passing in the specified host, port, username, and password.
466+
* @return the connected Transport object
467+
* @throws MessagingException if the connect attempt failed
468+
* @since 4.1.2
469+
* @see #getTransport
470+
* @see #getHost()
471+
* @see #getPort()
472+
* @see #getUsername()
473+
* @see #getPassword()
474+
*/
475+
protected Transport connectTransport() throws MessagingException {
476+
String username = getUsername();
477+
String password = getPassword();
478+
if ("".equals(username)) { // probably from a placeholder
479+
username = null;
480+
if ("".equals(password)) { // in conjunction with "" username, this means no password to use
481+
password = null;
482+
}
483+
}
484+
485+
Transport transport = getTransport(getSession());
486+
transport.connect(getHost(), getPort(), username, password);
487+
return transport;
488+
}
489+
456490
/**
457491
* Obtain a Transport object from the given JavaMail Session,
458492
* using the configured protocol.
459493
* <p>Can be overridden in subclasses, e.g. to return a mock Transport object.
460494
* @see javax.mail.Session#getTransport(String)
495+
* @see #getSession()
461496
* @see #getProtocol()
462497
*/
463498
protected Transport getTransport(Session session) throws NoSuchProviderException {

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.GregorianCalendar;
2424
import java.util.List;
2525
import java.util.Properties;
26-
2726
import javax.activation.FileTypeMap;
2827
import javax.mail.Address;
2928
import javax.mail.Message;
@@ -41,6 +40,7 @@
4140
import org.springframework.mail.MailParseException;
4241
import org.springframework.mail.MailSendException;
4342
import org.springframework.mail.SimpleMailMessage;
43+
import org.springframework.util.ObjectUtils;
4444

4545
/**
4646
* @author Juergen Hoeller
@@ -106,7 +106,7 @@ public void testJavaMailSenderWithSimpleMessages() throws MessagingException, IO
106106
simpleMessage1.setTo("[email protected]");
107107
SimpleMailMessage simpleMessage2 = new SimpleMailMessage();
108108
simpleMessage2.setTo("[email protected]");
109-
sender.send(new SimpleMailMessage[] {simpleMessage1, simpleMessage2});
109+
sender.send(simpleMessage1, simpleMessage2);
110110

111111
assertEquals("host", sender.transport.getConnectedHost());
112112
assertEquals("username", sender.transport.getConnectedUsername());
@@ -152,7 +152,7 @@ public void testJavaMailSenderWithMimeMessages() throws MessagingException {
152152
mimeMessage1.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
153153
MimeMessage mimeMessage2 = sender.createMimeMessage();
154154
mimeMessage2.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
155-
sender.send(new MimeMessage[] {mimeMessage1, mimeMessage2});
155+
sender.send(mimeMessage1, mimeMessage2);
156156

157157
assertEquals("host", sender.transport.getConnectedHost());
158158
assertEquals("username", sender.transport.getConnectedUsername());
@@ -210,7 +210,7 @@ public void prepare(MimeMessage mimeMessage) throws MessagingException {
210210
messages.add(mimeMessage);
211211
}
212212
};
213-
sender.send(new MimeMessagePreparator[] {preparator1, preparator2});
213+
sender.send(preparator1, preparator2);
214214

215215
assertEquals("host", sender.transport.getConnectedHost());
216216
assertEquals("username", sender.transport.getConnectedUsername());
@@ -425,7 +425,7 @@ public void testFailedSimpleMessage() throws Exception {
425425
simpleMessage2.setTo("[email protected]");
426426

427427
try {
428-
sender.send(new SimpleMailMessage[] {simpleMessage1, simpleMessage2});
428+
sender.send(simpleMessage1, simpleMessage2);
429429
}
430430
catch (MailSendException ex) {
431431
ex.printStackTrace();
@@ -456,7 +456,7 @@ public void testFailedMimeMessage() throws Exception {
456456
mimeMessage2.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
457457

458458
try {
459-
sender.send(new MimeMessage[] {mimeMessage1, mimeMessage2});
459+
sender.send(mimeMessage1, mimeMessage2);
460460
}
461461
catch (MailSendException ex) {
462462
ex.printStackTrace();
@@ -537,6 +537,7 @@ public void connect(String host, int port, String username, String password) thr
537537
this.connectedPort = port;
538538
this.connectedUsername = username;
539539
this.connectedPassword = password;
540+
setConnected(true);
540541
}
541542

542543
@Override
@@ -552,9 +553,7 @@ public void sendMessage(Message message, Address[] addresses) throws MessagingEx
552553
if ("fail".equals(message.getSubject())) {
553554
throw new MessagingException("failed");
554555
}
555-
List<Address> addr1 = Arrays.asList(message.getAllRecipients());
556-
List<Address> addr2 = Arrays.asList(addresses);
557-
if (!addr1.equals(addr2)) {
556+
if (!ObjectUtils.nullSafeEquals(addresses, message.getAllRecipients())) {
558557
throw new MessagingException("addresses not correct");
559558
}
560559
if (message.getSentDate() == null) {

0 commit comments

Comments
 (0)