[ Team LiB ] Previous Section Next Section

Recipe 20.7 Adding Attachments to an Email in a Servlet

Problem

You want to build an email message with attachments in a servlet.

Solution

Use the JavaMail API for basic email messaging, and the the JavaBeans Activation Framework (JAF) to generate the file attachments.

Discussion

The JAF classes provide fine-grained control over setting up a file attachment for an email message.

If you are using both the JavaMail API and the JAF, make sure to import the packages in your servlet class:

import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;

//class definition continues

The sendMessage( ) method in Example 20-8 creates a new email message (specifically, a new javax.mail.internet.MimeMessage), adds its text message, and inserts a file attachment inside the message. The method then sends the message using the code you may have seen in Recipe 20.2 and Recipe 20.3:

Transport.send(mailMsg);

To accomplish this, the code creates a container (a javax.mail.Multipart object) and two javax.mail.BodyParts that make up the the container. The first BodyPart is a text message (used usually to describe the file attachment to the user), while the second BodyPart is the file attachment (in this case, a Microsoft Word file). Then the code sets the content of the MimeMessage to the Multipart. In a nutshell, the MimeMessage (an email message) contains a Multipart, which itself is composed of two BodyParts: the email's text message and an attached file.

If you want to look at the headers of a MimeMessage that contains attachments, call the getAllHeaders( ) method on the MimeMessage. See Recipe 20.8 for details.


Example 20-8. Making email attachment in a servlets
package com.jspservletcookbook;    

import java.io.*;
import java.util.Properties;

import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class EmailAttachServlet extends HttpServlet {

   //default value for mail server address, in case the user 
   //doesn't provide one
   private final static String DEFAULT_SERVER = "mail.attbi.com";

  public void doPost(HttpServletRequest request, 
    HttpServletResponse response) throws ServletException,
      java.io.IOException {
    
      response.setContentType("text/html");
      java.io.PrintWriter out = response.getWriter( );
      out.println(
        "<html><head><title>Email message sender</title></head><body>");
     
      String smtpServ = request.getParameter("smtp");
      if (smtpServ == null || smtpServ.equals(""))
        smtpServ = DEFAULT_SERVER;
      String from = request.getParameter("from");
      String to = request.getParameter("to");
      String subject = request.getParameter("subject");

      try {
          sendMessage(smtpServ, to, from, subject);
      } catch (Exception e) {
          throw new ServletException(e.getMessage( )); 
      }
      out.println(
        "<H2>Your attachment has been sent.</H2>");
      out.println("</body></html>");

  }//doPost
     
  public void doGet(HttpServletRequest request, 
    HttpServletResponse response) throws ServletException,
        java.io.IOException {
          
      doPost(request,response);
          
  }//doGet
     
  private void sendMessage(String smtpServ, String to, String from,
    String subject) throws Exception {
     
      Multipart multipart = null;
      BodyPart bpart1 = null;
      BodyPart bpart2 = null;

      Properties properties = System.getProperties( );

      //populate the 'Properties' object with the mail
      //server address, so that the default 'Session'
      //instance can use it.
      properties.put("mail.smtp.host", smtpServ);

      Session session = Session.getDefaultInstance(properties);
      Message mailMsg = new MimeMessage(session);//a new email message
      InternetAddress[] addresses = null;
    
      try {
   
          if (to != null) {
        
              //throws 'AddressException' if the 'to' email address
              //violates RFC822 syntax
              addresses = InternetAddress.parse(to, false);

              mailMsg.setRecipients(Message.RecipientType.TO, addresses);
        
          } else {
              throw new MessagingException(
                "The mail message requires a 'To' address.");
          }

          if (from != null) {
              mailMsg.setFrom(new InternetAddress(from));
          } else {
        
              throw new MessagingException(
                "The mail message requires a valid 'From' address.");
          } 
        
          if (subject != null)
            mailMsg.setSubject(subject);
        
          //This email message's content is a 'Multipart' type
          //The MIME type for the message's content is 'multipart/mixed'
          multipart = new MimeMultipart( );
        
          //The text part of this multipart email message
          bpart1 = new MimeBodyPart( );

          String textPart = 
          "Hello, just thought you'd be interested in this Word file.";
        
          // create the DataHandler object for the text part
          DataHandler data = new DataHandler(textPart, "text/plain");
        
          //set the text BodyPart's DataHandler
          bpart1.setDataHandler(data);
        
          //add the text BodyPart to the Multipart container
          multipart.addBodyPart( bpart1);

          //create the BodyPart that represents the attached Word file
          bpart2 = new MimeBodyPart( );

          //create the DataHandler that points to a File
          FileDataSource fds = new FileDataSource( new File(
          "h:/book/chapters/chap1/chap1.doc") );
        
          //Make sure that the attached file is handled as
          //the appropriate MIME type: application/msword here
          MimetypesFileTypeMap ftm = new MimetypesFileTypeMap( );
        
          //the syntax here is the MIME type followed by
          //space separated extensions
          ftm.addMimeTypes("application/msword doc DOC" );
        
          fds.setFileTypeMap(ftm);
          //The DataHandler is instantiated with the
          //FileDataSource we just created
          DataHandler fileData = new DataHandler( fds );

          //the BodyPart will contain the word processing file
          bpart2.setDataHandler(fileData);
        
          //add the second BodyPart, the one containing the attachment, to
          //the Multipart object
          multipart.addBodyPart( bpart2 );
        
          //finally, set the content of the MimeMessage to the
          //Multipart object
          mailMsg.setContent( multipart );
         
          // send the mail message; throws a 'SendFailedException' 
          //if any of the message's recipients have an invalid adress
          Transport.send(mailMsg);

        
      } catch (Exception exc) {
    
          throw exc;
        
      }//try

  }//sendMessage

}//EmailAttachServlet

