public void sendMessage()

in geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/transport/smtp/SMTPTransport.java [176:416]


    public void sendMessage(Message message, Address[] addresses) throws MessagingException {
        if (!isConnected()) {
            throw new IllegalStateException("Not connected");
        }
        // don't bother me w/ null messages or no addreses
        if (message == null) {
            throw new MessagingException("Null message");
        }

        // SMTP only handles instances of MimeMessage, not the more general
        // message case.
        if (!(message instanceof MimeMessage)) {
            throw new MessagingException("SMTP can only send MimeMessages");
        }

        // we must have a message list.
        if (addresses == null || addresses.length == 0) {
            throw new MessagingException("Null or empty address array");
        }
        
        boolean reportSuccess = getReportSuccess(); 
        
        // now see how we're configured for this send operation.
        boolean partialSends = false;

        // this can be attached directly to the message.
        if (message instanceof SMTPMessage) {
            partialSends = ((SMTPMessage) message).getSendPartial();
        }

        // if still false on the message object, check for a property
        // version also
        if (!partialSends) {
            partialSends = props.getBooleanProperty(MAIL_SMTP_SENDPARTIAL, false);
        }

        boolean haveGroup = false;

        // enforce the requirement that all of the targets are InternetAddress
        // instances.
        for (int i = 0; i < addresses.length; i++) {
            if (addresses[i] instanceof InternetAddress) {
                // and while we're here, see if we have a groups in the address
                // list. If we do, then
                // we're going to need to expand these before sending.
                if (((InternetAddress) addresses[i]).isGroup()) {
                    haveGroup = true;
                }
            } else {
                throw new MessagingException("Illegal InternetAddress " + addresses[i]);
            }
        }

        // did we find a group? Time to expand this into our full target list.
        if (haveGroup) {
            addresses = expandGroups(addresses);
        }

        SendStatus[] stats = new SendStatus[addresses.length];

        // create our lists for notification and exception reporting.
        Address[] sent = null;
        Address[] unsent = null;
        Address[] invalid = null;

        try {
            // send sender first. If this failed, send a failure notice of the
            // event, using the full list of
            // addresses as the unsent, and nothing for the rest.
            if (!connection.sendMailFrom(message)) {
                unsent = addresses;
                sent = new Address[0];
                invalid = new Address[0];
                // notify of the error.
                notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED, sent, unsent, invalid, message);

                // include the reponse information here.
                SMTPReply last = connection.getLastServerResponse(); 
                // now send an "uber-exception" to indicate the failure.
                throw new SMTPSendFailedException("MAIL FROM", last.getCode(), last.getMessage(), null, sent, unsent,
                        invalid);
            }

            // get the additional notification status, if available 
            String dsn = getDeliveryStatusNotification(message);

            // we need to know about any failures once we've gone through the
            // complete list, so keep a
            // failure flag.
            boolean sendFailure = false;

            // event notifcation requires we send lists of successes and
            // failures broken down by category.
            // The categories are:
            //
            // 1) addresses successfully processed.
            // 2) addresses deemed valid, but had a processing failure that
            // prevented sending.
            // 3) addressed deemed invalid (basically all other processing
            // failures).
            ArrayList sentAddresses = new ArrayList();
            ArrayList unsentAddresses = new ArrayList();
            ArrayList invalidAddresses = new ArrayList();

            // Now we add a MAIL TO record for each recipient. At this point, we
            // just collect
            for (int i = 0; i < addresses.length; i++) {
                InternetAddress target = (InternetAddress) addresses[i];

                // write out the record now.
                SendStatus status = connection.sendRcptTo(target, dsn);
                stats[i] = status;

                switch (status.getStatus()) {
                    // successfully sent
                    case SendStatus.SUCCESS:
                        sentAddresses.add(target);
                        break;

                    // we have an invalid address of some sort, or a general sending
                    // error (which we'll
                    // interpret as due to an invalid address.
                    case SendStatus.INVALID_ADDRESS:
                    case SendStatus.GENERAL_ERROR:
                        sendFailure = true;
                        invalidAddresses.add(target);
                        break;

                    // good address, but this was a send failure.
                    case SendStatus.SEND_FAILURE:
                        sendFailure = true;
                        unsentAddresses.add(target);
                        break;
                    }
            }

            // if we had a send failure, then we need to check if we allow
            // partial sends. If not allowed,
            // we abort the send operation now.
            if (sendFailure) {
                // if we're not allowing partial successes or we've failed on
                // all of the addresses, it's
                // time to abort.
                if (!partialSends || sentAddresses.isEmpty()) {
                    // we send along the valid and invalid address lists on the
                    // notifications and
                    // exceptions.
                    // however, since we're aborting the entire send, the
                    // successes need to become
                    // members of the failure list.
                    unsentAddresses.addAll(sentAddresses);

                    // this one is empty.
                    sent = new Address[0];
                    unsent = (Address[]) unsentAddresses.toArray(new Address[0]);
                    invalid = (Address[]) invalidAddresses.toArray(new Address[0]);

                    // go reset our connection so we can process additional
                    // sends.
                    connection.resetConnection();

                    // get a list of chained exceptions for all of the failures.
                    MessagingException failures = generateExceptionChain(stats, false);

                    // now send an "uber-exception" to indicate the failure.
                    throw new SMTPSendFailedException("MAIL TO", 0, "Invalid Address", failures, sent, unsent, invalid);
                }
            }

            try {
                // try to send the data
                connection.sendData((MimeMessage)message);
            } catch (MessagingException e) {
                // If there's an error at this point, this is a complete
                // delivery failure.
                // we send along the valid and invalid address lists on the
                // notifications and
                // exceptions.
                // however, since we're aborting the entire send, the successes
                // need to become
                // members of the failure list.
                unsentAddresses.addAll(sentAddresses);

                // this one is empty.
                sent = new Address[0];
                unsent = (Address[]) unsentAddresses.toArray(new Address[0]);
                invalid = (Address[]) invalidAddresses.toArray(new Address[0]);
                // notify of the error.
                notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED, sent, unsent, invalid, message);
                // send a send failure exception.
                throw new SMTPSendFailedException("DATA", 0, "Send failure", e, sent, unsent, invalid);
            }

            // create our lists for notification and exception reporting from
            // this point on.
            sent = (Address[]) sentAddresses.toArray(new Address[0]);
            unsent = (Address[]) unsentAddresses.toArray(new Address[0]);
            invalid = (Address[]) invalidAddresses.toArray(new Address[0]);

            // if sendFailure is true, we had an error during the address phase,
            // but we had permission to
            // process this as a partial send operation. Now that the data has
            // been sent ok, it's time to
            // report the partial failure.
            if (sendFailure) {
                // notify our listeners of the partial delivery.
                notifyTransportListeners(TransportEvent.MESSAGE_PARTIALLY_DELIVERED, sent, unsent, invalid, message);

                // get a list of chained exceptions for all of the failures (and
                // the successes, if reportSuccess has been
                // turned on).
                MessagingException failures = generateExceptionChain(stats, reportSuccess);

                // now send an "uber-exception" to indicate the failure.
                throw new SMTPSendFailedException("MAIL TO", 0, "Invalid Address", failures, sent, unsent, invalid);
            }

            // notify our listeners of successful delivery.
            notifyTransportListeners(TransportEvent.MESSAGE_DELIVERED, sent, unsent, invalid, message);

            // we've not had any failures, but we've been asked to report
            // success as an exception. Do
            // this now.
            if (reportSuccess) {
                // generate the chain of success exceptions (we already know
                // there are no failure ones to report).
                MessagingException successes = generateExceptionChain(stats, reportSuccess);
                if (successes != null) {
                    throw successes;
                }
            }
        } catch (SMTPSendFailedException e) {
            // if this is a send failure, we've already handled
            // notifications....just rethrow it.
            throw e;
        } catch (MessagingException e) {
            // notify of the error.
            notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED, sent, unsent, invalid, message);
            throw e;
        }
    }