/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://oss.oracle.com/licenses/CDDL+GPL-1.1
 * or LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package javax.mail;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.mail.event.*;

An abstract class that models a message transport. Subclasses provide actual implementations.

Note that Transport extends the Service class, which provides many common methods for naming transports, connecting to transports, and listening to connection events.

Author:John Mani, Max Spivak, Bill Shannon
See Also:
/** * An abstract class that models a message transport. * Subclasses provide actual implementations. <p> * * Note that <code>Transport</code> extends the <code>Service</code> * class, which provides many common methods for naming transports, * connecting to transports, and listening to connection events. * * @author John Mani * @author Max Spivak * @author Bill Shannon * * @see javax.mail.Service * @see javax.mail.event.ConnectionEvent * @see javax.mail.event.TransportEvent */
public abstract class Transport extends Service {
Constructor.
Params:
  • session – Session object for this Transport.
  • urlname – URLName object to be used for this Transport
/** * Constructor. * * @param session Session object for this Transport. * @param urlname URLName object to be used for this Transport */
public Transport(Session session, URLName urlname) { super(session, urlname); }
Send a message. The message will be sent to all recipient addresses specified in the message (as returned from the Message method getAllRecipients), using message transports appropriate to each address. The send method calls the saveChanges method on the message before sending it.

If any of the recipient addresses is detected to be invalid by the Transport during message submission, a SendFailedException is thrown. Clients can get more detail about the failure by examining the exception. Whether or not the message is still sent successfully to any valid addresses depends on the Transport implementation. See SendFailedException for more details. Note also that success does not imply that the message was delivered to the ultimate recipient, as failures may occur in later stages of delivery. Once a Transport accepts a message for delivery to a recipient, failures that occur later should be reported to the user via another mechanism, such as returning the undeliverable message.

In typical usage, a SendFailedException reflects an error detected by the server. The details of the SendFailedException will usually contain the error message from the server (such as an SMTP error message). An address may be detected as invalid for a variety of reasons - the address may not exist, the address may have invalid syntax, the address may have exceeded its quota, etc.

Note that send is a static method that creates and manages its own connection. Any connection associated with any Transport instance used to invoke this method is ignored and not used. This method should only be invoked using the form Transport.send(msg);, and should never be invoked using an instance variable.

Params:
  • msg – the message to send
Throws:
See Also:
/** * Send a message. The message will be sent to all recipient * addresses specified in the message (as returned from the * <code>Message</code> method <code>getAllRecipients</code>), * using message transports appropriate to each address. The * <code>send</code> method calls the <code>saveChanges</code> * method on the message before sending it. <p> * * If any of the recipient addresses is detected to be invalid by * the Transport during message submission, a SendFailedException * is thrown. Clients can get more detail about the failure by examining * the exception. Whether or not the message is still sent successfully * to any valid addresses depends on the Transport implementation. See * SendFailedException for more details. Note also that success does * not imply that the message was delivered to the ultimate recipient, * as failures may occur in later stages of delivery. Once a Transport * accepts a message for delivery to a recipient, failures that occur later * should be reported to the user via another mechanism, such as * returning the undeliverable message. <p> * * In typical usage, a SendFailedException reflects an error detected * by the server. The details of the SendFailedException will usually * contain the error message from the server (such as an SMTP error * message). An address may be detected as invalid for a variety of * reasons - the address may not exist, the address may have invalid * syntax, the address may have exceeded its quota, etc. <p> * * Note that <code>send</code> is a static method that creates and * manages its own connection. Any connection associated with any * Transport instance used to invoke this method is ignored and not * used. This method should only be invoked using the form * <code>Transport.send(msg);</code>, and should never be invoked * using an instance variable. * * @param msg the message to send * @exception SendFailedException if the message could not * be sent to some or any of the recipients. * @exception MessagingException for other failures * @see Message#saveChanges * @see Message#getAllRecipients * @see #send(Message, Address[]) * @see javax.mail.SendFailedException */
public static void send(Message msg) throws MessagingException { msg.saveChanges(); // do this first send0(msg, msg.getAllRecipients(), null, null); }
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.

Params:
  • msg – the message to send
  • addresses – the addresses to which to send the message
Throws:
See Also:
/** * Send the message to the specified addresses, ignoring any * recipients specified in the message itself. The * <code>send</code> method calls the <code>saveChanges</code> * method on the message before sending it. <p> * * @param msg the message to send * @param addresses the addresses to which to send the message * @exception SendFailedException if the message could not * be sent to some or any of the recipients. * @exception MessagingException for other failures * @see Message#saveChanges * @see #send(Message) * @see javax.mail.SendFailedException */
public static void send(Message msg, Address[] addresses) throws MessagingException { msg.saveChanges(); send0(msg, addresses, null, null); }
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.

Params:
  • msg – the message to send
  • user – the user name
  • password – this user's password
Throws:
See Also:
Since: JavaMail 1.5
/** * Send a message. The message will be sent to all recipient * addresses specified in the message (as returned from the * <code>Message</code> method <code>getAllRecipients</code>). * The <code>send</code> method calls the <code>saveChanges</code> * method on the message before sending it. <p> * * 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 for other failures * @see Message#saveChanges * @see #send(Message) * @see javax.mail.SendFailedException * @since JavaMail 1.5 */
public static void send(Message msg, String user, String password) throws MessagingException { msg.saveChanges(); send0(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.

Params:
  • msg – the message to send
  • addresses – the addresses to which to send the message
  • user – the user name
  • password – this user's password
Throws:
See Also:
Since: JavaMail 1.5
/** * Send the message to the specified addresses, ignoring any * recipients specified in the message itself. The * <code>send</code> method calls the <code>saveChanges</code> * method on the message before sending it. <p> * * 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 for other failures * @see Message#saveChanges * @see #send(Message) * @see javax.mail.SendFailedException * @since JavaMail 1.5 */
public static void send(Message msg, Address[] addresses, String user, String password) throws MessagingException { msg.saveChanges(); send0(msg, addresses, user, password); } // send, but without the saveChanges private static void send0(Message msg, Address[] addresses, String user, String password) throws MessagingException { if (addresses == null || addresses.length == 0) throw new SendFailedException("No recipient addresses"); /* * protocols is a map containing the addresses * indexed by address type */ Map<String, List<Address>> protocols = new HashMap<>(); // Lists of addresses List<Address> invalid = new ArrayList<>(); List<Address> validSent = new ArrayList<>(); List<Address> validUnsent = new ArrayList<>(); for (int i = 0; i < addresses.length; i++) { // is this address type already in the map? if (protocols.containsKey(addresses[i].getType())) { List<Address> v = protocols.get(addresses[i].getType()); v.add(addresses[i]); } else { // need to add a new protocol List<Address> w = new ArrayList<>(); w.add(addresses[i]); protocols.put(addresses[i].getType(), w); } } int dsize = protocols.size(); if (dsize == 0) throw new SendFailedException("No recipient addresses"); Session s = (msg.session != null) ? msg.session : Session.getDefaultInstance(System.getProperties(), null); Transport transport; /* * Optimize the case of a single protocol. */ if (dsize == 1) { transport = s.getTransport(addresses[0]); try { if (user != null) transport.connect(user, password); else transport.connect(); transport.sendMessage(msg, addresses); } finally { transport.close(); } return; } /* * More than one protocol. Have to do them one at a time * and collect addresses and chain exceptions. */ MessagingException chainedEx = null; boolean sendFailed = false; for(List<Address> v : protocols.values()) { Address[] protaddresses = new Address[v.size()]; v.toArray(protaddresses); // Get a Transport that can handle this address type. if ((transport = s.getTransport(protaddresses[0])) == null) { // Could not find an appropriate Transport .. // Mark these addresses invalid. for (int j = 0; j < protaddresses.length; j++) invalid.add(protaddresses[j]); continue; } try { transport.connect(); transport.sendMessage(msg, protaddresses); } catch (SendFailedException sex) { sendFailed = true; // chain the exception we're catching to any previous ones if (chainedEx == null) chainedEx = sex; else chainedEx.setNextException(sex); // retrieve invalid addresses Address[] a = sex.getInvalidAddresses(); if (a != null) for (int j = 0; j < a.length; j++) invalid.add(a[j]); // retrieve validSent addresses a = sex.getValidSentAddresses(); if (a != null) for (int k = 0; k < a.length; k++) validSent.add(a[k]); // retrieve validUnsent addresses Address[] c = sex.getValidUnsentAddresses(); if (c != null) for (int l = 0; l < c.length; l++) validUnsent.add(c[l]); } catch (MessagingException mex) { sendFailed = true; // chain the exception we're catching to any previous ones if (chainedEx == null) chainedEx = mex; else chainedEx.setNextException(mex); } finally { transport.close(); } } // done with all protocols. throw exception if something failed if (sendFailed || invalid.size() != 0 || validUnsent.size() != 0) { Address[] a = null, b = null, c = null; // copy address lists into arrays if (validSent.size() > 0) { a = new Address[validSent.size()]; validSent.toArray(a); } if (validUnsent.size() > 0) { b = new Address[validUnsent.size()]; validUnsent.toArray(b); } if (invalid.size() > 0) { c = new Address[invalid.size()]; invalid.toArray(c); } throw new SendFailedException("Sending failed", chainedEx, a, b, c); } }
Send the Message to the specified list of addresses. An appropriate TransportEvent indicating the delivery status is delivered to any TransportListener registered on this Transport. Also, if any of the addresses is invalid, a SendFailedException is thrown. Whether or not the message is still sent succesfully to any valid addresses depends on the Transport implementation.

Unlike the static send method, the sendMessage method does not call the saveChanges method on the message; the caller should do so.

Params:
  • msg – The Message to be sent
  • addresses – array of addresses to send this message to
Throws:
See Also:
/** * Send the Message to the specified list of addresses. An appropriate * TransportEvent indicating the delivery status is delivered to any * TransportListener registered on this Transport. Also, if any of * the addresses is invalid, a SendFailedException is thrown. * Whether or not the message is still sent succesfully to * any valid addresses depends on the Transport implementation. <p> * * Unlike the static <code>send</code> method, the <code>sendMessage</code> * method does <em>not</em> call the <code>saveChanges</code> method on * the message; the caller should do so. * * @param msg The Message to be sent * @param addresses array of addresses to send this message to * @see javax.mail.event.TransportEvent * @exception SendFailedException if the send failed because of * invalid addresses. * @exception MessagingException if the connection is dead or not in the * connected state */
public abstract void sendMessage(Message msg, Address[] addresses) throws MessagingException; // Vector of Transport listeners private volatile Vector<TransportListener> transportListeners = null;
Add a listener for Transport events.

The default implementation provided here adds this listener to an internal list of TransportListeners.

Params:
  • l – the Listener for Transport events
See Also:
/** * Add a listener for Transport events. <p> * * The default implementation provided here adds this listener * to an internal list of TransportListeners. * * @param l the Listener for Transport events * @see javax.mail.event.TransportEvent */
public synchronized void addTransportListener(TransportListener l) { if (transportListeners == null) transportListeners = new Vector<>(); transportListeners.addElement(l); }
Remove a listener for Transport events.

The default implementation provided here removes this listener from the internal list of TransportListeners.

Params:
  • l – the listener
See Also:
/** * Remove a listener for Transport events. <p> * * The default implementation provided here removes this listener * from the internal list of TransportListeners. * * @param l the listener * @see #addTransportListener */
public synchronized void removeTransportListener(TransportListener l) { if (transportListeners != null) transportListeners.removeElement(l); }
Notify all TransportListeners. Transport implementations are expected to use this method to broadcast TransportEvents.

The provided default implementation queues the event into an internal event queue. An event dispatcher thread dequeues events from the queue and dispatches them to the registered TransportListeners. Note that the event dispatching occurs in a separate thread, thus avoiding potential deadlock problems.

Params:
  • type – the TransportEvent type
  • validSent – valid addresses to which message was sent
  • validUnsent – valid addresses to which message was not sent
  • invalid – the invalid addresses
  • msg – the message
/** * Notify all TransportListeners. Transport implementations are * expected to use this method to broadcast TransportEvents.<p> * * The provided default implementation queues the event into * an internal event queue. An event dispatcher thread dequeues * events from the queue and dispatches them to the registered * TransportListeners. Note that the event dispatching occurs * in a separate thread, thus avoiding potential deadlock problems. * * @param type the TransportEvent type * @param validSent valid addresses to which message was sent * @param validUnsent valid addresses to which message was not sent * @param invalid the invalid addresses * @param msg the message */
protected void notifyTransportListeners(int type, Address[] validSent, Address[] validUnsent, Address[] invalid, Message msg) { if (transportListeners == null) return; TransportEvent e = new TransportEvent(this, type, validSent, validUnsent, invalid, msg); queueEvent(e, transportListeners); } }