001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.mail; 018 019import java.io.PrintStream; 020import java.io.PrintWriter; 021import java.util.LinkedHashMap; 022import java.util.Map; 023 024import org.springframework.util.ObjectUtils; 025 026/** 027 * Exception thrown when a mail sending error is encountered. 028 * Can register failed messages with their exceptions. 029 * 030 * @author Dmitriy Kopylenko 031 * @author Juergen Hoeller 032 */ 033@SuppressWarnings("serial") 034public class MailSendException extends MailException { 035 036 private transient final Map<Object, Exception> failedMessages; 037 038 private Exception[] messageExceptions; 039 040 041 /** 042 * Constructor for MailSendException. 043 * @param msg the detail message 044 */ 045 public MailSendException(String msg) { 046 this(msg, null); 047 } 048 049 /** 050 * Constructor for MailSendException. 051 * @param msg the detail message 052 * @param cause the root cause from the mail API in use 053 */ 054 public MailSendException(String msg, Throwable cause) { 055 super(msg, cause); 056 this.failedMessages = new LinkedHashMap<Object, Exception>(); 057 } 058 059 /** 060 * Constructor for registration of failed messages, with the 061 * messages that failed as keys, and the thrown exceptions as values. 062 * <p>The messages should be the same that were originally passed 063 * to the invoked send method. 064 * @param msg the detail message 065 * @param cause the root cause from the mail API in use 066 * @param failedMessages Map of failed messages as keys and thrown 067 * exceptions as values 068 */ 069 public MailSendException(String msg, Throwable cause, Map<Object, Exception> failedMessages) { 070 super(msg, cause); 071 this.failedMessages = new LinkedHashMap<Object, Exception>(failedMessages); 072 this.messageExceptions = failedMessages.values().toArray(new Exception[failedMessages.size()]); 073 } 074 075 /** 076 * Constructor for registration of failed messages, with the 077 * messages that failed as keys, and the thrown exceptions as values. 078 * <p>The messages should be the same that were originally passed 079 * to the invoked send method. 080 * @param failedMessages Map of failed messages as keys and thrown 081 * exceptions as values 082 */ 083 public MailSendException(Map<Object, Exception> failedMessages) { 084 this(null, null, failedMessages); 085 } 086 087 088 /** 089 * Return a Map with the failed messages as keys, and the thrown exceptions 090 * as values. 091 * <p>Note that a general mail server connection failure will not result 092 * in failed messages being returned here: A message will only be 093 * contained here if actually sending it was attempted but failed. 094 * <p>The messages will be the same that were originally passed to the 095 * invoked send method, that is, SimpleMailMessages in case of using 096 * the generic MailSender interface. 097 * <p>In case of sending MimeMessage instances via JavaMailSender, 098 * the messages will be of type MimeMessage. 099 * <p><b>NOTE:</b> This Map will not be available after serialization. 100 * Use {@link #getMessageExceptions()} in such a scenario, which will 101 * be available after serialization as well. 102 * @return the Map of failed messages as keys and thrown exceptions as values 103 * @see SimpleMailMessage 104 * @see javax.mail.internet.MimeMessage 105 */ 106 public final Map<Object, Exception> getFailedMessages() { 107 return this.failedMessages; 108 } 109 110 /** 111 * Return an array with thrown message exceptions. 112 * <p>Note that a general mail server connection failure will not result 113 * in failed messages being returned here: A message will only be 114 * contained here if actually sending it was attempted but failed. 115 * @return the array of thrown message exceptions, 116 * or an empty array if no failed messages 117 */ 118 public final Exception[] getMessageExceptions() { 119 return (this.messageExceptions != null ? this.messageExceptions : new Exception[0]); 120 } 121 122 123 @Override 124 public String getMessage() { 125 if (ObjectUtils.isEmpty(this.messageExceptions)) { 126 return super.getMessage(); 127 } 128 else { 129 StringBuilder sb = new StringBuilder(); 130 String baseMessage = super.getMessage(); 131 if (baseMessage != null) { 132 sb.append(baseMessage).append(". "); 133 } 134 sb.append("Failed messages: "); 135 for (int i = 0; i < this.messageExceptions.length; i++) { 136 Exception subEx = this.messageExceptions[i]; 137 sb.append(subEx.toString()); 138 if (i < this.messageExceptions.length - 1) { 139 sb.append("; "); 140 } 141 } 142 return sb.toString(); 143 } 144 } 145 146 @Override 147 public String toString() { 148 if (ObjectUtils.isEmpty(this.messageExceptions)) { 149 return super.toString(); 150 } 151 else { 152 StringBuilder sb = new StringBuilder(super.toString()); 153 sb.append("; message exceptions (").append(this.messageExceptions.length).append(") are:"); 154 for (int i = 0; i < this.messageExceptions.length; i++) { 155 Exception subEx = this.messageExceptions[i]; 156 sb.append('\n').append("Failed message ").append(i + 1).append(": "); 157 sb.append(subEx); 158 } 159 return sb.toString(); 160 } 161 } 162 163 @Override 164 public void printStackTrace(PrintStream ps) { 165 if (ObjectUtils.isEmpty(this.messageExceptions)) { 166 super.printStackTrace(ps); 167 } 168 else { 169 ps.println(super.toString() + "; message exception details (" + 170 this.messageExceptions.length + ") are:"); 171 for (int i = 0; i < this.messageExceptions.length; i++) { 172 Exception subEx = this.messageExceptions[i]; 173 ps.println("Failed message " + (i + 1) + ":"); 174 subEx.printStackTrace(ps); 175 } 176 } 177 } 178 179 @Override 180 public void printStackTrace(PrintWriter pw) { 181 if (ObjectUtils.isEmpty(this.messageExceptions)) { 182 super.printStackTrace(pw); 183 } 184 else { 185 pw.println(super.toString() + "; message exception details (" + 186 this.messageExceptions.length + ") are:"); 187 for (int i = 0; i < this.messageExceptions.length; i++) { 188 Exception subEx = this.messageExceptions[i]; 189 pw.println("Failed message " + (i + 1) + ":"); 190 subEx.printStackTrace(pw); 191 } 192 } 193 } 194 195}