Using Java to Develop a Very Simple SMTP Client

Using Java to Develop a Very Simple SMTP Client
Yanjiang Qian
January 30, 2006
1 Introduction
In this short article, let’s enjoy the digging of the Simple Mail Transfer Protocol (SMTP) and a simple implementing of its client end. The Java programming language, which has the powerful support for net programming, certainly is the first candidate to do the job.
2 Background
Just as what its name indicates, SMTP [5] is the standard internet protocol for sending email from one system to another. Although the word “simple” belies the inherent complexity of the protocol, SMTP has proved to be a remarkably robust, useful, and successful standard.
When the SMTP was written in 1982, the internet was not so complex today. The number of hosts was small enough that all of the participants could recognize each other. In this early setting, SMTP emphasis on reliability instead of security was reasonable and contributed to its wide adoption. But later, with the development of the net, this feature gave spammers and infectious code an easy way to spread their unwanted messages. Spam and email worms become the biggest threats for the internet. To against, several proposals was proposed and used today. The method of sender authentication is a recent and popular one. Nowadays, almost all the free mail servers use this mechanism to ensure that the computer or the user who is sending the mail to and from them is authorized to do so [6].
In the following sections, we will first dig the SMTP procedure and then the SMTP service extension for authentication. After that, we’ll use Java to implement a simple SMTP client package. And at last, using the package developed, we’ll provide a email sending example.
3 The SMTP Procedure
The procedure of SMTP [5] mail transaction looks simple and directly. There are three main steps to this transaction. The transaction is started with a MAIL command which provides the sender’s information. Then follows is a series of one or more RCPT commands which give the information for the recipients. Then is the DATA command which gives the content of the mail. And finally, the end of mail data indicator, which will be explained in the later of this section, confirms the transaction.
The first step, i.e., the MAIL command is like this
MAIL <SP> FROM:<reverse-path> <CRLF>
This command tells the SMTP-receiver that a new mail transaction is starting. The <reverse-path> specifies who the mail is from. If accepted, the SMTP-receiver returns a 250 OK reply from the SMTP mail server.
Then is the second step, i.e., the RCPT command.
RCPT <SP>TO:<forward-path> <CRLF>
This command provides the <forward-path> which specifies one recipient, i.e., who the mail is to. If accepted, the SMTP-receiver returns a 250 OK reply. Note that, since there can be more than one recipient, this step can be repeated any number of times.
The third step is the DATA command.
DATA <CRLF>
If accepted, the SMTP-receiver returns a 354 Intermediate reply and considers all succeeding lines to be the message text.
Then you may want to ask, since all lines after the DATA command are considered as message text, then how to indicate the end of the message? Good question! According to the SMTP, to indicate the end of the mail data, we use a line containing only a period. Like following
<CRLF>.<CRLF>
Please see Section 4.5.2 on RFC 821, there are more detailed discussions. The above procedure is an example of a mail transaction. These commands must be used only in the order discussed above. Figure 1 below is an example demonstrates the procedures of a mail transaction.
Figure 1: The Procedures of A Mail Transaction
[S:] 220 MYSHECMSG01.ad.infosys.com
[C:] HELO MYSHECMSG01.ad.infosys.com
[S:] 250 MYSHECMSG01.ad.infosys.com Hello [172.21.7.115]
[C:] MAIL FROM:<214109@infosys.com>
[S:] 250 2.1.0 214109@infosys.com....Sender OK
[C:] RCPT To:<214109@infosys.com>
[S:] 250 2.1.5 214110@infosys.com
[C:] DATA
[S:] 354 Start mail input; end with <CRLF>.<CRLF>
[C:] From: <214109@infosys.com>
To: <[214109@infosys.com]>
Subject: hello
Date: Fri Jan 27 23:07:21 GMT+05:30 2006
Content-Type: text/plain;charset="GB2312"
This is a test
.
[S:] 250 2.6.0 Queued mail for delivery
[C:] 221 2.0.0 Service closing transmission channel
4 Introduction to Authentication
The RFC 2554 [4] defines the SMTP Service Extension for authentication. Here I want to go the key part directly, leaving the detail for you. You can get the RFC 2554 from this link http://www.ietf.org/rfc/rfc2554.txt.
The main SMTP service extension for authentication is the AUTH command. The argument of command specifies the authentication mechanism. LOGIN and CRAM-MD5 are two main supported mechanisms.
The procedure of the authentication is like this. First, the AUTH command indicates an authentication mechanism by its argument to the server. If the server supports the requested mechanism, it will use the ”server challenges and client answers” that are specific to the authentication mechanism to authenticate and identify the user. Take the LOGIN mechanism for example, after receiving the AUTH LOGIN command, the server, which should support the LOGIN mechanism of course, will ask the email sender the user-name and the password for the user account. If the sender can responded with expected information, then a authentication is finished, and the sender can perform other proper commands. A server challenge, otherwise known as a ready response, is a 334 reply with the text part containing a BASE64 encoded string. The client answer consists of a line containing a BASE64 encoded string.
If the requested mechanism is not supported, the server rejects the AUTH command with a 504 reply. And corresponding reply will be sent by the server if the sender fails in the challenges. Figure 2 below is an example demonstrates the procedures of authentication for the LOGIN authentication mechanism.
Figure 2: The Procedure of Authentication
[S:] ....
[C:] EHLO MYSHECMSG01.ad.infosys.com
[S:] 250-MYSHECMSG01.ad.infosys.com Hello [172.21.7.115]
[C:] AUTH LOGIN
[S:] 334 VXNlcm5hbWU6
[C:] MjE0MTA5
[S:] 334 UGFzc3dvcmQ6
[C:] Smlhbmc9NTgxMjA0
[S:] 235 2.7.0 Authentication successful.
[C:] ....
5 SMTP Client Implementing Package
After getting some understanding the protocol and theory, let’s do something really interesting. In this section, we’ll use the information from previous sections develop a SMTP client implementing[1, 2, 3] package. This package will contains three main classes, EmailAddress, Email and EmailController. Following sections describes each class in detail.
5.1 EmailAddress
The EmailAddress class includes two fields, address and password. The address is formed as ”userID + ’@’ + domain”. For example, I have two emails. One is ”214109@infosys.com” and the other is ”yanjiangqian@hotmail.com”. Not like in the early time of the Internet, nowadays we always must do authentication to the SMTP mail server through which if we want to delivery our mails [6]. So there is the field password coming with EmailAddress. 
In this class, there are two constructors. One takes address and password as its parameters, and the other takes only the address. This is for the sake of compatibility. The method getUserID and getDomain is used to get the userID and domain of the address separately. The EmailAddress class is shown in Figure 3 below.
Figure 3: The EmailAddress Class
001: /*
002:  * File Name: EmailAddress.java
003:  * Description: This file contains the EmailAddress Class.
004:  * Date: 30/01/2006
005:  */
006: package com.forrest.smtpclient;
007:
008: /**
009:  * This <B>EmailAddress</B>Class descripts the Email
010:  * Address.
011:  *
012:  * @author Yanjiang Qian
013:  * @version 1.0 30/01/2006
014:  */
015: public class EmailAddress {
016:     /** Email Address */
017:     private String address;
018:
019:     /** The password for the address */
020:     private String password;
021:
022:     /**
023:      * Constructor.
024:      *
025:      * @param strAddr
026:      *            address of the mail
027:      * @param strPwd
028:      *            password for this mail
029:      * @throws EmailException
030:      */
031:     public EmailAddress(String strAddr, String strPwd)
032:             throws EmailException {
033:         if (strAddr == null || strAddr.equals("")) {

034:             throw new EmailException(
035:                     "Invalid Email Address");
036:         }
037:         this.address = strAddr;
038:         this.password = strPwd;
039:     }
040:
041:     /**
042:      * Constructor.
043:      *
044:      * @param strAddr
045:      *            address of the mail
046:      * @throws EmailException
047:      */
048:     public EmailAddress(String strAddr)
049:             throws EmailException {
050:         if (strAddr == null || strAddr.equals("")) {
051:             throw new EmailException(
052:                     "Invalid Email Address");
053:         }
054:         this.address = strAddr;
055:     }
056:
057:     /**
058:      * Get the Password for this email address.
059:      *

060:      * @return the password
061:      */
062:     public String getPassword() {
063:         return password;
064:     }
065:
066:     /**
067:      * Set the Password for this email address.
068:      *
069:      * @param password
070:      *            the password to be set
071:      */
072:     public void setPassword(String strPassword) {
073:         this.password = strPassword;
074:     }
075:
076:     /**
077:      * Set the address of current mail
078:      *
079:      * @param strAddress
080:      *            the address
081:      */
082:     public void setAddress(String strAddress) {
083:         this.address = strAddress;
084:     }
085:
086:     /**
087:      * Get the userID from this email address. Usually, the

088:      * email address is formed as "userID +
'@' + domain".
089:      * This method will get the userID part.
090:      *
091:      * @return the userID
092:      */
093:     public String getUserID() {
094:         int idx = this.address.indexOf(
'@' );
095:         return this.address.substring(0, idx);
096:     }
097:
098:     /**
099:      * Get the userID from this email address. Usually, the
100:      * email address is formed as "userID +
'@' + domain".
101:      * This method will get the domain part.
102:      *
103:      * @return the domain
104:      */
105:     public String getDomain() {
106:         int idx = this.address.indexOf(
'@' ) + 1;
107:         return this.address.substring(idx);
108:     }
109:
110:     public boolean equals(Object obj) {
111:         if (obj != null) {
112:             if (obj instanceof EmailAddress) {
113:                 EmailAddress emailaddr = (EmailAddress) obj;
114:                 if (emailaddr.address
115:                         .equalsIgnoreCase(this.address))
116:                     return true;
117:             }
118:         }
119:         return false;
120:     }
121:
122:     public String toString() {
123:         return this.address;
124:     }
125: }
5.2 Email
The Email class includes sender, recipients, subject, data, four fields. The sender is an EmailAddress object. The recipients is an Vector object of EmailAddress objects. The subject and data are two String objects for the subject and data of a email message separately. In this class, there are some setter and getter methods for these four fields. The addRecipient method takes an EmailAddress object as parameter and add it to the recipients list.
The Email class is shown in Figure 4.
Figure 4: The Email Class
001: /*
002:  * File Name: Email.java
003:  * Description: This file contains the Email Class.
004:  * Date: 30/01/2006
005:  */
006:
007: package com.forrest.smtpclient;
008:
009: import java.util.Enumeration;
010: import java.util.Vector;
011:
012: /**
013:  * The <B>Email</B> Class.
014:  *
015:  * @author Yanjiang Qian
016:  * @version 1.0
017:  */
018: public class Email {
019:     /** sender of the mail */
020:     private EmailAddress sender;
021:
022:     /** mail recipients list */
023:     private Vector recipients;
024:
025:     /** subject of the mail */
026:     private String subject;
027:
028:     /** data of the mail */
029:     private String data;
030:
031:     /**
032:      * Contructor.
033:      */
034:     public Email() {
035:         this.recipients = new Vector();
036:     }
037:
038:     /**
039:      * Add a recipient to the recipients list.
040:      *
041:      * @param emailAddr
042:      *            the email address of the recipient
043:      * @return true if successfully added, false otherwise.
044:      */
045:     public boolean addRecipient(EmailAddress emailAddr) {
046:         if (emailAddr != null) {
047:             if (!recipients.contains(emailAddr))
048:                 return recipients.add(emailAddr);
049:         }
050:         return false;
051:     }
052:
053:     /**
054:      * Set the mail sender
055:      *
056:      * @param emailAddr
057:      *            mail sender
058:      */
059:     public void setSender(EmailAddress emailAddr) {
060:         this.sender = emailAddr;
061:     }
062:
063:     /**
064:      * Get the mail sender
065:      *
066:      * @return the mail sender
067:      */
068:     public EmailAddress getSender() {
069:         return this.sender;
070:     }
071:
072:     /**
073:      * Set recipients for the mail
074:      *
075:      * @param vecRecipients
076:      *            vector object contains the recipients
077:      */
078:     public void setRecipients(Vector vecRecipients) {
079:         if (vecRecipients != null
080:                 && vecRecipients.size() > 0) {
081:             this.recipients = vecRecipients;
082:         }
083:     }
084:
085:     /**
086:      * Get all recipients of the mail
087:      *
088:      * @return all the recipients
089:      */
090:     public EmailAddress[] getRecipients() {
091:         EmailAddress[] addresses =
092:             new EmailAddress[this.recipients.size()];
093:         int idx = 0;
094:         for (Enumeration e = recipients.elements();
095:             e.hasMoreElements();) {
096:             addresses[idx++] =
097:                 (EmailAddress) e.nextElement();
098:         }
099:         return addresses;
100:     }
101:
102:     /**
103:      * Set the mail subject
104:      *
105:      * @param strSubject
106:      *            subject to set
107:      */
108:     public void setSubject(String strSubject) {
109:         this.subject = strSubject;
110:     }
111:
112:     /**
113:      * Get the mail subject
114:      *
115:      * @return the subject
116:      */
117:     public String getSubject() {
118:         return this.subject;
119:     }
120:
121:     /**
122:      * Set the data of the mail
123:      *
124:      * @param strData
125:      *            mail data to be set
126:      */
127:     public void setData(String strData) {
128:         this.data = strData;
129:     }
130:
131:     /**
132:      * Get the data part of the mail
133:      *
134:      * @return the data part of the mail
135:      */
136:     public String getData() {
137:         return this.data;
138:     }
139: }
5.3 EmailController
The EmailController functions as a bridge between the SMTP mail server and the client. It first creates a stream socket and connects it to the specified port number at the specified IP address of the SMTP mail server. Then request and response to the server with ordered commands, sending the mail. At last, close the connection. The constructor method EmailController takes the IP address of the SMTP mail server ad one of its parameters. The other parameter port specifies the port on which the connection will be established. Defualt value for this port is ”25”. The send method takes an email object as its parameter. Its function is to send the mail to the server specified by the constructor method. The readResponse and sendRequest are two methods used in the send. The readResponse method takes an String of the expected reply code (See APPENDIX E of RFC 821[5] to get more information) as its parameter. The reply code contains three digits and is always the starting part of the server’s reply. So we can use this method to
check whether the reply is what we expected. If the reply is not what we expected, then an exception will be throwed out to indicate an error happened. For the sendRequest method, the msg parameter is the request message from the client. The message like ”MAIL FROM:<user@some.com>”, “TO:<other@other.com>”, ”AUTH LOGIN”, ” <CRLF> .<CRLF> ”etc.
The EmailController class is shown in Figure 5.
Figure 5: The EmailController Class
001: /*
002:  * File Name: EMailController.java
003:  * Description: This file contains the EMailController Class.
004:  * Date: 30/01/2006
005:  */
006:
007: package com.forrest.smtpclient;
008:
009: import java.io.BufferedReader;
010: import java.io.DataOutputStream;
011: import java.io.IOException;
012: import java.io.InputStreamReader;
013: import java.net.InetAddress;
014: import java.net.Socket;
015: import java.net.UnknownHostException;
016:
017: import sun.misc.BASE64Encoder;
018:
019: /**
020:  * The <B>EMailController</B> Class functions as a
021:  * controller who will handle the connection establishing,
022:  * mail sending, connection closing etc.
023:  *
024:  * @author Yanjiang Qian
025:  * @version 1.0
026:  */
027: public class EMailController {
028:     private BufferedReader in;
029:
030:     private DataOutputStream out;
031:
032:     private Socket socket;
033:
034:     private InetAddress mailServer;
035:
036:     public static final String CRLF = "/r/n";
037:
038:     public static final String
039:         MAIL_ENDER = CRLF + "." + CRLF;
040:
041:     /**
042:      * Contstructor
043:      *
044:      * @param strMailServer
045:      *            SMTP mail server
046:      * @param port
047:      *            port, default is 25
048:      * @throws UnknownHostException
049:      * @throws IOException
050:      */
051:     public EMailController(String strMailServer, int port)
052:             throws UnknownHostException, IOException {
053:         this.mailServer = InetAddress
054:                 .getByName(strMailServer);
055:         socket = new Socket(this.mailServer, port);
056:         in = new BufferedReader(new InputStreamReader(
057:                 socket.getInputStream()));
058:         out = new DataOutputStream(
059:                 socket.getOutputStream());
060:     }
061:
062:     /**
063:      * Contstructor uses 25 as default port
064:      *
065:      * @param strMailServer
066:      *            SMTP mail server
067:      * @throws UnknownHostException
068:      * @throws IOException
069:      */
070:     public EMailController(String strMailServer)
071:             throws UnknownHostException, IOException {
072:         this(strMailServer, 25);
073:     }
074:
075:     /**
076:      * Send the mail
077:      *
078:      * @param email
079:      *            the email object
080:      * @return true if the sending operation is successful,
081:      *         false otherwise.
082:      */
083:     public boolean send(Email email) {
084:         // get the fields
085:         String strMailServer = mailServer.toString();
086:         strMailServer = strMailServer.substring(0,
087:                 strMailServer.indexOf('/'));
088:         String sender = email.getSender().toString();
089:         String strUserName = email.getSender().getUserID();
090:         String strPassword =
091:             email.getSender().getPassword();
092:         EmailAddress[] recipients = email.getRecipients();
093:         String subject = email.getSubject();
094:         String data = email.getData();
095:
096:         // conecting to the server successfully
097:         try {
098:             readResponse("220");
099:
100:             // HELO host
101:             sendRequest("HELO " + strMailServer + CRLF);
102:             readResponse("250");
103:
104:             if (!strPassword.trim().equals("")) {
105:                 // EHLO host
106:                 sendRequest("EHLO " + strMailServer + CRLF);
107:                 readResponse("250");
108:
109:                 // AUTH LOGIN
110:                 sendRequest("AUTH LOGIN" + CRLF);
111:                 readResponse("334");
112:
113:                 // USERNAME:
114:                 sendRequest(new String(new BASE64Encoder()
115:                         .encode(strUserName.getBytes()))
116:                         + CRLF);
117:                 readResponse("334");
118:
119:                 // PASSWORD:
120:                 sendRequest(new String(new BASE64Encoder()
121:                         .encode(strPassword.getBytes()))
122:                         + CRLF);
123:                 readResponse("235");
124:             }
125:
126:             // MAIL FROM:<..>
127:             sendRequest("MAIL FROM:<" + sender + ">" + CRLF);
128:             readResponse("250");
129:
130:             // RCPT TO:<..>
131:             for (int i = 0; i < recipients.length; i++) {
132:                 sendRequest("RCPT To:<"
133:                         + recipients[i].toString() + ">"
134:                         + CRLF);
135:                 readResponse("250");
136:             }
137:             // DATA
138:             sendRequest("DATA" + CRLF);
139:             readResponse("354");
140:
141:             // data of the mail
142:             StringBuffer s1 = new StringBuffer("From: <"
143:                     + sender + ">" + CRLF);
144:             String tos = "";
145:             for (int i = 0; i < recipients.length - 1; i++) {
146:                 tos += recipients[i].toString();
147:                 tos += "; ";
148:             }
149:             tos += recipients[recipients.length - 1]
150:                     .toString();
151:
152:             s1.append("To: <" + tos + ">" + CRLF);
153:             s1.append("Subject: " + subject + CRLF);
154:             s1.append("Date: "
155:                     + new java.util.Date().toString()
156:                     + CRLF);
157:             s1.append("Content-Type: "
158:                     + "text/plain;charset=/"UTF-8/""
159:                     + CRLF);
160:             s1.append(CRLF);
161:             s1.append(data);
162:             s1.append(MAIL_ENDER);
163:
164:             // send the mail
165:             sendRequest(s1.toString());
166:             readResponse("250");
167:
168:             // QUIT
169:             sendRequest("QUIT" + CRLF);
170:             readResponse("221");
171:             close();
172:         } catch (Exception e) {
173:             e.printStackTrace();
174:         }
175:         return true;
176:     }
177:
178:     /**
179:      * Reading expected response from the SMTP mail server.
180:      * The expected response is specified by the cmd.
181:      *
182:      * @param cmd
183:      *            the expected response code, like 220, 520,
184:      *            etc.
185:      * @throws Exception
186:      */
187:     private void readResponse(String cmd) throws Exception {
188:         String tmp = in.readLine();
189:         if (tmp.startsWith(cmd))
190:             System.out.println(" [S:] " + tmp);
191:         else
192:             throw new Exception(tmp);
193:         while (tmp.startsWith(cmd + "-")) {
194:             tmp = in.readLine();
195:         }
196:     }
197:
198:     /**
199:      * Sending request to the SMTP mail server
200:      *
201:      * @param msg
202:      *            the request
203:      */
204:     private void sendRequest(String msg) {
205:         System.out.print(" [C:] " + msg);
206:         try {
207:             out.writeBytes(msg);
208:         } catch (IOException e) {
209:             e.printStackTrace();
210:         }
211:     }
212:
213:     /**
214:      * Close all the connections and release the resources.
215:      */
216:     public void close() {
217:         try {
218:             in.close();
219:             in = null;
220:         } catch (Exception ex) {
221:         }
222:         try {
223:             out.close();
224:             out = null;
225:         } catch (Exception ex) {
226:         }
227:         try {
228:             socket.close();
229:             socket = null;
230:         } catch (Exception ex) {
231:         }
232:     }
233: }
 
