Package org.apache.geronimo.mail.smtp

Source Code of org.apache.geronimo.mail.smtp.SMTPTransport$SendStatus

/**
*
* Copyright 2003-2005 The Apache Software Foundation
*
*  Licensed 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 org.apache.geronimo.mail.smtp;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeBodyPart;

import org.apache.geronimo.mail.AbstractTransport;

import java.net.Socket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Date;

/**
*  Simple implementation of SMTP transport.  Just does plain RFC821-ish
*  delivery.
*
*  Supported properties :
*
<ul>
<li> mail.host : to set the server to deliver to.  Default = localhost</li>
<li> mail.smtp.port : to set the port.  Default = 25</li>
<li> mail.smtp.locahost : name to use for HELO/EHLO - default getHostName()</li>
</ul>
*
*  There is no way to indicate failure for a given recipient (it's possible to have a
*  recipient address rejected).  The sun impl throws exceptions even if others successful),
*  but maybe we do a different way...
*
*  TODO : lots.  ESMTP, user/pass, indicate failure, etc...
*
* @version $Rev: 158693 $ $Date: 2005-03-22 15:53:53 -0700 (Tue, 22 Mar 2005) $
*/
public class SMTPTransport extends AbstractTransport {

    /**
     *  constants for EOL termination
     */
    private static final char CR = 0x0D;
    private static final char LF = 0x0A;

    /**
     *  property key for SMTP server to talk to
     */
    private static final String MAIL_HOST = "mail.host";
    private static final String MAIL_SMTP_LOCALHOST = "mail.smtp.localhost";
    private static final String MAIL_SMTP_PORT = "mail.smtp.port";

    private static final int MIN_MILLIS = 1000 * 60;
    private static final String DEFAULT_MAIL_HOST = "localhost";
    private static final int DEFAULT_MAIL_SMTP_PORT = 25;

    /**
     * @param session
     * @param name
     */
    public SMTPTransport(Session session, URLName name) {
        super(session, name);
    }

    /* (non-Javadoc)
     * @see javax.mail.Transport#sendMessage(javax.mail.Message, javax.mail.Address[])
     */
    public void sendMessage(Message message, Address[] addresses)
        throws MessagingException {

        /*
         * do it and ignore the return
         */
        sendMessage(addresses, message);
    }

    public SendStatus[] sendMessage(Address[] addresses, Message message)
        throws MessagingException {

        /*
         * don't bother me w/ null messages or no addreses
         */

        if (message == null ) {
            throw new MessagingException("Null message");
        }

        if (addresses == null || addresses.length == 0) {
            throw new MessagingException("Null or empty address array");
        }


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

        try {

            /*
             * create socket and connect to server.
             */

            Socket s = getConnectedSocket();

            /*
             *  receive welcoming message
             */
            if (!getWelcome(s)) {
                throw new MessagingException("Error in getting welcome msg");
            }

            /*
             * say hello
             */
            if (!sendHelo(s)) {
                throw new MessagingException("Error in saying HELO to server");
            }

            /*
             * send sender
             */
            if (!sendMailFrom(s, message.getFrom())) {
                throw new MessagingException("Error in setting the MAIL FROM");
            }

            /*
             * send recipients.  Only send if not null or "", and just ignore
             * (but log) any errors
             */

            for (int i=0; i < addresses.length; i++) {
                String to = addresses[i].toString();

                int status = SendStatus.SUCCESS;

                if (to != null && !"".equals(to)) {
                    if (!sendRcptTo(s, to)) {

                        // this means it didn't like our recipient.  I say we keep
                        // going

                        if (this.session.getDebug()) {
                            this.session.getDebugOut().println("ERROR setting recipient " + to);
                        }

                        status = SendStatus.FAIL;
                    }
                }
                else {
                    status = SendStatus.FAIL;
                }

                stat[i] = new SendStatus(status, to);
            }

            /*
             * send data
             */
            if (!sendData(s, message)) {
                throw new MessagingException("Error sending data");
            }

            /*
             * say goodbye
             */

            sendQuit(s);

            try {
                s.close();
            }
            catch (IOException e) {
                //
                // TODO - should we just eat this?  We have delivered the msg...
                //
                e.printStackTrace();
            }
        }
        catch (SMTPTransportException e) {
            throw new MessagingException("error", e);
        }
        catch (MalformedSMTPReplyException e) {
            throw new MessagingException("error", e);
        }

        return stat;
    }