The comments in Example 20-8 explain what happens when you use the javax.activation classes to create a file attachment of the intended MIME type. The most confusing part is creating a javax.activation.FileDataSource that points to the file that you want to attach to the email message. The code uses the FileDataSource to instantiate the javax.activation.DataHandler, which is responsible for the content of the file attachment.

//create the DataHandler that points to a File
FileDataSource fds = new FileDataSource( new File(
  "h:/book/chapters/chap1/chap1.doc") );

Make sure that the MimeMessage identifies the attached file as a MIME type of application/msword, so that the user's email application can try to handle the attachment as a Microsoft Word file. Set the FileTypeMap of the FileDataSource with the following code:

//Make sure that the attached file is handled as
//the appropriate MIME type: application/msword here
MimetypesFileTypeMap ftm = new MimetypesFileTypeMap( );
        
//the syntax here is the MIME type followed by
//space separated extensions
ftm.addMimeTypes("application/msword doc DOC" );
        
fds.setFileTypeMap(ftm);

A MimetypesFileTypeMap is a class that associates MIME types (like application/msword) with file extensions such as .doc.

Make sure you associate the correct MIME type with the file that you are sending as an attachment, since you explicitly make this association in the code. See http://java.sun.com/j2ee/1.4/docs/api/javax/activation/MimetypesFileTypeMap.html for further details.


Then the code performs the following steps:

  1. Creates a DataHandler by passing this FileDataSource in as a constructor parameter.

  2. Sets the content of the BodyPart with that DataHandler.

  3. Adds the BodyPart to the Multipart object (which in turn represents the content of the email message).

See Also

Sun Microsystem's JavaMail API page: http://java.sun.com/products/javamail/; the JAF web page: http://java.sun.com/products/javabeans/glasgow/jaf.html; Recipe 20.1 on adding JavaMail-related JARs to your web application; Recipe 20.2 on sending email from a servlet; Recipe 20.3 on sending email using a JavaBean; Recipe 20.4 covering how to access email in a servlet; Recipe 20.5 on accessing email with a JavaBean; Recipe 20.6 on handling attachments in a servlet; Recipe 20.8 on reading an email's headers.

    [ Team LiB ] Previous Section Next Section