FileDocCategorySizeDatePackage
MailMessage.javaAPI DocApache Ant 1.7014955Wed Dec 13 06:16:20 GMT 2006org.apache.tools.mail

MailMessage

public class MailMessage extends Object
A class to help send SMTP email. This class is an improvement on the sun.net.smtp.SmtpClient class found in the JDK. This version has extra functionality, and can be used with JVMs that did not extend from the JDK. It's not as robust as the JavaMail Standard Extension classes, but it's easier to use and easier to install, and has an Open Source license.

It can be used like this:

String mailhost = "localhost"; // or another mail host
String from = "Mail Message Servlet <MailMessage@server.com>";
String to = "to@you.com";
String cc1 = "cc1@you.com";
String cc2 = "cc2@you.com";
String bcc = "bcc@you.com";
 
MailMessage msg = new MailMessage(mailhost);
msg.setPort(25);
msg.from(from);
msg.to(to);
msg.cc(cc1);
msg.cc(cc2);
msg.bcc(bcc);
msg.setSubject("Test subject");
PrintStream out = msg.getPrintStream();
 
Enumeration enum = req.getParameterNames();
while (enum.hasMoreElements()) {
String name = (String)enum.nextElement();
String value = req.getParameter(name);
out.println(name + " = " + value);
}
 
msg.sendAndClose();

Be sure to set the from address, then set the recepient addresses, then set the subject and other headers, then get the PrintStream, then write the message, and finally send and close. The class does minimal error checking internally; it counts on the mail host to complain if there's any malformatted input or out of order execution.

An attachment mechanism based on RFC 1521 could be implemented on top of this class. In the meanwhile, JavaMail is the best solution for sending email with attachments.

Still to do:

  • Figure out how to close the connection in case of error
version
1.1, 2000/03/19, added angle brackets to address, helps some servers version 1.0, 1999/12/29

Fields Summary
public static final String
DEFAULT_HOST
default mailhost
public static final int
DEFAULT_PORT
default port for SMTP: 25
private String
host
host name for the mail server
private int
port
host port for the mail server
private String
from
sender email address
private Vector
replyto
list of email addresses to reply to
private Vector
to
list of email addresses to send to
private Vector
cc
list of email addresses to cc to
private Vector
headersKeys
headers to send in the mail
private Vector
headersValues
private MailPrintStream
out
private SmtpResponseReader
in
private Socket
socket
private static final int
OK_READY
private static final int
OK_HELO
private static final int
OK_FROM
private static final int
OK_RCPT_1
private static final int
OK_RCPT_2
private static final int
OK_DATA
private static final int
OK_DOT
private static final int
OK_QUIT
Constructors Summary
public MailMessage()
Constructs a new MailMessage to send an email. Use localhost as the mail server with port 25.

exception
IOException if there's any problem contacting the mail server


                                
      
    this(DEFAULT_HOST, DEFAULT_PORT);
  
public MailMessage(String host)
Constructs a new MailMessage to send an email. Use the given host as the mail server with port 25.

param
host the mail server to use
exception
IOException if there's any problem contacting the mail server

    this(host, DEFAULT_PORT);
  
public MailMessage(String host, int port)
Constructs a new MailMessage to send an email. Use the given host and port as the mail server.

param
host the mail server to use
param
port the port to connect to
exception
IOException if there's any problem contacting the mail server

    this.port = port;
    this.host = host;
    replyto = new Vector();
    to = new Vector();
    cc = new Vector();
    headersKeys = new Vector();
    headersValues = new Vector();
    connect();
    sendHelo();
  
Methods Summary
public voidbcc(java.lang.String bcc)
Sets the bcc address. Does NOT set any header since it's a *blind* copy. This method may be called multiple times.

param
bcc the bcc address
exception
IOException if there's any problem reported by the mail server

    sendRcpt(bcc);
    // No need to keep track of Bcc'd addresses
  
public voidcc(java.lang.String cc)
Sets the cc address. Also sets the "Cc" header. This method may be called multiple times.

param
cc the cc address
exception
IOException if there's any problem reported by the mail server

    sendRcpt(cc);
    this.cc.addElement(cc);
  
voidconnect()

    socket = new Socket(host, port);
    out = new MailPrintStream(
          new BufferedOutputStream(
          socket.getOutputStream()));
    in = new SmtpResponseReader(socket.getInputStream());
    getReady();
  
voiddisconnect()

        if (out != null) {
            out.close();
        }
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                // ignore
            }
        }
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                // ignore
            }
        }
    
voidflushHeaders()

    // RFC 822 s4.1:
    //   "Header fields are NOT required to occur in any particular order,
    //    except that the message body MUST occur AFTER the headers"
    // (the same section specifies a reccommended order, which we ignore)
   for (int i = 0; i < headersKeys.size(); i++) {
      String name = (String) headersKeys.elementAt(i);
      String value = (String) headersValues.elementAt(i);
      out.println(name + ": " + value);
    }
    out.println();
    out.flush();
  
public voidfrom(java.lang.String from)
Sets the from address. Also sets the "From" header. This method should be called only once.

param
from the from address
exception
IOException if there's any problem reported by the mail server

        sendFrom(from);
        this.from = from;
    