    /**
     * Sends the data in the message down the socket.  This presumes the
     * server is in the right place and ready for getting the DATA message
     * and the data right place in the sequence
     *
     * @param s
     * @param msg
     * @return
     * @throws SMTPTransportException
     * @throws MalformedSMTPReplyException
     */
    protected boolean sendData(Socket s, Message msg)
        throws SMTPTransportException, MalformedSMTPReplyException {

        if (msg == null) {
            throw new SMTPTransportException("invalid message");
        }

        /*
         * send the DATA command
         */
        sendLine(s, "DATA");

        SMTPReply line = new SMTPReply(receiveLine(s, 5 * MIN_MILLIS));

        if (this.session.getDebug()) {
            this.session.getDebugOut().println(line);
        }

        if (line.isError()) {
            return false;
        }

        /*
         * now the data...  I could look at the type, but
         */

        try {
            OutputStream os = s.getOutputStream();

            // todo - be smarter here and send in chunks to let the other side
            // digest easier.  There's a 3 min recommended timeout per chunk...

            msg.writeTo(os);
            os.flush();
        }
        catch (IOException e) {
            throw new SMTPTransportException(e);
        }
        catch(MessagingException e) {
            throw new SMTPTransportException(e);
        }

        /*
         * now to finish
         */
        sendLine(s, "");
        sendLine(s, ".");

        line = new SMTPReply(receiveLine(s, 10 * MIN_MILLIS));

        return !line.isError();
    }

    /**
     *  Sends the QUIT message and receieves the response
     *
     * @param s
     * @return
     * @throws SMTPTransportException
     * @throws MalformedSMTPReplyException
     */
    protected boolean sendQuit(Socket s)
        throws SMTPTransportException, MalformedSMTPReplyException {

        sendLine(s, "QUIT");

        SMTPReply line = new SMTPReply(receiveLine(s, 5 * MIN_MILLIS));

        return !line.isError();
    }

    /**
     * Sets a receiver address for the current message
     *
     * @param s
     * @param addr
     * @return
     * @throws SMTPTransportException
     * @throws MalformedSMTPReplyException
     */
    protected boolean sendRcptTo(Socket s, String addr)
        throws SMTPTransportException, MalformedSMTPReplyException {

        if (addr == null || "".equals(addr)) {
            throw new SMTPTransportException("invalid address");
        }

        String msg = "RCPT TO: " + addr;

        sendLine(s, msg);

        SMTPReply line = new SMTPReply(receiveLine(s, 5 * MIN_MILLIS));

        return !line.isError();
    }

    /**
     * Set the sender for this mail.
     * @param s
     * @param from
     * @return
     * @throws SMTPTransportException
     * @throws MalformedSMTPReplyException
     */
    protected boolean sendMailFrom(Socket s, Address[] from)
            throws SMTPTransportException, MalformedSMTPReplyException {

        if (from == null || from.length == 0) {
            throw new SMTPTransportException("no FROM address");
        }

        /*
         * TODO - what do we do w/ more than one from???
         */

        String msg = "MAIL FROM: " + from[0].toString();

        sendLine(s, msg);

        SMTPReply line = new SMTPReply(receiveLine(s, 5 * MIN_MILLIS));

        return !line.isError();
    }

    /**
     *  Sends the initiating "HELO" message.  We're keeping it simple, just
     * identifying ourselves as we dont' require service extensions, and
     *  want to keep it simple for now
     *
     * @param s socket we are talking on.  It's assumed to be open and in
     *    right state for this message
     * @return
     * @throws SMTPTransportException
     * @throws MalformedSMTPReplyException
     */
    protected boolean sendHelo(Socket s)
        throws SMTPTransportException, MalformedSMTPReplyException {

        String fqdm = null;

        try {
            fqdm = InetAddress.getLocalHost().getHostName();
        }
        catch (UnknownHostException e) {
            // fine, we're misconfigured - ignore
        }

        if (fqdm == null) {
            fqdm = session.getProperty(MAIL_SMTP_LOCALHOST);
        }

        if (fqdm == null) {
            throw new SMTPTransportException("Can't get local hostname. " +
                    " Please correctly configure JDK/DNS or set mail.smtp.localhost");
        }

        sendLine(s, "HELO " + fqdm);

        SMTPReply line = new SMTPReply(receiveLine(s, 5 * MIN_MILLIS));

        return !line.isError();
    }

    /**
     *  Get the servers welcome blob from the wire....
     *
     * @param s
     * @return
     * @throws SMTPTransportException
     * @throws MalformedSMTPReplyException
     */
    protected boolean getWelcome(Socket s)
        throws SMTPTransportException, MalformedSMTPReplyException {

        SMTPReply line = new SMTPReply(receiveLine(s, 5 * MIN_MILLIS));

        return !line.isError();
    }

    /**
     *  Sends a  message down the socket and terminates with the
     *  appropriate CRLF
     *
     * @param s
     * @param data
     * @throws SMTPTransportException
     */
    protected void sendLine(Socket s, String data)
        throws SMTPTransportException {

        if (s == null) {
            throw new SMTPTransportException("bonehead...");
        }

        if (!s.isConnected()) {
            throw new SMTPTransportException("no connection");
        }

        try {
            OutputStream out = s.getOutputStream();

            out.write(data.getBytes());
            out.write(CR);
            out.write(LF);
            out.flush();

            if (this.session.getDebug()) {
                this.session.getDebugOut().println("sent: " + data);
            }
        }
        catch (IOException e) {
            throw new SMTPTransportException(e);
        }
    }

