Java Mail API
Java Mail API
Java Mail API
Tutorials
jGuru: Fundamentals of the JavaMail API
Short Course
By jGuru
This latter way is best when you need to send multiple messages, as it will keep the
connection with the mail server active between messages. The basic send() mechanism
makes a separate connection to the server for each method call.
Note: To watch the mail commands go by to the mail server, set the
debug flag with session.setDebug(true). Store and Folder
Getting messages starts similarly to sending messages, with a Session. However, after
getting the session, you connect to a Store, quite possibly with a username and
password or Authenticator. Like Transport, you tell the Store what protocol to use:
// Store store = session.getStore("imap");
Store store = session.getStore("pop3");
store.connect(host, username, password);
After connecting to the Store, you can then get a Folder, which must be opened before
you can read messages from it:
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
Message message[] = folder.getMessages();
For POP3, the only folder available is the INBOX. If you are using IMAP, you can have
other folders available.
Note: Sun's providers are meant to be smart. While Message
message[] = folder.getMessages(); might look like a slow operation
reading every message from the server, only when you actually need
to get a part of the message is the message content retrieved. Once you have a
Message to read, you can get its content with getContent() or write its content to a
stream with writeTo(). The getContent() method only gets the message content, while
writeTo() output includes headers.
System.out.println(((MimeMessage)message).getContent());
Once you're done reading mail, close the connection to the folder and store.
folder.close(aBoolean);
store.close();
The boolean passed to the close() method of folder states whether or not to update the
folder by removing deleted messages.
Moving On
Essentially, understanding how to use these seven classes is all you need for nearly
everything with the JavaMail API. Most of the other capabilities of the JavaMail API
build off these seven classes to do something a little different or in a particular way, like
if the content is an attachment. Certain tasks, like searching, are isolated, and are
discussed later.
Using the JavaMail API
You've seen how to work with the core parts of the JavaMail API. In the following
sections you'll find a how-to approach for connecting the pieces to do specific tasks.
Sending Messages
Sending an email message involves getting a session, creating and filling a message,
and sending it. You can specify your SMTP server by setting the mail.smtp.host
property for the Properties object passed when getting the Session:
String host = ...;
String from = ...;
String to = ...;
// Get session
Session session = Session.getDefaultInstance(props, null);
// Define message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject("Hello JavaMail");
message.setText("Welcome to JavaMail");
// Send message
Transport.send(message);
You should place the code in a try-catch block, as setting up the message and sending it
can throw exceptions.
Exercise
....
Sending Your First Message
Fetching Messages
For reading mail, you get a session, get and connect to an appropriate store for your
mailbox, open the appropriate folder, and get your message(s). Also, don't forget to
close the connection when done.
String host = ...;
String username = ...;
String password = ...;
// Get session
Session session = Session.getDefaultInstance(props, null);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
// Get directory
Message message[] = folder.getMessages();
// Close connection
folder.close(false);
store.close();
What you do with each message is up to you. The above code block just displays who
the message is from and the subject. Technically speaking, the list of from addresses
could be empty and the getFrom()[0] call could throw an exception.
To display the whole message, you can prompt the user after seeing the from and
subject fields, and then call the message's writeTo() method if they want to see it.
BufferedReader reader = new BufferedReader (
new InputStreamReader(System.in));
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i<n; i++) {
System.out.println(i + ": " + message[i].getFrom()[0]
+ "\t" + message[i].getSubject());
Exercise
Checking for Mail
Deleting Messages and Flags
Deleting messages involves working with the Flags associated with the messages.
There are different flags for different states, some system-defined and some user-
defined. The predefined flags are defined in the inner class Flags.Flag and are listed
below:
Flags.Flag.ANSWERED
Flags.Flag.DELETED
Flags.Flag.DRAFT
Flags.Flag.FLAGGED
Flags.Flag.RECENT
Flags.Flag.SEEN
Flags.Flag.USER
Just because a flag exists doesn't mean the flag is supported by all mail
servers/providers. For instance, besides deleting messages, the POP protocol supports
none of them. Checking for new mail is not a POP task but one built into mail clients.
To find out what flags are supported, ask the folder with getPermanentFlags().
To delete messages, you set the message's DELETED flag:
message.setFlag(Flags.Flag.DELETED, true);
Open up the folder in READ_WRITE mode first though:
folder.open(Folder.READ_WRITE);
Then, when you are done processing all messages, close the folder, passing in a true
value to expunge the deleted messages.
folder.close(true);
There is an expunge() method of Folder that can be used to delete the messages.
However, it doesn't work for Sun's POP3 provider. Other providers may or may not
implement the capabilities. It will more than likely be implemented for IMAP
providers. Because POP only supports single access to the mailbox, you have to close
the folder to delete the messages with Sun's provider.
To unset a flag, just pass false to the setFlag() method. To see if a flag is set, check with
isSet().
Authenticating Yourself
You previously learned that you can use an Authenticator to prompt for username and
password when needed, instead of passing them in as strings. Here you'll actually see
how to more fully use authentication.
Instead of connecting to the Store with the host, username, and password, you configure
the Properties to have the host, and tell the Session about your custom Authenticator
instance, as shown here:
// Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);
You then subclass Authenticator and return a PasswordAuthentication object from the
getPasswordAuthentication() method. The following is one such implementation, with
a single field for both. As this isn't a Project Swing tutorial, just enter the two parts in
the one field, separated by a comma.
import javax.mail.*;
import javax.swing.*;
import java.util.*;
Since the PopupAuthenticator relies on Swing, it will start up the event-handling thread
for AWT. This basically requires you to add a call to System.exit() in your code to stop
the program.
Replying to Messages
The Message class includes a reply() method to configure a new Message with the
proper recipient and subject, adding "Re: " if not already there. This does not add any
content to the message, only copying the from or reply-to header to the new recipient.
The method takes a boolean parameter indicating whether to reply to only the sender
(false) or reply to all (true).
MimeMessage reply = (MimeMessage)message.reply(false);
reply.setFrom(new InternetAddress("president@whitehouse.gov"));
reply.setText("Thanks");
Transport.send(reply);
To configure the reply-to address when sending a message, use the setReplyTo()
method.
Exercise
Replying to Mail
Forwarding Messages
Forwarding messages is a little more involved. There is no single method to call, and
you build up the message to forward by working with the parts that make up a message.
A mail message can be made up of multiple parts. Each part is a BodyPart, or more
specifically, a MimeBodyPart when working with MIME messages. The different body
parts get combined into a container called Multipart or, again, more specifically a
MimeMultipart. To forward a message, you create one part for the text of your message
and a second part with the message to forward, and combine the two into a multipart.
Then you add the multipart to a properly addressed message and send it.
That's essentially it. To copy the content from one message to another, just copy over its
DataHandler, a class from the JavaBeans Activation Framework.
// Create the message to forward
Message forward = new MimeMessage(session);
// Fill in header
forward.setSubject("Fwd: " + message.getSubject());
forward.setFrom(new InternetAddress(from));
forward.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
// Send message
Transport.send(forward);
When including attachments with your messages, if your program is a servlet, your
users must upload the attachment besides tell you where to send the message.
Uploading each file can be handled with a form encoding type of multipart/form-data.
<FORM ENCTYPE="multipart/form-data"
method=post action="/myservlet">
<INPUT TYPE="file" NAME="thefile">
<INPUT TYPE="submit" VALUE="Upload">
</FORM>
Note: Message size is limited by your SMTP server, not the JavaMail
API. If you run into problems, consider increasing the Java heap size
by setting the ms and mx parameters. Exercise
Sending Attachments
Getting Attachments
Getting attachments out of your messages is a little more involved then sending them,
as MIME has no simple notion of attachments. The content of your message is a
Multipart object when it has attachments. You then need to process each Part, to get the
main content and the attachment(s). Parts marked with a disposition of
Part.ATTACHMENT from part.getDisposition() are clearly attachments. However,
attachments can also come across with no disposition (and a non-text MIME type) or a
disposition of Part.INLINE. When the disposition is either Part.ATTACHMENT or
Part.INLINE, you can save off the content for that message part. Just get the original
filename with getFileName() and the input stream with getInputStream().
Multipart mp = (Multipart)message.getContent();
The saveFile() method just creates a File from the filename, reads the bytes from the
input stream, and writes them off to the file. In case the file already exists, a number is
added to the end of the filename until one is found that doesn't exist.
// from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++) {
file = new File(filename+i);
}
The code above covers the simplest case where message parts are flagged appropriately.
To cover all cases, handle when the disposition is null and get the MIME type of the
part to handle accordingly.
if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
// Handle plain
} else {
// Special non-attachment cases here of
// image/gif, text/html, ...
}
...
}
Exercise
Sending HTML Messages with Images
Searching with SearchTerm
The JavaMail API includes a filtering mechanism found in the javax.mail.search
package to build up a SearchTerm. Once built, you then ask a Folder what messages
match, retrieving an array of Message objects:
SearchTerm st = ...;
Message[] msgs = folder.search(st);
There are 22 different classes available to help you build a search term.
AND terms (class AndTerm)
OR terms (class OrTerm)
NOT terms (class NotTerm)
SENT DATE terms (class SentDateTerm)
CONTENT terms (class BodyTerm)
HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm,
SubjectTerm, etc.)
Essentially, you build up a logical expression for matching messages, then search. For
instance the following term searches for messages with a (partial) subject string of
ADV or a from field of friend@public.com. You might consider periodically running
this query and automatically deleting any messages returned.
SearchTerm st =
new OrTerm(
new SubjectTerm("ADV:"),
new FromStringTerm("friend@public.com"));
Message[] msgs = folder.search(st);
Resources
You can do much more with the JavaMail API than what's described here. The lessons
and exercises found here can be supplemented by the following resources:
JavaMail API Home
JavaBeans Activation Framework Home
javamail-interest mailing list
Sun's JavaMail FAQ
jGuru's JavaMail FAQ
Third Party Products List
Copyright 1996-2001 jGuru.com. All Rights Reserved.