[ Team LiB ] Previous Section Next Section

Recipe 20.6 Handling Attachments from an Email Received in a Servlet

Problem

You want to read an email message and save any attachments from a servlet.

Solution

Use the JavaMail API and a special JavaBean to save the InputStreams from attached files to a specified folder.

Discussion

Accessing email usually involves authenticating a user with a POP account, then connecting with the mail server and downloading any email messages. Example 20-6 uses the Session , Store, Folder, and Message classes from the JavaMail API to download an array of Messages from a particular user's email account. However, the servlet in Recipe 20.4 was designed to deal only with Messages whose content was of type String (the return value of the Message.getContent( ) method).

If the Message's content is of type Multipart , then the process of handling attachments mirrors the peeling of an onion—more code is involved. Example 20-6 separates the email-related code into a JavaBean that can be used from a servlet. The bean's displayMessage( ) method tests the content of each Message. If the content is of type Multipart, then the code examines each contained BodyPart.

Picture a Multipart message type as a container. The container's headers are like any other email message's headers (but with different values). The container encloses BodyParts, which are like messages inside of messages. Some BodyParts represent the text message accompanying a Multipart email message. Other BodyParts represent the attached files, such as a Microsoft Word file or JPEG image.


If the BodyPart's content is a String, then the bean displays the text message. Otherwise, the bean assumes the BodyPart is an attached file; it saves the file to a special attachments folder. You're probably already familiar with the handleMessages( ) code, so you can skip to the displayMessage( ) method, which deals with saving any file attachments.

Example 20-6. A JavaBean that handles attachments and delivers a browser message
package com.jspservletcookbook;    

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

import javax.mail.*;
import javax.mail.internet.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class AttachBean  {

  /* NOT SHOWN: private bean fields (or, properties); default variables;
     and the sendMessage method
     See Example 20-2 */

  public AttachBean( ){}
     
   private void handleMessages(HttpServletRequest request,
       PrintWriter out) throws IOException, ServletException {
    
       /* get the user and password information for a POP
          account from an HttpSession object */

       HttpSession httpSession =  request.getSession( );
       String user = (String) httpSession.getAttribute("user");
       String password = (String) httpSession.getAttribute("pass");
       String popAddr = (String) httpSession.getAttribute("pop");
   
       Store popStore = null;
       Folder folder = null;
   
       if (! check(popAddr))
           popAddr = AttachBean.DEFAULT_SERVER;
    
       try {
   
           if ((! check(user)) || (! check(password)))
            throw new ServletException(
            "A valid username and password is required to check email.");
   
           Properties properties = System.getProperties( );
           Session session = Session.getDefaultInstance(properties);
           popStore = session.getStore("pop3");
           popStore.connect(popAddr, user, password);
           folder = popStore.getFolder("INBOX");
           if (! folder.exists( ))
               throw new ServletException(
                 "An 'INBOX' folder does not exist for the user.");
       
           folder.open(Folder.READ_ONLY);
           Message[] messages = folder.getMessages( );

           int msgLen = messages.length;
           if (msgLen == 0)
               out.println(
                 "<h2>The INBOX folder does not yet contain any " +
                 " email messages.</h2>");
  
           for (int i = 0; i < msgLen; i++){
      
               displayMessage(messages[i], out);
               out.println("<br /><br />");

           }//for
   
        } catch (Exception exc) {
    
            out.println(
            "<h2>Sorry, an error occurred while accessing " +
            "the email messages.</h2>");

            out.println(exc.toString( ));
        
        } finally {

            try{
            
               if (folder != null)
                   folder.close(false);
            
               if (popStore != null)
                  popStore.close( );
              
            } catch (Exception e) { }
       }
    }//handleMessages
    
        private void displayMessage(Message msg, PrintWriter out) 
        throws MessagingException, IOException{
        
        if (msg != null){
        
            /* get the content of the message; the message could
               be an email without attachments, or an email
               with attachments. The method getContent( ) will return an
               instance of 'Multipart' if the msg has attachments */

            Object o = msg.getContent( );
    
            if ( o instanceof String){
                
                //just display some info about the message content
                handleStringMessage(msg,(String) o, out);
          
            } else if ( o instanceof Multipart ) {
                
                //save the attachment(s) to a folder
                Multipart mpart = (Multipart) o;
                Part part = null;
                File file = null;
                FileOutputStream stream = null;
                InputStream input = null;
                String fileName = "";
              
                //each Multipart is made up of 'BodyParts' that
                //are of type 'Part'
                for (int i = 0; i < mpart.getCount( ); i++){
                  
                    part = mpart.getBodyPart(i);
                    Object partContent = part.getContent( );
                  
                    if (partContent instanceof String){
                        handleStringMessage(msg,(String) partContent,
                          out);
                   
                    }  else {//handle as a file attachment
                
                        fileName = part.getFileName( );
              
                        if (! check(fileName)){//default file name
                           fileName = "file"+
                               new java.util.Date( ).getTime( );}
                      
                        //write the attachment's InputStream to a file
                        file = new File( attachFolder +
                        System.getProperty("file.separator") + fileName);
                        stream = new FileOutputstream(file);
                        input = part.getInputStream( );
                        int ch;
                 
                        while ( (ch = input.read( )) != -1){
                           stream.write(ch);}
                    
                              input.close( ); 
                        out.println(
                          "Handled attachment named: "+
                              fileName+"<br /><br />");
                    }// if
                }//for

            }//else if instanceof multipart
 
        } else{
       
           out.println(
               "<h2>The received email message returned null.</h2>");
       
        }// if msg != null
         
    }//displayMessage
    
        private void handleStringMessage(Part part, String emailContent,
        PrintWriter out)  throws MessagingException {
    
      if (part instanceof Message){
          Message msg = (Message) part;
          if (msg.getFrom( )[0] instanceof InternetAddress){
         
              out.println("Message received from: " +
               ((InternetAddress) msg.getFrom( )[0]).getAddress( ) +
                 "<br />");
          }
             
              out.println(
                "Message content type: " + msg.getContentType( ) +
                  "<br />");
              out.println("Message content: " + emailContent +"<br />");
      }
    
    }
    
  private boolean check(String value){
    
      if(value == null || value.equals(""))
          return false;
            
      return true;

  }//check

/* NOT SHOWN: various 'setter' methods for the bean's properties
     See Example 20-2 */

}// AttachBean

Once the displayMessage( ) code identifies a BodyPart as an attached file, it receives the bytes that represent the file as an InputStream. A BodyPart implements the Part interface, which defines the method getInputStream( ). The code saves the file using the InputStream and the java.io.FileOutputStream class.

Example 20-7 shows the doGet( ) method of a servlet using com.jspservletcookbook.AttachBean.

Example 20-7. A servlet's doGet( ) method uses a JavaBean to deal with email attachments
  public void doGet(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>");
    
      AttachBean emailer = new AttachBean( );
      emailer.setSmtpHost("mail.attbi.com");
      emailer.setAttachFolder(getServletContext( ).getRealPath("/") + "attachments");
      emailer.handleMessages(request,out);
    
      out.println("</body></html>");

  }//doGet

Figure 20-2 shows the messages that the servlet (using the JavaBean) displays in a browser. The first email is a simple text message without attachments. The second email contains two attachments; its MIME type is multipart/mixed.

Figure 20-2. A servlet displays information about received attachments and messages
figs/jsjc_2002.gif

See Also

Sun Microsystem's JavaMail API page: http://java.sun.com/products/javamail/; 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.7 on adding attachments to an email message; Recipe 20.8 on reading an email's headers.

    [ Team LiB ] Previous Section Next Section