6 An Example
Finally, we come to this section. In this section, we will develop a simple Java AWT program to test the package we developed in last section. Now, leave the implemented package, just think about the procedure we need when we are sending an email. And at the same time, please notice what field need we provided in the graphic user interface of this example.
In our daily life, when we want to send a mail, take hotmail for example, first we must use web brower to open a link, http://www.hotmail.com, then a sign in page will be displayed out. The page will provide two fields for input, userid and password. After we typed the correct userid and password, we click on the sign in button, then we go to the mail box. Let’s go a little further to compose a new email. We click on the”New Message”. Oh, the mail writing page is displayed out. Suppose today is my birthday3, I
want to send a invite to my best friend Bob. I have knew his email address is ffffx0@gmail.com, so I type in the To field ”ffffx0@gmail.com”. Then, I think the mail should also be sent to Tom (hope2jiang@126.com). I also want him joining my party. Again, I type ”hope2jiang@126.com” in the To field with a semicolon separates it from Bob’s mail address. Then comes to the Subject. I type ”Invite you join my birthday party”. Finally, it is the data part of the mail. I type something ebullient to ensure that they will certainly come and finished my email. But wait, our composing is finished,
but the email still does not go the recipients. I find there’s a Send on the page. I click on it, then a dialog shows out to tell me that my message has been successfully sent. That’s the procedure of sending an email.
You may want to ask, do you want to develop a example like this? Of course not. I have said we will develop a simple one. The example will not be so complicated like this but will be pocket version of this. Then which part or field should be kept and which to be droped? If you’ve went through last paragraph carefully, you must have found the text in italy font. They are link, userid, password, To, Subject and data. After think for a while, you may nod your head and say that, yes, userid, password, To, Subject and data must be kept. But what about link? How can we use it in our example? Good question! Go through Class EmailController, you may get the answer yourself. The fields will appear in the SimpleTest class is Server[2] , Port[3] , From6[4] , Password, To, Subject and Message7[5] . The SimpleTest class is shown in Figure 6.
Figure 6: The SimpleTest Class
001: /*
002:  * File Name: SimpleTest.java
003:  * Description: This file contains the SimpleTest Class.
004:  * Date: 30/01/2006
005:  */
006:
007: package example;
008:
009: import example.LabeledTextField;
010:
011: import java.awt.BorderLayout;
012: import java.awt.Button;
013: import java.awt.Color;
014: import java.awt.Font;
015: import java.awt.Frame;
016: import java.awt.GridLayout;
017: import java.awt.Label;
018: import java.awt.Panel;
019: import java.awt.TextArea;
020: import java.awt.event.ActionEvent;
021: import java.awt.event.ActionListener;
022: import java.awt.event.WindowAdapter;
023: import java.awt.event.WindowEvent;
024: import java.io.IOException;
025: import java.net.UnknownHostException;
026: import java.util.StringTokenizer;
027:
028: import com.forrest.smtpclient.Email;
029: import com.forrest.smtpclient.EmailAddress;
030: import com.forrest.smtpclient.EmailException;
031: import com.forrest.smtpclient.EMailController;
032:
033: /**
034:  * The is a simple test. Date: 30/01/2006
035:  *
036:  * @author Yanjiang Qian
037:  * @version 1.0
038:  */
039: public class SimpleTest extends Frame implements
040:         ActionListener {
041:     /** Serial Verson ID */
042:     private static final long serialVersionUID = 1L;
043:
044:     /** The SMTP mail server */
045:     private LabeledTextField serverField;
046:
047:     /** The port of the mail server */
048:     private LabeledTextField portField;
049:
050:     /** The From mail (sender) */
051:     private LabeledTextField fromField;
052:
053:     /** The password of the sender's userID */
054:     private LabeledTextField passwordField;
055:
056:     /** The To mail (recipient) */
057:     private LabeledTextField toField;
058:
059:     /** The subject of the mail */
060:     private LabeledTextField subjectField;
061:
062:     /** The data of the mail message */
063:     private TextArea dataArea;
064:
065:     /** The send button */
066:     private Button sendButton;
067:
068:     /** The result of current mail sending operation */
069:     private Label result;
070:
071:     /**
072:      * Contructor.
073:      *
074:      * @param title
075:      *            Title of the Frame
076:      */
077:     public SimpleTest(String title) {
078:         super(title);
079:         initizlize();
080:     }
081:
082:     /**
083:      * Initialize the user interface.
084:      */
085:     private void initizlize() {
086:         setBackground(Color.lightGray);
087:         setLayout(new BorderLayout(5, 30));
088:
089:         int fontSize = 14;
090:
091:         Font labelFont = new Font("Courier", Font.BOLD,
092:                 fontSize);
093:         Font textFont = new Font("Courier", Font.PLAIN,
094:                 fontSize - 2);
095:         Font resultFont = new Font("Arial", Font.BOLD,
096:                 fontSize - 1);
097:
098:         Panel inputPanel = new Panel();
099:         inputPanel.setLayout(new BorderLayout());
100:
101:         Panel labelPanel = new Panel();
102:         labelPanel.setLayout(new GridLayout(7, 1));
103:
104:         serverField = new LabeledTextField("Server:  ",
105:                 labelFont, 20, textFont);
106:         portField = new LabeledTextField("Port:    ",
107:                 labelFont, "25", 5, textFont);
108:         fromField = new LabeledTextField("From:    ",
109:                 labelFont, 20, textFont);
110:         passwordField = new LabeledTextField("Password:",
111:                 labelFont, 6, textFont);
112:         toField = new LabeledTextField("To:      ",
113:                 labelFont, 50, textFont);
114:         subjectField = new LabeledTextField("Subject: ",
115:                 labelFont, 40, textFont);
116:
117:         labelPanel.add(serverField);
118:         labelPanel.add(portField);
119:         labelPanel.add(fromField);
120:         labelPanel.add(passwordField);
121:         labelPanel.add(toField);
122:         labelPanel.add(subjectField);
123:
124:         Label messageLabel = new Label("Message Body:");
125:         messageLabel.setFont(labelFont);
126:
127:         labelPanel.add(messageLabel);
128:
129:         inputPanel.add(labelPanel, BorderLayout.NORTH);
130:
131:         dataArea = new TextArea(5, 80);
132:         dataArea.setFont(textFont);
133:
134:         inputPanel.add(dataArea, BorderLayout.CENTER);
135:
136:         Panel buttonPanel = new Panel();
137:         sendButton = new Button("Send");
138:         sendButton.addActionListener(this);
139:         sendButton.setFont(labelFont);
140:         buttonPanel.add(sendButton);
141:
142:         Panel resultPanel = new Panel();
143:         result = new Label(
144:                 "This is the result of your sending...");
145:         result.setFont(resultFont);
146:         result.setForeground(Color.RED);
147:         resultPanel.add(result);
148:
149:         inputPanel.add(buttonPanel, BorderLayout.SOUTH);
150:
151:         add(inputPanel, BorderLayout.CENTER);
152:         add(resultPanel, BorderLayout.SOUTH);
153:
154:         setSize(500, 500);
155:
156:         setVisible(true);
157:
158:         addWindowListener(new WindowsClose());
159:     }
160:
161:     public void actionPerformed(ActionEvent e) {
162:         if (e.getSource() == sendButton) {
163:             sendMail();
164:         }
165:     }
166:
167:     /**
168:      * Send the mail
169:      */
170:     public void sendMail() {
171:         EMailController server = null;
172:         String strServer = serverField.getTextField()
173:                 .getText();
174:         String strPort = portField.getTextField().getText();
175:         String strFrom = fromField.getTextField().getText();
176:         String strPassword = passwordField.getTextField()
177:                 .getText();
178:         String strTo = toField.getTextField().getText();
179:         StringTokenizer st = new StringTokenizer(strTo, ";");
180:
181:         /* Configure the mail server */
182:         try {
183:             int port = Integer.parseInt(strPort);
184:             server = new EMailController(strServer, port);
185:         } catch (UnknownHostException e) {
186:             e.printStackTrace();
187:         } catch (NumberFormatException e) {
188:             e.printStackTrace();
189:         } catch (IOException e) {
190:             e.printStackTrace();
191:         }
192:         /* Configure the email message */
193:         Email email = new Email();
194:         try {
195:             email.setSender(new EmailAddress(strFrom,
196:                     strPassword));
197:             while (st.hasMoreTokens()) {
198:                 email.addRecipient(new EmailAddress(st
199:                         .nextToken()));
200:             }
201:
202:             email.setSubject(subjectField.getTextField()
203:                     .getText());
204:             email.setData(dataArea.getText());
205:         } catch (EmailException e1) {
206:             e1.printStackTrace();
207:         }
208:         /* send the mail */
209:         boolean success = server.send(email);
210:
211:         /* the sending result */
212:         if (success) {
213:             result.setText("Your mail has been " +
214:                     "successfully sent!");
215:             subjectField.getTextField().setText("");
216:             dataArea.setText("");
217:         } else {
218:             result.setText("Your mail sending " +
219:                     "operation is failed.");
220:         }
221:     }
222:
223:     public static void main(String args[]) {
224:         SimpleTest example = new SimpleTest(
225:                 "SMTP Client Example");
226:     }
227: }
228:
229: /**
230:  * A Windows Adapter Class. It will handle the window
231:  * closing event.
232:  *
233:  * @author 214109
234:  * @version 1.0
235:  */
236: class WindowsClose extends WindowAdapter {
237:     public void windowClosing(WindowEvent we) {
238:         we.getWindow().dispose();
239:     }
240: }
Figure 7 shows the running result of the program.
Figure 7: Snapshot of the Program
 
