19.2 Sending Email
Sending
messages is the most basic email need of a Java program. While email
clients like Eudora and mailing list managers like listproc are the
only common programs that receive messages, all sorts of programs
send messages. For instance, web browsers can submit HTML forms via
email. Security scanning tools like Satan can run in the background
and email their results to the administrator when
they're done. When the Unix cron program detects a
misconfigured crontab file, it emails the error
to the owner. Books & Writers runs a popular service that tracks
the sales rank of authors' books on Amazon.com and
notifies them periodically via email. A massively parallel
computation like the SETI@home project can submit individual results
via email. Some multiplayer games like chess can be played across the
network by emailing the moves back and forth (though this scheme
wouldn't work for faster-moving games like Quake or
even for speed chess). And these are just a few of the different
kinds of programs that send email. In today's wired
world, by far the simplest way to notify users of an event when
they're not sitting in front of the computer that
the program is running on is to send them email.The JavaMail API provides everything
programs need to send email. To send a message, a program follows
these eight simple steps:Set the mail.host property to point to the local
mail server.Start a mail session with the Session.getInstance() method.Create a new Message object, probably by
instantiating one of its concrete subclasses.Set the message's From: address.Set the message's To: address.Set the message's Subject:.Set the content of the message.Send the message with the Transport.send( )
method.The order of these steps is not especially rigid. For instance, steps
4 through 7 can be performed in any order. Individually, each of the
steps is quite simple.The first step is to set up the properties for the mail session. The
only property you have to set in order to send mail is
mail.host. This is configured as a
java.util.Properties object rather than an
environment variable. For example, this code fragment sets the
mail.host property to
mail.cloud9.net:
Properties props = new Properties( );Your programs will of course have to set this property to the name of
props.put("mail.host", "mail.cloud9.net");
your own mail server. These properties are used to retrieve a
Session object from the
Session.getInstance( ) factory method, like this:
Session mailConnection = Session.getInstance(props, null);The Session object represents an ongoing
communication between a program and one mail server. The second
argument to the getInstance( ) method,
null here, is a
javax.mail.Authenticator that will ask the user
for a password if the server requests one. We'll
discuss this more later in the section on password authentication.
Most of the time, you do not need to provide a username and password
to send email when using the local SMTP server, only to receive it.The Session object is used to construct a new
Message object:
Message msg = new MimeMessage(mailConnection);I specify the MimeMessage class in particular
since I know I'm sending Internet email. However,
this is the one place where I do explicitly choose a format for the
email message. In some cases, this may not be necessary if I can copy
the incoming message format instead.Now that I have a Message object, I need to set up
its fields and contents. The From: address and To: address will each
be javax.mail.internet.InternetAddress objects.
You can provide either an email address alone or an email address and
a real name:
Address bill = new InternetAddress("god@microsoft.com", "Bill Gates");
Address elliotte = new InternetAddress("elharo@metalab.unc.edu");The setFrom( ) method allows us to saywho's sending the message by setting the From:
header. There's no protection against forgery.
It's quite easy for me to masquerade as Bill Gates
at a (presumably) fictitious email address:
msg.setFrom(bill);The setRecipient() method is slightly more
complex. You not only have to specify the address that the message
will be sent to, but how that address is used; that is, as a To:
field, a Cc: field, or a Bcc: field. These are indicated by three
mnemonic constants of the Message.RecipientType
class:
Message.RecipientType.TOFor example:
Message.RecipientType.CC
Message.RecipientType.BCC
msg.setRecipient(Message.RecipientType.TO, elliotte);The subject is set as a simple string of text. For example:
msg.setSubject("You must comply.");The body is also set as a single string of text. However, along withthat text, you need to provide the MIME type of the text. The most
common type is text/plain. For example:
msg.setContent("Resistance is futile. You will be assimilated!",
"text/plain");Finally, the static Transport.send( ) methodconnects to the mail server specified by the
mail.host property and sends the message on its
way:
Transport.send(msg);Example 19-1 puts all these steps together into a
standalone program that sends the following message:
Date: Mon, 29 Nov 1999 15:55:42 -0500 (EST)I've shown this message in standard RFC 822 format
From: Bill Gates <god@microsoft.com>
To: elharo@metalab.unc.edu
Subject: You must comply.
Resistance is futile. You will be assimilated!
used for Internet email. However, that isn't
necessary. The main point is that you need to know the addressee
(
Example 19-1. Sending a very simple mail message
import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;
public class Assimilator {
public static void main(String[] args) {
try {
Properties props = new Properties( );
props.put("mail.host", "mail.cloud9.net");
Session mailConnection = Session.getInstance(props, null);
Message msg = new MimeMessage(mailConnection);
Address bill = new InternetAddress("god@microsoft.com",
"Bill Gates");
Address elliotte = new InternetAddress("elharo@metalab.unc.edu");
msg.setContent("Resistance is futile. You will be assimilated!",
"text/plain");
msg.setFrom(bill);
msg.setRecipient(Message.RecipientType.TO, elliotte);
msg.setSubject("You must comply.");
Transport.send(msg);
}
catch (Exception ex) {
ex.printStackTrace( );
}
}
}
19.2.1 Sending Email from an Application
Example 19-1 is a simple application that sends
a fixed message to a known address with a specified subject. Once you
see how to do this, it's straightforward to replace
the strings that give the message address, subject, and body with
data read from the command line, a GUI, a database, or some other
source. For instance, Example 19-2 is a very simple
GUI for sending email. Figure 19-1 shows the program
running. The mail code is all tied up in the
actionPerformed( ) method and looks very similar
to the main( ) method of Example 19-1. The big difference is that now the host,
subject, From: address, To: address, and text of the message are all
read from the GUI components at runtime rather than being hardcoded
as string literals in the source code. The rest of code is related to
setting up the GUI and has little to do with the JavaMail API.
Example 19-2. A graphical SMTP client
import javax.mail.*;This is far from an ideal program. The GUI could be more cleanly
import javax.mail.internet.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class SMTPClient extends JFrame {
private JButton sendButton = new JButton("Send Message");
private JLabel fromLabel = new JLabel("From: ");
private JLabel toLabel = new JLabel("To: ");
private JLabel hostLabel = new JLabel("SMTP Server: ");
private JLabel subjectLabel = new JLabel("Subject: ");
private JTextField fromField = new JTextField(40);
private JTextField toField = new JTextField(40);
private JTextField hostField = new JTextField(40);
private JTextField subjectField = new JTextField(40);
private JTextArea message = new JTextArea(40, 72);
private JScrollPane jsp = new JScrollPane(message);
public SMTPClient( ) {
super("SMTP Client");
Container contentPane = this.getContentPane( );
contentPane.setLayout(new BorderLayout( ));
JPanel labels = new JPanel( );
labels.setLayout(new GridLayout(4, 1));
labels.add(hostLabel);
JPanel fields = new JPanel( );
fields.setLayout(new GridLayout(4, 1));
String host = System.getProperty("mail.host", ");
hostField.setText(host);
fields.add(hostField);
labels.add(toLabel);
fields.add(toField);
String from = System.getProperty("mail.from", ");
fromField.setText(from);
labels.add(fromLabel);
fields.add(fromField);
labels.add(subjectLabel);
fields.add(subjectField);
Box north = Box.createHorizontalBox( );
north.add(labels);
north.add(fields);
contentPane.add(north, BorderLayout.NORTH);
message.setFont(new Font("Monospaced", Font.PLAIN, 12));
contentPane.add(jsp, BorderLayout.CENTER);
JPanel south = new JPanel( );
south.setLayout(new FlowLayout(FlowLayout.CENTER));
south.add(sendButton);
sendButton.addActionListener(new SendAction( ));
contentPane.add(south, BorderLayout.SOUTH);
this.pack( );
}
class SendAction implements ActionListener {
public void actionPerformed(ActionEvent evt) {
try {
Properties props = new Properties( );
props.put("mail.host", hostField.getText( ));
Session mailConnection = Session.getInstance(props, null);
final Message msg = new MimeMessage(mailConnection);
Address to = new InternetAddress(toField.getText( ));
Address from = new InternetAddress(fromField.getText( ));
msg.setContent(message.getText( ), "text/plain");
msg.setFrom(from);
msg.setRecipient(Message.RecipientType.TO, to);
msg.setSubject(subjectField.getText( ));
// This can take a non-trivial amount of time so
// spawn a thread to handle it.
Runnable r = new Runnable( ) {
public void run( ) {
try {
Transport.send(msg);
}
catch (Exception ex) {
ex.printStackTrace( );
}
}
};
Thread t = new Thread(r);
t.start( );
message.setText(");
}
catch (Exception ex) {
// I should really bring up a more specific error dialog here.
ex.printStackTrace( );
}
}
}
public static void main(String[] args) {
SMTPClient client = new SMTPClient( );
// Next line requires Java 1.3 or later. I want to set up the
// exit behavior here rather than in the constructor since
// other programs that use this class may not want to exit
// the application when the SMTPClient window closes.
client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.show( );
}
}
separated from the mailing code. And it would be better to bring up
an error dialog if something went wrong rather than just printing a
stack trace of the exception on System.err.
However, since none of that would teach us anything about the
JavaMail API, I leave it all as an exercise for the interested
reader.
Figure 19-1. A simple GUI mail program

19.2.2 Sending Email from an Applet
In terms of GUIs and the JavaMail API,
there's no difference between sending email from an
applet and an application. However, the browser's
security manager can get in your way. Like everything else in this
book, the JavaMail API can't get around the normal
restrictions on network connections from applets and other remotely
loaded code. An applet that wants to send email can still talk only
to the host the applet itself came from.Fortunately, however, many hosts that run web servers also run SMTP
servers. If this is the case, it's quite
straightforward for an applet to send email. The JavaMail API and the
Java Activation Framework on which it depends aren't
included with most browsers, but since they're
implemented in pure Java in the javax package,
browsers can download the necessary classes from the server. For
example, this APPLET element references not only
the applet's own code but also the
mail.jar and activation.jar
files for the JavaMail API and the Java Activation Framework,
respectively:
<APPLET CODE=SMTPApplet ARCHIVE="activation.jar,mail.jar"Example 19-3 is a simple applet that sends email. The
WIDTH=600 HEIGHT=400>
<PARAM NAME="to" VALUE="hamp@sideview.mtsterling.ky.us">
<PARAM NAME="subject" VALUE="Hay Orders">
<PARAM NAME="from" VALUE="noone">
</APPLET>
address to send email to and the subject are read from
PARAM tags. The address to send email from is also
read from a PARAM tag, but the user has the option
to change it. The text to send is typed into a text area by the user.
Finally, the server is determined by looking at the
applet's codebase.
Example 19-3. An applet that sends email
import java.applet.*;Figure 19-2 shows this applet running in Internet
import javax.mail.*;
import javax.mail.internet.*;
import java.util.Properties;
import java.awt.event.*;
import java.awt.*;
public class SMTPApplet extends Applet {
private Button sendButton = new Button("Send Message");
private Label fromLabel = new Label("From: ");
private Label subjectLabel = new Label("Subject: ");
private TextField fromField = new TextField(40);
private TextField subjectField = new TextField(40);
private TextArea message = new TextArea(30, 60);
private String toAddress = ";
public SMTPApplet( ) {
this.setLayout(new BorderLayout( ));
Panel north = new Panel( );
north.setLayout(new GridLayout(3, 1));
Panel n1 = new Panel( );
n1.add(fromLabel);
n1.add(fromField);
north.add(n1);
Panel n2 = new Panel( );
n2.add(subjectLabel);
n2.add(subjectField);
north.add(n2);
this.add(north, BorderLayout.NORTH);
message.setFont(new Font("Monospaced", Font.PLAIN, 12));
this.add(message, BorderLayout.CENTER);
Panel south = new Panel( );
south.setLayout(new FlowLayout(FlowLayout.CENTER));
south.add(sendButton);
sendButton.addActionListener(new SendAction( ));
this.add(south, BorderLayout.SOUTH);
}
public void init( ) {
String subject = this.getParameter("subject");
if (subject == null) subject = ";
subjectField.setText(subject);
toAddress = this.getParameter("to");
if (toAddress == null) toAddress = ";
String fromAddress = this.getParameter("from");
if (fromAddress == null) fromAddress = ";
fromField.setText(fromAddress);
}
class SendAction implements ActionListener {
public void actionPerformed(ActionEvent evt) {
try {
Properties props = new Properties( );
props.put("mail.host", getCodeBase( ).getHost( ));
Session mailConnection = Session.getInstance(props, null);
final Message msg = new MimeMessage(mailConnection);
Address to = new InternetAddress(toAddress);
Address from = new InternetAddress(fromField.getText( ));
msg.setContent(message.getText( ), "text/plain");
msg.setFrom(from);
msg.setRecipient(Message.RecipientType.TO, to);
msg.setSubject(subjectField.getText( ));
// This can take a non-trivial amount of time so
// spawn a thread to handle it.
Runnable r = new Runnable( ) {
public void run( ) {
try {
Transport.send(msg);
}
catch (Exception ex) {
ex.printStackTrace( );
}
}
};
Thread t = new Thread(r);
t.start( );
message.setText(");
}
catch (Exception ex) {
// We should really bring up a more specific error dialog here.
ex.printStackTrace( );
}
}
}
}
Explorer 4.0.1 on the Macintosh. I've been careful
to only use methods and classes available in Java 1.1 so this applet
runs across the most web browsers possible. I also avoided using
Swing so that there'd be one less large JAR file to
download. As it is, the mail.jar and
activation.jar files that this applet requires
take up almost 300K, more than I'm comfortable with,
but manageable on a fast connection.
Figure 19-2. The SMTP applet

stricter than the default.The mail.jar and
activation.jar files must be available in the
applet's codebase.The web server that serves the applet must also be an SMTP server
willing to relay mail from the client system to the receiver system.
These days, most open SMTP relays have been shut down to avoid abuse
by spammers, so this can be a sticking point. If it is,
you'll get an exception like this:
javax.mail.SendFailedException: 550 <hamp@sideview.mtsterling.ky.us>...However, you should at least be able to send email to addresses in
Relaying denied
the web server's domain. You may be able to set up
one of these addresses to automatically forward the messages to their
eventual recipient.
• Table of Contents• Index• Reviews• Reader Reviews• Errata• AcademicJava Network Programming, 3rd EditionBy
Elliotte Rusty Harold Publisher: O'ReillyPub Date: October 2004ISBN: 0-596-00721-3Pages: 706
Thoroughly revised to cover all the 100+ significant updates
to Java Developers Kit (JDK) 1.5, Java Network
Programming is a complete introduction to
developing network programs (both applets and applications)
using Java, covering everything from networking fundamentals
to remote method invocation (RMI). It includes chapters on
TCP and UDP sockets, multicasting protocol and content
handlers, servlets, and the new I/O API. This is the
essential resource for any serious Java developer.