HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

This column looks at the construction of an Intranet-based contact manager known as Informer. In previous articles, I have looked at the building blocks of Informer, and how easy it was to use Symantec's dbAnywhere package to provide all of the database connectivity. For those of you following this column, you will have noted that very little actual code has been produced manually. This is due to Visual Café's excellent drag and drop interface. I could attempt to continue the complete construction of Informer without having to produce a single line of code myself, but that would defeat the purpose of this column: trying to teach Java. And besides that, it would be boring!

So, let's build some features onto our Informer the good old fashioned way: coding. I spend a good part of my day answering other people's problems at both the N-ARY Java forums and Usenet's comp.lang.java.programmer forums, and one of the most common questions that keeps coming up is "How do I send an e-mail from Java?". E-mail functionality from Informer would be a very handy feature to have, so let's kill a couple of birds with one stone and present a self-contained class that may be used to send e-mails.

SMTP
One of the most popular and widely used protocols for sending e-mail over the TCP/IP networks is the Simple Message Transport Protocol (SMTP). You may have noticed this field in your e-mail software where it asks for outgoing host. SMTP hosts come as part of the standard operating system on the majority of UNIX's and for this reason it has widespread acceptance.

A relatively unknown fact about outgoing e-mail is that you can use any SMTP host on the network to deliver your e-mail. Think of an SMTP host like a mailbox sitting on a street corner. You simply write your letter, put an address on it and then place it in the mailbox. At this point, the postal service comes along and collects all the mail and then takes it for processing so it may be delivered. Internet e-mail isn't a million miles away from this analogy. You still write your letter, and you still address it, albeit with an e-mail address ([email protected], for example), and then you take it to a mailbox for delivery. An SMTP host is acting in exactly the same manner as the mailbox on the street corner. As long as the message is correctly formatted, it will get delivered.

Although we are free to choose any SMTP host in the world, we are restricted if we are sending e-mail from within a Java applet. then, due to security restrictions we have to ensure that an SMTP host is located on the server where the applet originated. This isn't too much of a concern if the applet is being downloaded from a Web server on a UNIX box. If you are going to send an e-mail from a Java application or Java servlet, then this isn't an issue.

SMTP Communication
Any of you who have written client software to talk to other TCP servers will be familiar with the mechanism required to communicate with SMTP. Like other TCP servers - NEWS, FTP, POP - SMTP uses command strings formatted as ASCII lines and terminated with the carriage return/new line (\r\n) sequence. Depending on the command, the server responds with a status code indicating the success of the previous operation. This status code is formatted as a three-digit number followed by an optional message.

Sending e-mail via an SMTP server can be broken down into three distinct stages:

  1. Establishing a connection to the server
  2. Sending e-mails
  3. Disconnecting from the server
Creating a connection
Creating a connection to an SMTP host involves opening up the network connection and then communicating to the host that we exist. It's at this point that most people new to Java and programming start shaking. Traditionally, network programming has never been easy; anyone who has tried to code an application for Windows using Winsock will testify to that. Java has made network programming child's play.

Connecting to any TCP server can be achieved using the Socket class from the java.net package. Once a new class instance has been created, an input and an output stream is retrieved and communication can begin. For example, look at Listing 1.

Notice how easy it is to create a connection to the host. If for some reason the connection can't be created, then the Socket class throws an exception. This hasn't been shown in the sample code but you will find it in the final listing. Having created the connection, we create two streams, Buffered Reader and DataOutputStream, to handle all the communication.

All communication is formatted as ASCII text; therefore, the class BufferedReader (from JDK1.1) gives us a clean function for reading lines back from the server using the readLine() method. Conversely, sending lines out can be done easily through the DataOutputStream class using the writeBytes(...) method.

Having created a connection, the first thing we will expect from the server is a line that identifies itself. For example:

