Exploit JavaMail's SMTP and MBOX Support
Take a closer look at the JavaMail API's access to SMTP to receive mail and how to manage MBOX mailboxes
by Kevin Jones
Posted January 28, 2004
I introduced the JavaMail API in a previous article (see "JavaMail's Flexible Protocol Support," Java Pro Online, January 21, 2004) and explained how to use it to read mail from a POP3 server. In addition to receiving mail, JavaMail can also be used to send mail and to examine mailboxes, that is, e-mail that has been received and stored on the client. Here, let's look at how to send e-mail using Simple Mail Transfer Protocol (SMTP) and how to access MBOX mailboxes, a standard storage mechanism for many mail clients (see the sidebar, "Mail Protocols").
As you may imagine, SMTP access is a little different from POP3 access. You start the same way by accessing the Session, but then from there you create a Transport object and use that to connect to the server. Once you're connected you can create a message to send. The message contains the address you send to, the reply to address, the address of the sender (these may be different; for example, the reply to address may be the address of a list server), and the message itself. Different SMTP servers may work slightly differently; for example, SMTP servers today will typically stop relays, which means that the sender's or the receiver's address must be an address within the organization. Typically, this factor also means that the server will require authentication (see Listing 1). Notice that the mail.smtp.auth property has been set, which allows the application to authenticate to the server.
Now let's take a look at accessing messages that have already been stored on a client. While this example might seem unnecessary, it will also cover selecting a provider and processing a multipart message.
SMTP and POP3 access comes built into the JavaMail JDK; although, as mentioned previously they are not production quality. However, with MBOX we don't even have that luxury because different providers that do support the MBOX protocol have to be installed. Our code has to make sure that the appropriate provider is selected (the JavaMail specification defines how to install multiple providers). Luckily, each provider advertises the protocols it supports so the correct provider can be chosen:
Session session = Session.
getDefaultInstance(props);
Provider[] providers =
session.getProviders();
Provider provider = null;
for (int i = 0; i <
providers.length; i++)
{
Provider p = providers[i];
if(p.getProtocol().equals(
"mbox"))
provider = p;
}
You can also choose the provider based on the vendor and version information.
Once you have the provider, you then need to access the folder that contains the actual e-mails. Again there are various ways of doing this, and they all involve providing a URL to the folder. On my machine the Inbox folder is /home/kevinj/evolution/local/Inbox/mbox, and it can be accessed like this:
Store s = session.getStore(
provider);
Folder root = s.getFolder(
"/home/kevinj/evolution/local/
Inbox/mbox");
Once you have the folder you can then access the messages:
root.open(Folder.READ_ONLY);
Message[] messages =
root.getMessages();
for (int i = 0; i <
messages.length; i++)
{
// process messages
Message message = messages[i];
}
Each message now needs to be processed. The message processing would be the same whether the message is accessed from the MBOX store or as part of a POP3 download.
Getting the Message
A Message may consist of multiple parts, or it may consist of a single part. Each part is identified with a Multipart Internet Mail Extensions (MIME) type, and a multipart message will itself be tagged with the multipart MIME type. The data in a message is accessed with the Java Activation Framework, which provides a DataHandler class that is able to translate a MIME type to a Java object—for example, a DataHandler would turn a text/* MIME type into a java.lang.String.
If the message contains a single part, then accessing the data in a message is simply a matter of calling getContent():
if (message.getContentType().
startsWith("multipart") == true)
{
// process a multipart message
// shown later
}
else
{
Object content =
message.getContent();
System.out.println("content: "
+ content);
}
However, if the message is a multipart message, then each part has to be accessed separately:
MimeMultipart content =
(MimeMultipart) message.
getContent();
int count = content.getCount();
for (int j = 0; j < count; j++)
{
BodyPart b = content.
getBodyPart(j);
System.out.println(
"Description:" +
b.getDescription());
System.out.println(
"Disposition:" +
b.getDisposition());
System.out.println(
"File Name:" +
b.getFileName());
System.out.println(
"Line Count:" +
b.getLineCount());
System.out.println(
"Content Type:" +
b.getContentType());
// process content
}
Once you get each part, then each part can be accessed by calling getContent().
One other thing to be aware of is the use of JavaMail from more than one application within the same virtual machine. For example, there might be multiple Web applications within the same servlet container. The JavaMail Session object is used to manage authentication. To manage authentication, the client passes an Authenticator object to the Session. If no authenticator is passed, then a default authenticator is used. Subsequent calls to getDefaultInstance() check the authenticator passed to the authenticator stored in the default session. If the same class loader loads both authenticators, then the caller is allowed to use the default session. Passing null in both cases is a bad idea as it allows other clients access to the default session created by some other application.
Authenticator is an abstract class that has to be extended by an application. The JavaMail API provides a PasswordAuthentication class to help with the authentication:
session = Session.
getDefaultInstance(
props, new Authenticator(){
protected PasswordAuthentication
getPasswordAuthentication()
{
return new
PasswordAuthentication(
userName, password);
}
});
Transport trans = session.
getTransport("smtp");
trans.connect();
The JavaMail API is a provider-based API that allows access to different e-mail protocols. It provides an easy mechanism to read mail, either from a POP3 or IMAP server; to manage mailboxes; and to send mail using SMTP.
About the Author
Kevin Jones is a developer who has spent the last four years researching and teaching Java programming and most recently investigating HTTP and XML. Kevin lives in the U.K. and works for Developmentor, a training company based in the United States and Europe that specializes in technical training on Java and Microsoft platforms. Contact Kevin at .
|