References
[1] Anonymous, January 26, 2006. Using Java to Develop a Email Sending Program, Available from http://chinaitpower.com/A/2003-07-17/142169.html.
[2] Anonymous, January 26, 2006. Using Socket to Send Email, Available from http://www.99net.net/study/prog/67171825.htm.
[3] George Crawford. A simple smtp framework for java. ACM Acrossroads, April 1997. Available from http://www.acm.org/crossroads/xrds4-4/ovp.html.
[4] J. Myers, 1999. SMTP Service Extension for Authentication, Available from http://www.ietf.org/rfc/rfc2554.txt.
[5] Jonathan B. Postel, 1982. Simple Mail Transfer Protocal, Available from http://www.ietf.org/rfc/rfc0821.txt.
[6] Kirk Strauser. The history and features of smtp. Free Software Magazine, March 2005.
The Source Code
In the implemented package (Section 5) and the example (Section 6), there are two classes, EmailException and LabeledTextField, not listed out.
Here is the source code.
Figure 8: The EmailException Class
01: /*
02:  * File Name: EmailException.java
03:  * Description: This file contains the Email Class.
04:  * Date: 30/01/2006
05:  */
06: package com.forrest.smtpclient;
07:
08: /**
09:  * The <B>EmailException</B> Class.
10:  *
11:  * @author Yanjiang Qian
12:  * @version 1.0 30/01/2006
13:  */
14: public class EmailException extends Exception {
15:     /** Serial Version ID */
16:     private static final long serialVersionUID = 1L;
17:
18:     /**
19:      * Constuctor
20:      *
21:      * @param strMsg
22:      */
23:     public EmailException(String strMsg) {
24:         super(strMsg);
25:     }
26: }
Figure 9: The LabeledTextField Class
01: package example;
02:
03: import java.awt.*;
04:
05: /**
06:  * A TextField with an associated Label.
07:  * <P>
08:  * Taken from Core Servlets and JavaServer Pages from
09:  * Prentice Hall and Sun Microsystems Press,
10:  *
http://www.coreservlets.com/ . &copy; 2000 Marty Hall; may
11:  * be freely used or adapted.
12:  */
13:
14: public class LabeledTextField extends Panel {
15:     /** Serial Version ID */
16:     private static final long serialVersionUID = 1L;
17:
18:     /** The Label */
19:     private Label label;
20:
21:     /** TextField */
22:     private TextField textField;
23:
24:     /**
25:      * Constructor
26:      *
27:      * @param labelString
28:      *            the label
29:      * @param labelFont
30:      *            the font of the label text
31:      * @param textFieldSize
32:      *            the size of the textfield
33:      * @param textFont
34:      *            the font of the text
35:      */
36:     public LabeledTextField(String labelString,
37:             Font labelFont, int textFieldSize, Font textFont) {
38:         setLayout(new FlowLayout(FlowLayout.LEFT));
39:         label = new Label(labelString, Label.RIGHT);
40:         if (labelFont != null)
41:             label.setFont(labelFont);
42:         add(label);
43:         textField = new TextField(textFieldSize);
44:         if (textFont != null)
45:             textField.setFont(textFont);
46:         add(textField);
47:     }
48:
49:     public LabeledTextField(String labelString,
50:             String textFieldString) {
51:         this(labelString, null, textFieldString,
52:                 textFieldString.length(), null);
53:     }
54:
55:     public LabeledTextField(String labelString,
56:             int textFieldSize) {
57:         this(labelString, null, textFieldSize, null);
58:     }
59:
60:     public LabeledTextField(String labelString,
61:             Font labelFont, String textFieldString,
62:             int textFieldSize, Font textFont) {
63:         this(labelString, labelFont, textFieldSize,
64:                 textFont);
65:         textField.setText(textFieldString);
66:     }
67:
68:     /**
69:      * The Label at the left side of the LabeledTextField.
70:      * To manipulate the Label, do:
71:      *
72:      * <PRE>
73:      *
74:      * LabeledTextField ltf = new LabeledTextField(...);
75:      * ltf.getLabel().someLabelMethod(...);
76:      *
77:      * </PRE>
78:      *
79:      * @see #getTextField
80:      */
81:
82:     public Label getLabel() {
83:         return (label);
84:     }
85:
86:     /**
87:      * The TextField at the right side of the
88:      * LabeledTextField.
89:      *
90:      * @see #getLabel
91:      */
92:
93:     public TextField getTextField() {
94:         return (textField);
95:     }
96: }


[1] The SMTP (RFC 821) was proposed by Jonathan B. Postel at August 1982. An SMTP server listens on port 25 for client connection.   
[2] A little difference from the link, Server here is the actually URL address of the server.
[3] The default port of SMTP mail server is 25. But some implementing may be different.
So a port field is provided.
[4] Almost same as userid, but From is the full email address.
[5] Same as data
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值