in geronimo-mail_2.1_spec/src/main/java/jakarta/mail/Transport.java [69:181]
private static void sendInternal(final Message message, final Address[] addresses, final String user, final String password) throws MessagingException {
if (addresses == null || addresses.length == 0) {
throw new SendFailedException("No recipient addresses");
}
final Session session = message.session;
final Map<Transport, List<Address>> msgsByTransport = new HashMap<Transport, List<Address>>();
for (int i = 0; i < addresses.length; i++) {
final Address address = addresses[i];
final Transport transport = session.getTransport(address);
List<Address> addrs = msgsByTransport.get(transport);
if (addrs == null) {
addrs = new ArrayList<Address>();
msgsByTransport.put(transport, addrs);
}
addrs.add(address);
}
message.saveChanges();
// Since we might be sending to multiple protocols, we need to catch and process each exception
// when we send and then throw a new SendFailedException when everything is done. Unfortunately, this
// also means unwrapping the information in any SendFailedExceptions we receive and building
// composite failed list.
MessagingException chainedException = null;
final List<Address> sentAddresses = new ArrayList<Address>();
final List<Address> unsentAddresses = new ArrayList<Address>();
final List<Address> invalidAddresses = new ArrayList<Address>();
for (final Iterator<Entry<Transport, List<Address>>> i = msgsByTransport.entrySet().iterator(); i.hasNext();) {
final Entry<Transport, List<Address>> entry = i.next();
final Transport transport = entry.getKey();
final List<Address> addrs = entry.getValue();
try {
// we MUST connect to the transport before attempting to send.
if(user != null) {
transport.connect(user, password);
} else {
transport.connect();
}
transport.sendMessage(message, addrs.toArray(new Address[addrs.size()]));
// if we have to throw an exception because of another failure, these addresses need to
// be in the valid list. Since we succeeded here, we can add these now.
sentAddresses.addAll(addrs);
} catch (final SendFailedException e) {
// a true send failure. The exception contains a wealth of information about
// the failures, including a potential chain of exceptions explaining what went wrong. We're
// going to send a new one of these, so we need to merge the information.
// add this to our exception chain
if (chainedException == null) {
chainedException = e;
}
else {
chainedException.setNextException(e);
}
// now extract each of the address categories from
Address[] exAddrs = e.getValidSentAddresses();
if (exAddrs != null) {
for (int j = 0; j < exAddrs.length; j++) {
sentAddresses.add(exAddrs[j]);
}
}
exAddrs = e.getValidUnsentAddresses();
if (exAddrs != null) {
for (int j = 0; j < exAddrs.length; j++) {
unsentAddresses.add(exAddrs[j]);
}
}
exAddrs = e.getInvalidAddresses();
if (exAddrs != null) {
for (int j = 0; j < exAddrs.length; j++) {
invalidAddresses.add(exAddrs[j]);
}
}
} catch (final MessagingException e) {
// add this to our exception chain
if (chainedException == null) {
chainedException = e;
}
else {
chainedException.setNextException(e);
}
}
finally {
transport.close();
}
}
// if we have an exception chain then we need to throw a new exception giving the failure
// information.
if (chainedException != null) {
// if we're only sending to a single transport (common), and we received a SendFailedException
// as a result, then we have a fully formed exception already. Rather than wrap this in another
// exception, we can just rethrow the one we have.
if (msgsByTransport.size() == 1 && chainedException instanceof SendFailedException) {
throw chainedException;
}
// create our lists for notification and exception reporting from this point on.
final Address[] sent = sentAddresses.toArray(new Address[0]);
final Address[] unsent = unsentAddresses.toArray(new Address[0]);
final Address[] invalid = invalidAddresses.toArray(new Address[0]);
throw new SendFailedException("Send failure", chainedException, sent, unsent, invalid);
}
}