public java.io.PrintStreamgetPrintStream()
Returns a PrintStream that can be used to write the body of the message. A stream is used since email bodies are byte-oriented. A writer can be wrapped on top if necessary for internationalization. This is actually done in Message.java

return
a printstream containing the data and the headers of the email
exception
IOException if there's any problem reported by the mail server
see
org.apache.tools.ant.taskdefs.email.Message

    setFromHeader();
    setReplyToHeader();
    setToHeader();
    setCcHeader();
    setHeader("X-Mailer", "org.apache.tools.mail.MailMessage (ant.apache.org)");
    sendData();
    flushHeaders();
    return out;
  
voidgetReady()

    String response = in.getResponse();
    int[] ok = {OK_READY};
    if (!isResponseOK(response, ok)) {
      throw new IOException(
        "Didn't get introduction from server: " + response);
    }
  
booleanisResponseOK(java.lang.String response, int[] ok)

    // Check that the response is one of the valid codes
    for (int i = 0; i < ok.length; i++) {
      if (response.startsWith("" + ok[i])) {
        return true;
      }
    }
    return false;
  
public voidreplyto(java.lang.String rto)
Sets the replyto address This method may be called multiple times.

param
rto the replyto address

      this.replyto.addElement(rto);
    
static java.lang.StringsanitizeAddress(java.lang.String s)

    int paramDepth = 0;
    int start = 0;
    int end = 0;
    int len = s.length();

    for (int i = 0; i < len; i++) {
      char c = s.charAt(i);
      if (c == '(") {
        paramDepth++;
        if (start == 0) {
          end = i;  // support "address (name)"
        }
      } else if (c == ')") {
        paramDepth--;
        if (end == 0) {
          start = i + 1;  // support "(name) address"
        }
      } else if (paramDepth == 0 && c == '<") {
        start = i + 1;
      } else if (paramDepth == 0 && c == '>") {
        end = i;
      }
    }

    if (end == 0) {
      end = len;
    }

    return s.substring(start, end);
  
voidsend(java.lang.String msg, int[] ok)

        out.rawPrint(msg + "\r\n");  // raw supports <CRLF>.<CRLF>
        String response = in.getResponse();
        if (!isResponseOK(response, ok)) {
            throw new IOException("Unexpected reply to command: "
                                  + msg + ": " + response);
        }
    
public voidsendAndClose()
Sends the message and closes the connection to the server. The MailMessage object cannot be reused.

exception
IOException if there's any problem reported by the mail server

      try {
          sendDot();
          sendQuit();
      } finally {
          disconnect();
      }
  
voidsendData()

    int[] ok = {OK_DATA};
    send("DATA", ok);
  
voidsendDot()

    int[] ok = {OK_DOT};
    send("\r\n.", ok);  // make sure dot is on new line
  
voidsendFrom(java.lang.String from)

    int[] ok = {OK_FROM};
    send("MAIL FROM: " + "<" + sanitizeAddress(from) + ">", ok);
  
voidsendHelo()

    String local = InetAddress.getLocalHost().getHostName();
    int[] ok = {OK_HELO};
    send("HELO " + local, ok);
  
voidsendQuit()

        int[] ok = {OK_QUIT};
        try {
            send("QUIT", ok);
        } catch (IOException e) {
            throw new ErrorInQuitException(e);
        }
    
voidsendRcpt(java.lang.String rcpt)

    int[] ok = {OK_RCPT_1, OK_RCPT_2};
    send("RCPT TO: " + "<" + sanitizeAddress(rcpt) + ">", ok);
  
voidsetCcHeader()

    if (!cc.isEmpty()) {
      setHeader("Cc", vectorToList(cc));
    }
  
voidsetFromHeader()

    setHeader("From", from);
  
public voidsetHeader(java.lang.String name, java.lang.String value)
Sets the named header to the given value. RFC 822 provides the rules for what text may constitute a header name and value.

param
name name of the header
param
value contents of the header

    // Blindly trust the user doesn't set any invalid headers
    headersKeys.add(name);
    headersValues.add(value);
  
public voidsetPort(int port)
Set the port to connect to the SMTP host.

param
port the port to use for connection.
see
#DEFAULT_PORT

        this.port = port;
    
voidsetReplyToHeader()

    if (!replyto.isEmpty()) {
      setHeader("Reply-To", vectorToList(replyto));
    }
  
public voidsetSubject(java.lang.String subj)
Sets the subject of the mail message. Actually sets the "Subject" header.

param
subj the subject of the mail message

    setHeader("Subject", subj);
  
voidsetToHeader()

    if (!to.isEmpty()) {
      setHeader("To", vectorToList(to));
    }
  
public voidto(java.lang.String to)
Sets the to address. Also sets the "To" header. This method may be called multiple times.

param
to the to address
exception
IOException if there's any problem reported by the mail server

    sendRcpt(to);
    this.to.addElement(to);
  
java.lang.StringvectorToList(java.util.Vector v)

    StringBuffer buf = new StringBuffer();
    Enumeration e = v.elements();
    while (e.hasMoreElements()) {
      buf.append(e.nextElement());
      if (e.hasMoreElements()) {
        buf.append(", ");
      }
    }
    return buf.toString();