Advanced java code dealing with real world problems.

Thursday, September 10, 2009

Build a reliable email reader - Part 2

Here are the two supporting classes needed by the MailReader class. The first one is the Mailbox class that is used to hold all properties of a mailbox. You will need at least three properties to initialize an instance: pop3 server address, mailbox user name, and mailbox password. Use setters to override default values of other properties. Please notice that with Sun provider only the default folder name ("INBOX") is supported.
/*
 * blog/javaclue/javamail/Mailbox.java
 * 
 * Copyright (C) 2009 JackW
 * 
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with this library.
 * If not, see .
 */
package blog.javaclue.javamail;

import java.io.Serializable;

public class Mailbox implements Serializable {
 private static final long serialVersionUID = 826439429623556631L;

 private final String userId; 
 private final String userPswd;
 private final String host;

 private int port;
 private String protocol;
 private String folderName;
 private int messagesPerRead;
 private boolean useSsl;
 private int maxRetries;
 private int minimumWait; // in seconds
 private boolean isExchange;
 
 public Mailbox(String host, String userId, String userPswd) {
  this.host = host;
  this.userId = userId;
  this.userPswd = userPswd;
  initDefault();
 }
 
 void initDefault() {
  port = -1; // use protocol default port
  protocol = "pop3";
  folderName = "INBOX";
  messagesPerRead = 10;
  useSsl = false;
  maxRetries = -1;
  minimumWait = 5;
  isExchange = false;
 }

 public String getFolderName() {
  return folderName;
 }
 public void setFolderName(String folderName) {
  this.folderName = folderName;
 }
 public String getHost() {
  return host;
 }
 public int getMinimumWait() {
  return minimumWait;
 }
 public void setMinimumWait(int minimumWait) {
  this.minimumWait = minimumWait;
 }
 public int getPort() {
  return port;
 }
 public void setPort(int port) {
  this.port = port;
 }
 public String getProtocol() {
  return protocol;
 }
 public void setProtocol(String protocol) {
  this.protocol = protocol;
 }
 public int getMessagesPerRead() {
  return messagesPerRead;
 }
 public void setMessagesPerRead(int readPerPass) {
  this.messagesPerRead = readPerPass;
 }
 public int getMaxRetries() {
  return maxRetries;
 }
 public void setMaxRetries(int retryMax) {
  this.maxRetries = retryMax;
 }
 public String getUserId() {
  return userId;
 }
 public String getUserPswd() {
  return userPswd;
 }
 public boolean isUseSsl() {
  return useSsl;
 }
 public void setUseSsl(boolean useSsl) {
  this.useSsl = useSsl;
 }

 public boolean isExchange() {
  return isExchange;
 }

 public void setExchange(boolean isExchange) {
  this.isExchange = isExchange;
 }
}
The next class is the MailProcessor class which is used to process the email messages read by the MailReader. This is most likely the class you would customize when building your own back-end mail reader.
/*
 * blog/javaclue/javamail/MailProcessor.java
 * 
 * Copyright (C) 2009 JackW
 * 
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with this library.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package blog.javaclue.javamail;

import java.io.IOException;
import java.util.Date;

import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Part;

import org.apache.log4j.Logger;

/**
 * process email's handed over by MailReader class.
 * 
 * @author JackW
 */
public class MailProcessor {
 static final Logger logger = Logger.getLogger(MailProcessor.class);
 static final boolean isDebugEnabled = logger.isDebugEnabled();

 protected final String LF = System.getProperty("line.separator", "\n");
 private final Mailbox mailbox;
 
 private static final int MAX_BODY_SIZE = 150 * 1024; // 150KB
 private static final int MAX_CMPT_SIZE = 1024 * 1024; // 1MB
 private static final int MAX_TOTAL_SIZE = 10 * 1024 * 1024; // 10MB

 public MailProcessor(Mailbox mailbox) {
  this.mailbox = mailbox;
 }

 /**
  * process messages.
  * 
  * @param msgs -
  *            array of Messages.
  * @throws MessagingException
  * @throws IOException 
  */
 public void process(Message[] msgs) throws MessagingException, IOException {
  if (isDebugEnabled)
   logger.debug("Entering process() method...");
  for (int i = 0; i < msgs.length; i++) {
   if (msgs[i] != null && !msgs[i].isSet(Flags.Flag.SEEN)
     && !msgs[i].isSet(Flags.Flag.DELETED)) {
    processPart(msgs[i]);
    // message has been processed, delete it from mail box
    msgs[i].setFlag(Flags.Flag.DELETED, true);
   }
  }
 }

 /**
  * process message part
  * 
  * @param p -
  *            part
  * @throws MessagingException 
  * @throws IOException 
  */
 MessageBean processPart(Part p) throws IOException, MessagingException {
  Date start_tms = new Date();
  
  // parse the MimeMessage to MessageBean
  MessageBean msgBean = MessageBeanUtil.mimeToBean(p);
  
  // MailBox Host Address
  msgBean.setMailboxHost(mailbox.getHost());
  // MailBox User Id
  msgBean.setMailboxUser(mailbox.getUserId());
  
  // get message body
  String body = msgBean.getBody();

  // check message body and component size
  boolean msgSizeTooLarge = false;
  if (body.length() > MAX_BODY_SIZE) {
   msgSizeTooLarge = true;
   logger.warn("Message body size exceeded limit: " + body.length());
  }
  int totalSize = body.length();
  if (!msgSizeTooLarge && msgBean.getComponentsSize().size() > 0) {
   for (int i = 0; i < msgBean.getComponentsSize().size(); i++) {
    Integer objSize = (Integer) msgBean.getComponentsSize().get(i);
    if (objSize.intValue() > MAX_CMPT_SIZE) {
     msgSizeTooLarge = true;
     logger.warn("Message component(" + i + ") exceeded limit: " + objSize.intValue());
     break;
    }
    totalSize += objSize;
   }
  }
  if (!msgSizeTooLarge && totalSize > MAX_TOTAL_SIZE) {
   logger.warn("Message total size exceeded limit: " + totalSize);
   msgSizeTooLarge = true;
  }
  
  if (msgSizeTooLarge) {
   logger.error("The email message has been rejected due to its size");
   // XXX - add your code here to deal with it
  }
  else { // email size within the limit
   if (msgBean.getSmtpMessageId() == null) {
    logger.warn("SMTP Message-Id is null, FROM Address = " + msgBean.getFromAsString());
   }
   if (isDebugEnabled)
    logger.debug("Message read..." + LF + msgBean);
   // XXX: Add you code here to process the message ...
  }
  if (isDebugEnabled && msgBean.getAttachCount() > 0)
   logger.debug("Number of attachments receibved: " + msgBean.getAttachCount());

  long time_spent = new Date().getTime() - start_tms.getTime();
  if (isDebugEnabled)
   logger.debug("Msg from " + msgBean.getFromAsString() + " processed, " + time_spent);
  
  return msgBean;
 }
}

No comments:

Post a Comment

Followers

About Me

An IT professional with more than 20 years of experience in enterprise computing. An Audio enthusiast designed and built DIY audio gears and speakers.