    /**
     *  Receives one line from the server.  A line is a sequence of bytes
     *  terminated by a CRLF
     *
     * @param s socket to receive from
     * @return the line from the server as String
     */
    protected String receiveLine(Socket s, int delayMillis)
        throws SMTPTransportException {

        if (s == null) {
            throw new SMTPTransportException("bonehead...");
        }

        if (!s.isConnected()) {
            throw new SMTPTransportException("no connection");
        }

        int timeout = 0;

        try {

            /*
             * for now, read byte for byte, looking for a CRLF
             */

            timeout = s.getSoTimeout();

            s.setSoTimeout(delayMillis);

            InputStream is = s.getInputStream();

            StringBuffer buff = new StringBuffer();
           
            int c;
            boolean crFound = false, lfFound = false;

            while((c = is.read()) != -&& crFound == false && lfFound == false) {
                buff.append((char) c);

                if (c == CR) {
                    crFound = true;
                }
                if (c == LF) {
                    lfFound = true;
                }
            }

            if (this.session.getDebug()) {
                this.session.getDebugOut().println("received : " + buff.toString());
            }

            return buff.toString();
        }
        catch (SocketException e) {
            throw new SMTPTransportException(e);
        }
        catch (IOException e) {
            throw new SMTPTransportException(e);
        }
        finally {
            try {
                s.setSoTimeout(timeout);
            }
            catch(SocketException e) {
                // ignore - was just trying to do the decent thing...
            }
        }
    }


    /**
     *  Creates and returns a connected socket
     *
     * @return
     * @throws MessagingException
     */
    protected Socket getConnectedSocket()
        throws MessagingException {

        Socket s = new Socket();

        String mail_host = this.session.getProperty(MAIL_HOST);

        if (mail_host == null || "".equals(mail_host)) {
            mail_host = DEFAULT_MAIL_HOST;
        }

        String portString = this.session.getProperty(MAIL_SMTP_PORT);

        int port = DEFAULT_MAIL_SMTP_PORT;

        if (portString != null && !"".equals(portString)) {

            try {
                port = Integer.parseInt(portString);
            }
            catch (NumberFormatException e) {
                // ignore - we don't care, leave as default
            }
        }

        try {

            if (this.session.getDebug()) {
                this.session.getDebugOut().println("connecting to " + mail_host);
            }

            s.connect(new InetSocketAddress(mail_host, port));

            if (this.session.getDebug()) {
                this.session.getDebugOut().println("connected to " + mail_host);
            }
        }
        catch (IOException e) {

            if (this.session.getDebug()) {
                this.session.getDebugOut().println("error connecting to " + mail_host);
            }

            throw new MessagingException("Error connecting to " + mail_host, e);
        }

        return s;
    }

    public static void main(String[] args)
        throws Exception {

        Properties props = new Properties();
        props.setProperty("mail.host", "mail.optonline.net");

        Session session = Session.getDefaultInstance(props);

        session.setDebug(true);

        SMTPTransport t = new SMTPTransport(session, null);

        MimeMessage msg = new MimeMessage(session);

        MimeMultipart mmpt = new MimeMultipart();
        MimeBodyPart b1 = new MimeBodyPart();
        b1.setContent("body 1", "text/plain");

        mmpt.addBodyPart(b1);

        b1 = new MimeBodyPart();
        b1.setContent("body2", "text/plain");
        mmpt.addBodyPart(b1);

        Address[] list = new Address[1];
        list[0] new InternetAddress("geirm@optonline.net");
//        list[1] =  new InternetAddress("jeremy@boynes.com");

        msg.setSubject("From SMTPTransport : this is the subject");
        msg.setFrom(new InternetAddress("geirm@optonline.net"));
//        msg.setContent("This is the content (via SMTPTransport)", "text/plain");
        msg.setRecipients(Message.RecipientType.TO, list);
        msg.setContent(mmpt);

        msg.setSentDate(new Date());

        t.sendMessage(msg, list);
    }

    /**
     *  Simple holder class for the address/send status duple, as we can
     *  have mixed success for a set of addresses and a message
     *
     */
    public class SendStatus {
        public final static int SUCCESS = 0;
        public final static int FAIL = 1;
        final int status;
        final String address;

        public SendStatus(int s, String a) {
            this.status = s;
            this.address = a;
        }

        public int getStatus() {
            return this.status;
        }

        public String getAddress() {
            return this.address;
        }
    }
}
TOP

Related Classes of org.apache.geronimo.mail.smtp.SMTPTransport$SendStatus

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.