220 mail.n-ary.com ESMTP Sendmail 8.7.5/8.7.3; Sun, 21 Sep 1997 12:42:00 GMT

The first three digits signify the status code. If we receive a 220 response, we can assume the server is ready and waiting for us. Listing 2 shows how we sit and listen for this status code. We use the indexOf(...) method from the String class, which returns an integer index of the position of the string specified. If the string doesn't exist, then -1 is returned.

Once we receive this, we can send the HELO command which tells the server which domain we are calling from. Again, successful execution of this command will result in a 250 status code being sent back from the server.

Now we are ready to format and send e-mails.

Sending an e-mail
An e-mail has a number of properties but for this example we will assume four of them: originator, recipient, subject and body. This information is sent to the server in a series of short messages.

Sending the originator and recipient of the e-mail is performed using the MAIL FROM: and RCPT TO: commands, formatted with the e-mail address appearing on the same line inside angular brackets (<>). For example, Listing 4 shows sending the server these two commands, and waiting for the respective status codes.

Incidentally, although we have given the functionality here, you can send the same e-mail to multiple users by sending the server repeated RCPT TO: commands. This is particularly useful if you are operating with mailing lists; therefore, you don't need to send the e-mail body x number of times to the server.

Sending the e-mail body to the server is very easy. First, send a DATA command; when the server responds with a 354 status code, you can send the body to the server as a series of lines, terminated with a single dot (.) on a single line. Listing 5 illustrates this.

Notice anything? Before sending the e-mail body, we resent the e-mail originator and sent the Subject of the e-mail inside the body. This information is optional and doesn't need to be present for successful delivery. Document RFC822, the blueprints of the Internet, details the exact format the body text can take. For example, another field that can be added is the mime type of the data. Using this, you can send attachments, and even e-mail formatted as HTML text, that is now becoming a common place in most e-mail clients.

Closing a Connection
After sending the e-mails, connection to the server must be terminated. This is a two-fold process. We need to send the QUIT command to the server and then close the socket connection. No status code is sent from the server, so as soon as we have sent the command we can safely close the socket using the close() method. That's it. Communication finished.

Using sendEmail
We can package the above functionality into a separate class, sendEmail, and use this to send e-mails. I have included the complete listing for this class with this article (see Listing 7). Using the class is very easy. First create an instance of sendEmail, and then call the send(...) method. Listing 6 shows this.

Summary
In our continuing development of Informer, we took a break from the drag and drop building and looked at developing our own class to send e-mail. Although provided as one of the classes in Symantec's library, a custom-built class allows for a greater portability across many Java technologies, for example servlets and beans.

With the e-mail functionality built into Informer, we can look at building a proper user interface to this feature in the next article, while providing some extra features.

About the Author
Alan Williamson is on the Board of Directors at N-ARY Limited, a UK-based Java software company specializing in Java/JDBC/Servlets. He has recently completed his second book, focusing purely on Java Servlets, with his first book looking at using Java/JDBC/Servlets to provide a very efficient database solution.

	

Listing 1.
 
Socket smtpHost; 
BufferedReader In; 
DataOutputStream Out; 

smtpHost = new Socket( “mail2.n-ary.com”, 25 ); 
Out  = new DataOutputStream( smtpHost.getOutputStream() ); 
In  = new BufferedReader( new InputStreamReader( smtpHost.getInputStream() )); 

Listing 2.
 
String LineIn = In.readLine(); 
if ( LineIn.indexOf("220") == -1 ) throw new Exception(“Bad Server”); 

Listing 3.
 
Out.writeBytes( "HELO n-ary.com\r\n" ); 
LineIn = In.readLine(); 
if ( LineIn.indexOf("250") == -1 ) throw new Exception(“Bad return”); 

Listing 4.
 
//- Set the FROM 
Out.writeBytes( "MAIL FROM:<" + _from + ">\r\n" ); 
LineIn = In.readLine(); 
if ( LineIn.indexOf("250")==-1 ) throw new Exception("Bad MAIL FROM:"); 

