Consolidating Email using Java, Part 2
Complete Program Listings
Complete listings of the classes discussed in this lesson are shown in Listings 9 and 10 below.
/*File BigDog06fetch.java
Copyright 2005, R.G.Baldwin
Rev 08/17/05
This is a modification of the program named
BigDog04g to fully automate the process.
DISCLAIMER: THIS PROGRAM IS PROVIDED TO YOU AT
NO COST. BY USING THIS PROGRAM TO PROCESS YOUR
EMAIL, YOU AGREE THAT YOU ARE USING IT AT YOUR
OWN RISK. THE AUTHOR OF THE PROGRAM, RICHARD G.
BALDWIN, ACCEPTS NO LIABILITY FOR ANY LOSS THAT
YOU MAY INCUR THROUGH THE USE OF THIS PROGRAM.
This program downloads all messages from a
pop3Server and writes them as individual files in
a local working directory. Then it instantiates
an object of the class BigDog06forward, which
forwards the messages to a specified email
address using a specified SMTP server.
Messages are not deleted from the pop3Server
until they have been forwarded to the specified
email address. When the messages are deleted from
the pop3Server, the message files are also
removed from the working directory.
By enabling and disabling blocks of code prior to
compilation, you can customize the program to
cause the message files to be moved from the
working directory into an archive directory or
simply deleted from the working directory without
saving them in an archive directory.
The following information is provided as
command-line parameters:
pop3Server: server from which the messages will
be downloaded
userName: on pop3Server
password: on pop3Server
destinationAddress: email address to which the
messages are to be forwarded
smtpServer: an available SMTP server that can be
used to forward the messages
workingDir: messages are temporarily stored here
archiveDir: messages are moved to here from the
workingDir for long-term storage if desired
fwdTag: String prepended to the subject when the
message is forwarded.
Note that both of the directories listed above
must already exist when the program is run for
the first time.
If message files are not being saved in an
archive directory, the seventh parameter is a
dummy parameter, which is essentially ignored by
the program, but it must be provided.
If you don't want to tag the subject of the
forwarded msg, just enter "" as the eighth
command-line parameter.
For technical information on POP3, see RFC 1725
at
http://www.cse.ohio-state.edu/cgi-bin/rfc/
rfc1725.html
A POP3 Command Summary follows based on the
information at that web site.
Minimal POP3 Commands:
USER name
PASS string
QUIT
STAT
LIST [msg]
RETR msg
DELE msg
NOOP
RSET
QUIT
Optional POP3 Commands:
APOP name digest
TOP msg n
UIDL [msg]
POP3 Replies:
+OK
-ERR
Tested using JDK 1.5.0_01 under WinXP
************************************************/
import java.net.*;
import java.io.*;
import java.awt.*;
class BigDog06fetch{
static String workingDir;
int numberMsgs = 0;
int msgNumber;
String uidl = "";//unique msg ID
BufferedReader inputStream;
PrintWriter outputStream;
Socket socket;
String pathFileName;
static String[] params;
public static void main(String[] args){
if(args.length != 8){
System.out.println(
"Wrong number of parameters");
System.out.println(
"Usage: java BigDog06fetch "
+ "npop3Server nuserName npassword "
+ "ndestinationAddress nsmtpServer"
+ "nworkingDir narchiveDir nfwdTag");
System.out.println("If not saving msg "
+ "files in archive, seventh parameter "
+ "is a dummy parameter.");
System.out.println("Terminating program.");
System.exit(0);
}//end if
//Save the command-line parameters for later
//use by the object of the class
// BigDog06forward
params = args;
//Establish the name of the working
// directory. Note that this directory must
// already exist.
workingDir = args[5];
System.out.println(
"pop3Server: " + params[0]);
System.out.println("userName: " + params[1]);
System.out.println("password: ..........");
System.out.println(
"destinationAddress: " + params[3]);
System.out.println(
"smtpServer: " + params[4]);
System.out.println(
"workingDir: " + params[5]);
System.out.println(
"archiveDir: " + params[6]);
System.out.println("fwdTag: " + params[7]);
//Instantiate an object that will download
// and save the messages as individual files.
// This object will in turn instantiate an
// object of the class BigDog06forward, which
// will forward the messages to the
// destination email address.
new BigDog06fetch(args[0],args[1],args[2]);
}//end main
//===========================================//
//Constructor
BigDog06fetch(String pop3Server,
String userName,
String password){
int port = 110; //pop3 mail port
try{
//Get a socket, connected to the specified
// pop3Server on the specified port.
socket = new Socket(pop3Server,port);
//Get an input stream from the socket
inputStream = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
//Get an output stream to the socket.
// Note that this stream will autoflush.
outputStream = new PrintWriter(
new OutputStreamWriter(
socket.getOutputStream()),true);
//Display the msg received from the
// pop3Server on the command-line screen
// immediately following connection.
String connectMsg = validateOneLine();
System.out.println(
"Connected to pop3Server " + connectMsg);
//The communication process is now in the
// AUTHORIZATION state. Send the user
// name and password to the pop3Server.
//Commands are sent in plain text, upper
// case to the pop3Server. Some commands
// require an argument following the
// command, as is the case with USER.
//Send the command.
outputStream.println("USER " + userName);
//Get response and confirm that the
// response was +OK and was not -ERR.
String userResponse = validateOneLine();
//Display the response on the command-
// line screen.
System.out.println("USER " + userResponse);
//Send the password to the pop3Server
outputStream.println("PASS " + password);
//Validate the pop3Server's response as +OK
// Display the response in the process.
System.out.println(
"PASS " + validateOneLine());
System.out.println("Downloading Messages");
}catch(Exception e){
e.printStackTrace();
System.exit(0);
}//end catch
fetchMsgs();
}//end constructor
//===========================================//
//Validate a one-line response.
//The purpose of this method is to confirm that
// the pop3Server returned +OK and not -ERR to
// the previous command.
//If +OK, the method returns the string
// returned by the pop3Server.
//If -ERR, the method displays the string
// returned by the pop3Server and terminates
// the session.
private String validateOneLine(){
try{
String response = inputStream.readLine();
if(response.startsWith("+OK")){
return response;
}else{
System.out.println(response);
//Terminate the session.
outputStream.println("QUIT");
socket.close();
System.out.println(
"Premature QUIT on -ERR");
System.exit(0);
}//end else
}catch(IOException ex){
ex.printStackTrace();
System.exit(0);
}//end catch
//The following return statement is required
// to satisfy the compiler, but it can never
// be reached.
return "Make compiler happy";
}//end validateOneLine()
//===========================================//
void fetchMsgs(){
//Download all messages on the pop3Server.
try{
//The communication process is now in the
// TRANSACTION state.
//Retrive and save messages
outputStream.println("STAT");
String stat = validateOneLine();
//Get the number of messages as a String.
String numberMsgsStr = stat.substring(
4,stat.indexOf(" ",5));
//Convert the String to an int.
numberMsgs = Integer.parseInt(
numberMsgsStr);
if(numberMsgs == 0){
System.out.println(
"No msg to download.");
System.out.println(
"Terminating program.");
System.exit(0);
}//end if
//NOTE: Msg numbers begin with 1, not 0.
//Retrieve and save each message. Each msg
// ends with a period on a new line.
msgNumber = 1;
while(msgNumber <= numberMsgs){
//Process the next message.
//Get and save a unique identifier for
// the message from the pop3Server and
// validate the response.
outputStream.println(
"UIDL " + msgNumber);
uidl = validateOneLine();
//Open an output file to save the
// message. Use the UIDL as the file
// name.
pathFileName = workingDir + uidl;
DataOutputStream dataOut =
new DataOutputStream(
new FileOutputStream(
pathFileName));
//Send a RETR command to begin the
// message retrieval process
outputStream.println(
"RETR " + msgNumber);
//Validate the response.
String retrResponse =
validateOneLine();
//Read the first line in the message from
// the pop3Server.
String msgLine = inputStream.readLine();
//Continue reading lines until a "." is
// encountered as the first char in a
// line. That signals the end of the
// msg.
while(!(msgLine.equals("."))){
//Write the line to the output file and
// read the next line. Insert newline
// characters when writing the output
// to the file.
dataOut.writeBytes(msgLine + "n");
msgLine = inputStream.readLine();
}//end while(!(msgLine.equals(".")
//Close the output file. The message is
// now stored in a local file with a file
// name based on the unique ID provided
// by the pop3Server.
dataOut.close();
//Show progress on the command-line
// screen
System.out.print(msgNumber + " ");
//Increment the message number in
// preparation for processing the next
// message.
msgNumber++;
}//end while(msgNumber <= numberMsgs)
System.out.println(
"nMessages downloaded");
//Terminate the session with the
// pop3Server.
System.out.println(
"nDisconnect from pop3Server.");
outputStream.println("QUIT");
String quitResponse = validateOneLine();
//Display the response on the
// command-line screen.
System.out.println("QUIT " + quitResponse);
System.out.println();//blank line
socket.close();
//Sound an alarm.
try{
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
}catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}//end catch
//All messages have been downloaded and
// saved as local files. Instantiate an
// object that will forward each of the
// messages to the specified email
// address.
new BigDog06forward(
params[0],//pop3Server
params[1],//userName
params[2],//password
params[3],//destinationAddress
params[4],//smtpServer
params[5],//workingDir
params[6],//archiveDir
params[7]);//fwdTag
}//end try
catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}//end catch
}//end fetchMsgs
//===========================================//
}//end class BigDog06fetch
//=============================================//
Listing 9
|
/*File BigDog06forward.java
Copyright 2005, R.G.Baldwin
Rev 08/17/05
DISCLAIMER: THIS PROGRAM IS PROVIDED TO YOU AT
NO COST. BY USING THIS PROGRAM TO PROCESS YOUR
EMAIL, YOU AGREE THAT YOU ARE USING IT AT YOUR
OWN RISK. THE AUTHOR OF THE PROGRAM, RICHARD G.
BALDWIN, ACCEPTS NO LIABILITY FOR ANY LOSS THAT
YOU MAY INCUR THROUGH THE USE OF THIS PROGRAM.
An object of this class is instantiated by an
object of the class named BigDog06fetch to
process a set of message files written by the
BigDog06fetch object.
This object tags messages with a tag defined by
the user as a command-line parameter to the
main method for the class named BigDog06fetch.
Then the object forwards the messages to a
destination email account that is specified as a
command-line parameter using an SMTP server that
is specified as a command-line parameter.
See additional comments at the beginning of
BigDog06fetch.java.
This program uses the DELE command to delete
messages from the POP3 server from which the
messages were originally downloaded. Deletion of
the messages from the server can be disabled for
test purposes by disabling a block of code before
compiling the program.
Certain portions of this program may have been
disabled for test purposes. Search for the word
disable to identify those portions.
Tested using JDK 1.5.0_01 under WinXP
************************************************/
import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.*;
//import java.awt.event.*;
import sun.net.smtp.SmtpClient;
class BigDog06forward{
//User-specific information is stored here.
// This information is provided in the form of
// constructor parameters.
//ID of the destination email account.
final String destinationAddress;
//An smtp server through which the user is
// authorized to send email messages.
final String smtpServer;
//Local folder where message files are stored
// awaiting processing.
final String workingDir;
//Local folder for archiving message files.
final String archiveDir;
//Tag that is prepended to the Subject line of
// the message before forwarding.
String fwdTag;
//Following are working variables used by the
// program for various purposes.
BufferedReader inputStream;
PrintWriter outputStream;
Socket socket;
String pathFileName;
Vector <String> msgToDelete =
new Vector<String>();
String uidl;
boolean okToDelete = false;
int msgNumber = 0;
String pop3Server;
String userName;
String password;
//===========================================//
//Constructor
BigDog06forward(final String pop3Server,
final String userName,
final String password,
final String destinationAddress,
final String smtpServer,
final String workingDir,
final String archiveDir,
final String fwdTag){
this.pop3Server = pop3Server;
this.userName = userName;
this.password = password;
this.destinationAddress = destinationAddress;
this.smtpServer = smtpServer;
this.workingDir = workingDir;
this.archiveDir = archiveDir;
this.fwdTag = fwdTag;
System.out.println("Forwarding messages:");
forwardMsgs();
deleteMsgs();
}//end constructor
//===========================================//
//Validate a one-line response.
//The purpose of this method is to confirm that
// the pop3Server returned +OK and not -ERR to
// the previous command.
//If +OK, the method returns the string
// returned by the pop3Server.
//If -ERR, the method displays the string
// returned by the pop3Server and terminates
// the session.
private String validateOneLine(){
try{
String response = inputStream.readLine();
if(response.startsWith("+OK")){
return response;
}else{
System.out.println(response);
//Terminate the session.
outputStream.println("QUIT");
socket.close();
System.out.println(
"Premature QUIT on -ERR");
System.exit(0);
}//end else
}catch(IOException e){
e.printStackTrace();
System.exit(0);
}//end catch
//The following return statement is requied
// to satisfy the compiler, but it can never
// be reached..
return "Make compiler happy";
}//end validateOneLine()
//===========================================//
//Method to move a file from its current
// location specified by pathFileName to a new
// location specified by archiveDir.
public void moveFile(String pathFileName,
String archiveDir){
String fileName = pathFileName.substring(
pathFileName.lastIndexOf('/') + 1);
String archiveDirFileName =
archiveDir + fileName;
boolean moved =
new File(pathFileName).renameTo(
new File(archiveDirFileName));
if(!moved)System.out.println(
"Unable to move " + new File(pathFileName)
+ "nto " + new File(archiveDirFileName));
}//end moveFile method
//===========================================//
//This method reads and saves lines of data
// from a file starting with the line that
// startsWith firstLine and ending with the
// line that startsWith lastLine.
//If firstLine is null, data is saved beginning
// with the first line in the file.
//If lastLine is null, data is saved to the end
// of the file.
//The lines of data from the file are saved by
// concatenating them into a single string with
// a newline inserted into the string at the
// end of each line.
//The name and path to the file is given by
// pathFileName.
public String readLines(String pathFileName,
String firstLine,
String lastLine){
StringBuffer strBuf = new StringBuffer();
try{
BufferedReader inDataMsg
= new BufferedReader(new FileReader(
pathFileName));
String data;
boolean isSave = false;
while((data = inDataMsg.readLine())
!= null){
if( ((firstLine == null) ||
(data.startsWith(firstLine))) &&
(isSave == false)){
isSave = true;
}//end if
if(isSave){
strBuf.append(data + "n");
}//end if
if((lastLine != null) &&
(data.startsWith(lastLine))){
break;//no need to read any more
}//end if
}//end while loop
inDataMsg.close();//Close file
}catch(Exception e){
e.printStackTrace();
System.exit(0);
}//end catch
return new String(strBuf);
}//end readLines
//===========================================//
//This method is used to construct an email
// message and send it to the
// destinationAddress.
public boolean forwardEmailMsg(
String destinationAddress,
String smtpServer,
String fwdTag,
String pathFileName){
StringBuffer message = new StringBuffer(
"No message found");
try{
//Pass a string containing the name of
// the smtp server as a parameter to the
// following constructor.
SmtpClient smtp =
new SmtpClient(smtpServer);
//Pass any valid email address to the
// from() method.
smtp.from(destinationAddress);
//Pass the email address of the
// destinationAddress to the to() method.
smtp.to(destinationAddress);
//Construct the message as a single
// StringBuffer object by concatenating
// all of the lines in the message file.
message = new StringBuffer(readLines(
pathFileName,null,null));
//Insert fwdTag in subject
message = message.insert(message.indexOf(
"Subject: ")+9,fwdTag);
//Get an output stream for the message
PrintStream msg = smtp.startMessage();
//Write the message into the output
// stream.
msg.println(new String(message));
//Close the stream and send the message
smtp.closeServer();
return true;
}catch( Exception e ){
e.printStackTrace();
System.out.println(
"while forwarding email");
//Sound an alarm.
try{
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
}catch(Exception ex){
System.out.println(ex);
}//end catch
//Return false to indicate that the msg
// was not successfully forwarded.
return false;
}//end catch
}//end forwardEmailMsg
//===========================================//
void forwardMsgs(){
//Get a directory listing
//The following code creates a directory
// listing containing only those files that
// begin with +OK.
//This is an anonymous implementation of a
// class that implements FilenameFilter.
String[] dirList =
new File(workingDir).list(
new FilenameFilter(){public boolean accept(
File dir,String name){
if(!(new File(dir,name).
isFile())) return false;
return name.startsWith("+OK");
}//end accept
}//end FilenameFilter
);//end list
//Now process the files in the directory
for(int msgCounter = 0;
msgCounter < dirList.length;
msgCounter++){
String fileName = dirList[msgCounter];
pathFileName = workingDir + fileName;
//Get the original message number used by
// the pop3Server to ID the msg.
String strMsgNumber =
fileName.substring(
fileName.indexOf(" "),
fileName.lastIndexOf(" ")).trim();
msgNumber = Integer.parseInt(strMsgNumber);
System.out.print("" + msgNumber + " ");
//This code forwards the message to the
// destination email account and adds the
// identification of the message to the
// list of messages scheduled for deletion
// from the pop3Server later. The third
// parameter can be used to tag the message
// to show that it was forwarded. This
// parameter is provided as a command-line
// parameter to the BigDog06fetch program.
// Just pass an empty string, "", if you
// don't want to tag it.
//Don't add the message to the deletion
// list if forwarding failed.
okToDelete = forwardEmailMsg(
destinationAddress,
smtpServer,
fwdTag,
pathFileName);
if(okToDelete){
msgToDelete.add(pathFileName);
}//end if
}//end for loop on directory length
//Sound an audio alert
try{
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
Toolkit.getDefaultToolkit().beep();
Thread.currentThread().sleep(500);
}catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}//end catch
}//end forwardMsgs
//===========================================//
void deleteMsgs(){
System.out.println(
"nDelete Msgs from POP3 server.");
//Get connected to the email pop3Server
int port = 110; //pop3 mail port
try{
//Get a socket, connected to the specified
// pop3Server on the specified port.
socket = new Socket(pop3Server,port);
//Get an input stream from the socket
inputStream = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
//Get an output stream to the socket
outputStream = new PrintWriter(
new OutputStreamWriter(
socket.getOutputStream()),true);
//Display the msg received from the
// pop3Server on the command-line screen
// immediately following connection.
String connectMsg = validateOneLine();
System.out.println(
"nConnected to pop3Server "
+ connectMsg);
//The communication process is now in the
// AUTHORIZATION state. Send the user name
// and password to the pop3Server.
outputStream.println("USER " + userName);
//Get response and confirm that the
// response was +OK and was not -ERR.
String userResponse = validateOneLine();
//Display the response on the command-line
// screen.
System.out.println("USER " + userResponse);
//Send the password to the pop3Server
outputStream.println("PASS " + password);
//Validate the pop3Server's response as
// +OK. Display the response in the
// process.
System.out.println("PASS "
+ validateOneLine());
}catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}//end catch
//Process the files in the msgToDelete
// collection and delete those messages from
// the email pop3Server.
System.out.println(
"nDeleting Msgs from POP3 server.");
for(int cnt = 0;
cnt < msgToDelete.size();cnt++){
pathFileName = msgToDelete.
elementAt(cnt);
String strMsgNumber = pathFileName.
substring(pathFileName.indexOf(" "),
pathFileName.lastIndexOf(" ")).trim();
int msgNumber = Integer.parseInt(
strMsgNumber);
//Deletion of a message from the pop3Server
// is accomplished by marking the message
// for deletion while in the TRANSACTION
// state. The message is actually deleted
// when the client sends a QUIT command to
// the pop3Server causing the pop3Server to
// enter the UPDATE state. If the program
// aborts prematurely before sending a QUIT
// command, marked messages are not deleted
// from the pop3Server.
//Mark the message for deletion.
/*
//Disable the following statement if you
// enable message deletion.
System.out.println(
"Message deletion disabled");
*/
//Disable this code to disable deletion of
// messages from the pop3Server
outputStream.println("DELE " + msgNumber);
//Validate the response and display
// progress. Will terminate on DELE ERR.
validateOneLine();
System.out.print(msgNumber + " ");
//Disable to here to disable deletion of
// messages from the pop3Server
//You can customize the program to either
// move the message files from the working
// directory into an archive directory, or
// to simply delete the message files from
// the working directory without saving
// them in an archive directory.
//To move message files to the archive
// directory, enable this block of code and
// disable the next block of code.
{//Start move block
moveFile(pathFileName,archiveDir);
}//End move block
/*
//To delete message files without saving
// them in an archive directory, enable
// this block of code and disable the
// previous block of code.
{//Start delete block
File file = new File(pathFileName);
boolean isDeleted = file.delete();
if(!isDeleted)System.out.println(
"Unable to delete " + file);
}//End delete block
*/
}//end for loop on msgToDelete.size()
System.out.println();//blank line
//Terminate the session with the pop3Server
// causing the marked messages to actually be
// deleted from the pop3Server.
System.out.println(
"Disconnect from POP3 server");
outputStream.println("QUIT");
String quitResponse = validateOneLine();
//Display the response on the command-line
// screen.
System.out.println("QUIT " + quitResponse);
//Server is now in the UPDATE mode. It will
// delete all files marked with the DELE
// command earlier in the execution of the
// program.
//Close the socket
try{
socket.close();
}catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}//end catch
System.out.println("Messages deleted "
+ "from pop3Server.");
}//end deleteMsgs
//===========================================//
}//end class BigDog06forward
//=============================================//
|
Copyright 2005, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
About the author
Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.



Solid state disks (SSDs) made a splash in consumer technology, and now the technology has its eyes on the enterprise storage market. Download this eBook to see what SSDs can do for your infrastructure and review the pros and cons of this potentially game-changing storage technology.