text: One you program in Java, the JavaMail API is most commonly used to do the dirty work of connecting to the mail server and sending the message. Unfortunately, it's kind of ponderous to use (mainly due to the flexibility of email), so if you're going to use it more than once, it generally makes sense to write a wrapper for it. Depending on how you use it, the wrapper may be written to send one specific kind of email, such as a password reminder, or to work generically, accepting the subject, recipients, and body of the email as arguments.
  Once you have a wrapper for actually sending mail, you need a system for constructing the messages themselves. Let's look at password reminders. Nearly all email messages have a subject, body, and recipients..
  Here's a quick list of reasons why property files are suboptimal for storing strings to be used in email messages:
  To:field and three in the
  Cc:field. You can't easily do that using property files.
  \n..
  Let's look at the format for the email template itself. The templates are
  XML files that contain only a root element and children of that element. The
  root element is
  <subject>,
  <body>, and
  <from>. The optional elements are
  <to>,
  <cc>, and
  <bcc>. If you've used an email
  client at all, you can deduce what each of these elements should contain. There
  can be multiple instances of the optional elements, so that you can include
  multiple addresses for each type of recipient. I'll explain how this works when
  I describe how the message is processed. Here's an example template file:
  <email> <from>rafe@rafe.us</from> <to>someone@example.com</to> <cc>someoneelse@example.com</cc> <bcc>rafe@rafe.us</bcc> <subject>This is the subject</subject> <body>This is the body of an email message.</body> </email>
  One useful feature provided by property files is that you can use the
  MessageFormat class to substitute placeholders in your properties
  with values that are passed in at runtime. For example, if you are putting
  errors in a property file and one of the errors is
  file not found,
  you can write the property like this:
  file.not.found.error=Error, could not find file {0}.
  Then, at runtime, you can use
  MessageFormat as follows:
  ResourceBundle bundle = ResourceBundle.getBundle( "MyProperties", currentLocale); Object[] arguments = { "some_file.txt" }; String newString = MessageFormat.format( bundle.getString("file.not.found.error"), arguments);
  At the end,
  newString will contain
  Error, could not find
  file some_file.txt. I've built similar flexibility into this system. The
  MessageFormat can format any string, so you can embed the same
  tokens that can be used in a property file into the
  subject and
  body elements of your email template.
  In some cases, you'll want to insert personalized information into your
  templates when the email is sent. For example, you might want to include the
  recipient's first name in the email, or perhaps the details of their order.
  This system handles these situations by processing the body and subject of the
  MessageFormat. The catch is that it accepts
  only one array of arguments that are applied to both the subject and the body.
  So the subject could contain tokens
  {0},
  {2}, and
  {3}, and the body could contain tokens
  {0},
  {1}, and
  {4}. I took this approach because in many
  cases, the same arguments are used in both the body and the subject and it
  simplifies the parameter list that's passed in to the
  Once you've created your template, the next step is to process it. As you probably know, there are many XML processing libraries to choose from. Commons Digester, part of the Jakarta Commons project, was originally created as part of the Struts project in order to provide a quick and easy way to parse the Struts configuration file. It provides an easy way to map the elements in the XML file to a data structure using syntax similar to XPath. The advantage is that it enables you to pluck needed elements out of an XML document without parsing it node-by-node using SAX or dealing with the treelike data structure provided by the DOM.
  Here's the method that reads the data from the XML file and copies it into
  an
  public static EmailTemplate getEmailTemplate(InputStream aStream) { Digester digester = new Digester(); digester.setValidating(false); digester.addObjectCreate("email", EmailTemplate.class); digester.addBeanPropertySetter("email/subject", "subject"); digester.addBeanPropertySetter("email/body", "body"); digester.addBeanPropertySetter("email/from", "from"); digester.addCallMethod("email/to", "addTo", 0); digester.addCallMethod("email/cc", "addCc", 0); digester.addCallMethod("email/bcc", "addBcc", 0); try { return (EmailTemplate)digester.parse(aStream); } catch (IOException e) { logger.error("Error: ", e); return null; } catch (SAXException e) { logger.error("Error: ", e); return null; } }
  Let's look at the example line by line. The way Commons Digester works is
  that you set up some rules to apply to the file to be parsed. Before I set up
  my processing rules, I set the validating flag on the digester to false,
  because there's no DTD to validate the email template against. To begin
  processing the file, I instantiate the
  Digester object and then
  call methods to set up the data mapping rules. First, I call the
  addObjectCreate() method, which sets up a rule to create an
  For elements that only appear once in the template file, I use the
  addBeanPropertySetter() method. It accepts two arguments, the path
  to an element to match and the setter to call. In the first call, I indicate
  that the values in elements that match the pattern
  should be passed in to the
  subject setter of the
  elements to search for, separated by slashes. In this case, the pattern matches
  subject elements that are children of
  For elements that can occur multiple times in the template file, calling the
  setter method for the property won't work. Instead, I use the
  addCallMethod() rule, which takes the value in the element and
  calls the specified method. I use the version of this method that takes three
  arguments: the pattern to match, the method to call, and the number of
  arguments the method being called takes. In all three cases, I pass in
  0 as the third argument, which indicates that the body of the
  matched element is the only argument that should be passed to the method being
  called. In the
  addTo(),
  addCc(), and
  addBcc(), which
  add the recipients listed in the template file to collections in the template
  class.
  Once the rules have been set up for the six types of children of the email
  element, I'm ready to parse the file. In this case, I pass in the
  InputStream that the
  getEmailTemplate method accepts
  as an argument. The
  parse method can accept a
  File, a
  SAX
  InputSource, an
  InputStream, a
  Reader, or a URI as the target for the file to parse. I chose an
  InputStream in this case. It's up to the calling code to fetch the
  XML file and turn it into an
  InputStream. To write this in a more
  generic way, I could have set up this method to accept an
  Object
  and used the
  instanceof operator inside to verify that the
  argument is one of the types of arguments accepted by the
  parse
  method and then call it appropriately.
  The
  parse method can throw an
  IOException or a
  SAXException. Those are handled by passing the exception off to a
  Log4J logger, and then returning null. If no exceptions occur, then the new
  Digester is
  returned.
  The meat of the
  getEmailTemplate() method. The rest is just properties and
  convenience methods. It has three
  String properties: the body,
  subject, and from address, and three
  ArrayList properties: the to,
  CC, and BCC lists, all of which will contain strings as members. There are
  getters and setters for those properties, as well as "add" methods for the
  collections. There are three additional convenience methods:
  getToAddresses(),
  getCcAddresses(), and
  getBccAddresses(). The JavaMail API expects that you'll pass in
  addresses as old-fashioned arrays of
  InternetAddress objects.
  These methods convert the
  ArrayLists of
  String
  objects into the arrays required by JavaMail.
  Once the template file is parsed and is an
  object, the next step is to send the email message. The
  sendEmail(). It can be called in a number of different ways, all
  of which are shortcuts to the full method signature:
  public static void sendEmail( String aTo, EmailTemplate aTemplate, String[] aArgs)
  The arguments don't require much explanation. The first is a
  To
  address for the email. You can include recipient addresses in your email
  templates, but in many cases, the system will need to specify a recipient at
  runtime. For example, if you're sending a password reminder, it needs to go to
  the email address of the user requesting the password. The recipient addresses
  in the email template are for cases where the system needs to send an email to
  a hardcoded address or needs to include certain hardcoded recipients for
  testing. For example, suppose a system needs to generate an email that triggers
  a workflow every time an order is submitted — the hardcoded address in
  the template is useful in those situations.
  The second argument is the
  the list of arguments that will be passed to
  MessageFormat when it
  parses the subject and body of the email. It's up to the calling code to create
  the array of information used to personalize the email template. There are also
  several other method declarations that simplify calling this method (so that
  you can call it without specifying a recipient, or without arguments).
  The body of the
  sendEmail() method mostly consists of calls to
  set up sending the message using JavaMail. I talked about the fact that there
  was a lot of overhead when it comes to using JavaMail, and now you see what I
  meant. First, I check to make sure that the
  null. If it is, there's nothing I can do. The first step in
  setting up is creating a
  Properties object (a glorified
  Hashtable) with the SMTP server set. In my configuration, I have
  the SMTP server setting in a properties file, so I read it from the properties
  file and put it in the properties object I created.
  I then create a JavaMail
  Session object and pass in the
  Properties object. The
  Session object is needed to
  create the
  MimeMessage object, which I do next. Then I set the
  From: address to the address specified in the
  EmailTemplate object that I passed in as an argument. The next
  step is to set the
  To: field for the message I'm constructing.
  There are some gymnastics here because the user can pass in a
  To:
  address and the template can also contain any number of
  To: addresses. The
  problem here is that JavaMail likes to use arrays for lists of addresses, so
  it's up to me to determine how large the list of recipients is and construct
  the array to pass in. Once I've created an array of recipients that includes
  the argument to the method (if it's not
  null) and the recipients
  in the template, I set it on the
  MimeMessage object.
  Since all
  CC: and
  BCC: addresses must be specified
  within the template, handling them is more straightforward. I simply use the
  convenience methods in the
  additional recipients to the message. As I mentioned earlier, I use
  MessageFormat to apply any arguments supplied with the method call
  to the subject and body. Once I've done so, I copy the new subject into the
  message object. I do the same thing with the message body. All that's left at
  that point is to call
  Transport.send() and pass in the
  MimeMessage object.
  Now that I've explained how the system works, I'll explain how to use it from a servlet, though it will work similarly in any real program. Here's the code:
  // Grab the email template. InputStream template = getServlet() .getServletConfig() .getServletContext() .getResourceAsStream( "/WEB-INF/email/registrationNotification.xml"); EmailTemplate notification = EmailTemplate.getEmailTemplate(template); // Create the section of the email containing the actual user data. String[] args = { "Rafe" }; EmailSender.sendEmail("rafe@rafe.us", notification, args);
  The first step in using this system is to turn your XML template file into
  an
  InputStream. Because I'm using a servlet, I fetch the file from
  the
  ServletContext. There are other ways to get the file, but in a
  servlet environment, this one works well. Then all I have to do is pass the
  InputStream off to the
  Next, I just set up my array of arguments for customizing the email and call
  the
  There are a number of enhancements that can be made to this system. Two
  obvious improvements are the ability to support both HTML and plaintext email,
  and the ability to include attachments with the email messages. To create these
  kinds of messages, the
  javax.mail.MimeMultipart message type is
  used. There's also the issue of where to store and how to specify attachments.
  In my system, I handle adding the attachments outside of the context of the
  template file, because my attachments are generated at the time the email is
  sent.
  Rafe Colburn is a Java developer and computer book author, and has written on Perl, CGI programming, HTML, and Java.
  Return to ONJava.com.