//- Set the TO field 
Out.writeBytes( "RCPT TO:<" + _to + ">\r\n" ); 
LineIn = In.readLine(); 
if ( LineIn.indexOf("250")==-1 ) throw new Exception("Bad RCPT TO:"); 

Listing 5.
 
//- Set the DATA field 
Out.writeBytes( "DATA\r\n" ); 
LineIn = In.readLine(); 
if ( LineIn.indexOf("354")==-1 ) throw new Exception("Bad DATA"); 
Out.writeBytes( "From: " +_to + "\r\n” ); 
Out.writeBytes( “Subject: " + _subject + "\r\n"); 

Out.writeBytes( _body ); 
Out.writeBytes( "\r\n.\r\n" ); 

Listing 6.
 
//- Set the DATA field 
sendEmail S; 

S = new sendEmail( "mail2.n-ary.com" ); 
S.send( "[email protected]", "[email protected]", "Hello", "Hello Ceri, how are you?" ); 
S.send( "[email protected]", "[email protected]", "Hello", "Hey Frode, hows it going." ); 
S.close(); 

Listing 7.
 
import java.net.*; 
import java.io.*; 

class sendEmail extends java.lang.Object 
{ 
 private Socket smtpHost; 
 private BufferedReader In; 
 private DataOutputStream Out; 

 public sendEmail(String _Host) 
 { 
  try 
  { 
   smtpHost = new Socket( _Host, 25 ); 
   Out = new DataOutputStream( smtpHost.getOutputStream() ); 
   In = new BufferedReader( new InputStreamReader(smtpHost.getInputStream()) ); 

   //- Read Welcome message from server 
   String LineIn = In.readLine(); 
   if ( LineIn.indexOf("220")==-1 ) throw new Exception("Bad Server"); 

   //- Introduce ourselves to the server 
   Out.writeBytes( "HELO n-ary.com\r\n" ); 
   LineIn = In.readLine(); 
   if ( LineIn.indexOf("250")==-1 ) throw new Exception(); 
  } 
  catch( Exception E ) 
  { 
   smtpHost = null; 
  } 
 } 

 public boolean send( String _to, String _from, String _subject, String _body ) 
 { 
  //- Send One Email 
  if ( smtpHost == null ) return false; 

  try{ 
   String LineIn; 

   //- Set the FROM 
   Out.writeBytes( "MAIL FROM:<" + _from + ">\r\n" ); 
   LineIn = In.readLine(); 
   if ( LineIn.indexOf("250")==-1 ) throw new Exception("Bad MAIL FROM:"); 

   //- Set the TO field 
   Out.writeBytes( "RCPT TO:<" + _to + ">\r\n" ); 
   LineIn = In.readLine(); 
   if ( LineIn.indexOf("250")==-1 ) throw new Exception("Bad RCPT TO:"); 

   //- Set the DATA field 
   Out.writeBytes( "DATA\r\n" ); 
   LineIn = In.readLine(); 
   if ( LineIn.indexOf("354")==-1 ) throw new Exception("Bad DATA"); 
   Out.writeBytes( "From: " +_to + "\r\n” ); 
   Out.writeBytes( “Subject: " + _subject + "\r\n"); 

   Out.writeBytes( _body ); 
   Out.writeBytes( "\r\n.\r\n" ); 

   LineIn = In.readLine(); 
   if ( LineIn.indexOf("250")==-1 ) throw new Exception("Bad End of Data"); 

  }catch(Exception E) 
  { 
   System.out.println( "send: " + E ); 
   return false; 
  } 

  return true; 
 } 

 public void close() 
 { 
  try{ 
   if ( smtpHost != null ) smtpHost.close(); 
  }catch( Exception E ){} 
 } 

 protected void finalize() throws Throwable 
 { 
  close(); 
 } 
}

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.