javax.mail.Transport Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package javax.mail;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;
import javax.mail.event.TransportEvent;
import javax.mail.event.TransportListener;
/**
* Abstract class modeling a message transport.
*
* @version $Rev$ $Date$
*/
public abstract class Transport extends Service {
/**
* Send a message to all recipient addresses the message contains (as returned by {@link Message#getAllRecipients()})
* using message transports appropriate for each address. Message addresses are checked during submission,
* but there is no guarantee that the ultimate address is valid or that the message will ever be delivered.
*
* {@link Message#saveChanges()} will be called before the message is actually sent.
*
* @param message the message to send
* @throws MessagingException if there was a problem sending the message
*/
public static void send(final Message message) throws MessagingException {
send(message, message.getAllRecipients());
}
/**
* Send a message to all addresses provided irrespective of any recipients contained in the message,
* using message transports appropriate for each address. Message addresses are checked during submission,
* but there is no guarantee that the ultimate address is valid or that the message will ever be delivered.
*
* {@link Message#saveChanges()} will be called before the message is actually sent.
*
* @param message the message to send
* @param addresses the addesses to send to
* @throws MessagingException if there was a problem sending the message
*/
public static void send(final Message message, final Address[] addresses) throws MessagingException {
sendInternal(message, addresses, null, null);
}
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> msgsByTransport = new HashMap>();
for (int i = 0; i < addresses.length; i++) {
final Address address = addresses[i];
final Transport transport = session.getTransport(address);
List addrs = msgsByTransport.get(transport);
if (addrs == null) {
addrs = new ArrayList();
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 sentAddresses = new ArrayList();
final List unsentAddresses = new ArrayList();
final List invalidAddresses = new ArrayList();
for (final Iterator>> i = msgsByTransport.entrySet().iterator(); i.hasNext();) {
final Entry> entry = i.next();
final Transport transport = entry.getKey();
final List 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);
}
}
/**
* Send a message. The message will be sent to all recipient
* addresses specified in the message (as returned from the
* Message method getAllRecipients).
* The send method calls the saveChanges
* method on the message before sending it.
*
* Use the specified user name and password to authenticate to
* the mail server.
*
* @param msg the message to send
* @param user the user name
* @param password this user's password
* @exception SendFailedException if the message could not
* be sent to some or any of the recipients.
* @exception MessagingException
* @see Message#saveChanges
* @see #send(Message)
* @see javax.mail.SendFailedException
* @since JavaMail 1.5
*/
public static void send(final Message msg,
final String user, final String password) throws MessagingException {
send(msg, msg.getAllRecipients(), user, password);
}
/**
* Send the message to the specified addresses, ignoring any
* recipients specified in the message itself. The
* send method calls the saveChanges
* method on the message before sending it.
*
* Use the specified user name and password to authenticate to
* the mail server.
*
* @param msg the message to send
* @param addresses the addresses to which to send the message
* @param user the user name
* @param password this user's password
* @exception SendFailedException if the message could not
* be sent to some or any of the recipients.
* @exception MessagingException
* @see Message#saveChanges
* @see #send(Message)
* @see javax.mail.SendFailedException
* @since JavaMail 1.5
*/
public static void send(final Message msg, final Address[] addresses,
final String user, final String password) throws MessagingException {
sendInternal(msg, addresses, user, password);
}
/**
* Constructor taking Session and URLName parameters required for {@link Service#Service(Session, URLName)}.
*
* @param session the Session this transport is for
* @param name the location this transport is for
*/
public Transport(final Session session, final URLName name) {
super(session, name);
}
/**
* Send a message to the supplied addresses using this transport; if any of the addresses are
* invalid then a {@link SendFailedException} is thrown. Whether the message is actually sent
* to any of the addresses is undefined.
*
* Unlike the static {@link #send(Message, Address[])} method, {@link Message#saveChanges()} is
* not called. A {@link TransportEvent} will be sent to registered listeners once the delivery
* attempt has been made.
*
* @param message the message to send
* @param addresses list of addresses to send it to
* @throws SendFailedException if the send failed
* @throws MessagingException if there was a problem sending the message
*/
public abstract void sendMessage(Message message, Address[] addresses) throws MessagingException;
private final Vector transportListeners = new Vector();
public void addTransportListener(final TransportListener listener) {
transportListeners.add(listener);
}
public void removeTransportListener(final TransportListener listener) {
transportListeners.remove(listener);
}
protected void notifyTransportListeners(final int type, final Address[] validSent, final Address[] validUnsent, final Address[] invalid, final Message message) {
queueEvent(new TransportEvent(this, type, validSent, validUnsent, invalid, message), transportListeners);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy