пятница, 18 сентября 2009 г.

JavaMail в пивном соусе. Работа с содержанием и атачами письма.

Для работы с почтовиком необходимо уметь две вещи:
1. Получать и отправлять письма
2. Обрабатывать полученные письма.
Про работу с первый пунктом я уже писал в статье "Несколько мгновений JavaMail + Gmail", сейчас же хотел рассказать как же обрабатывать полученные письма.


Ничего сложного в обработке писем нет, но для начала опишем пару классов, которые будет использовать для передачи информации в другие модули программы.

EFile.java - класс описывающий файл
/**
* Класс описывающий файл
*/
public class EFile {

public EFile() {
}

public EFile(String fileName, String mimeType) {
this.fileName = fileName;
this.mimeType = mimeType;
}

public EFile(String fileName) {
this.fileName = fileName;
}

private String fileName;
private byte[] content = null;
private String mimeType;

/**
* Устанавливает содержание файла
* @param content - содержание файла
*/
public void setContent(byte[] content) {
this.content = content;
}

/**
* Возвращает содержание файла
* @return - содержание файла
* @throws IOException
*/
public byte[] getContent() throws IOException {
return content;
}

/**
* Устанавливает Mime тип файла
* @param mimeType - Mime тип файла
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}

/**
* Возвращает Mime тип файла
* @return - Mime тип файла
*/
public String getMimeType() {
return mimeType;
}

/**
* Устанавливает название файла
* @param fileName - название файла
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}

/**
* Возвращает название файла
* @return - название файла
*/
public String getFileName() {
return fileName;
}
}


EMailType - флаги письма
/**
* Флаги письма
*/
public enum EMailType {
/**
* Ответ
*/
Answered,
/**
* Удален
*/
Deleted,
/**
* Черновик
*/
Draft,
/**
* Помечен
*/
Flagged,
/**
* Новый
*/
Recent,
/**
* Просмотренный
*/
Seen
}


EMail.java - класс описывающий письмо
/**
* Класс описывающий письмо
*/
public class EMail extends Object {

public EMail() {
attachedFile = new ArrayList<efile>();
}

private String content;
private List<efile> attachedFile;
private EMailType emailType;
private List<string> from;
private List<string> to;
private String subject;
private Date sendDate;
private String messageId;
private String references;

private String replyContent;
private EFile replyFile;
private Boolean isValid;
private String xMailer;

/**
* Устанавливает флаг письма
* @param emailType - флаг письма
*/
public void setEmailType(EMailType emailType) {
this.emailType = emailType;
}
/**
* Возвращает флаг письма
* @return - флаг письма
*/
public EMailType getEmailType() {
return emailType;
}

/**
* Устанавливает список прикрепленных файлов
* @param attachedFile - список прикрепленных файлов
*/
public void setAttachedFile(List<efile> attachedFile) {
this.attachedFile = attachedFile;
}
/**
* Возвращает список прикрепленных файлов
* @return - список прикрепленных файлов
*/
public List<efile> getAttachedFile() {
return attachedFile;
}

/**
* Устанавливает список отправителей
* @param from - список отправителей
*/
public void setFrom(List<string> from) {
this.from = from;
}
/**
* Возвращает список отправителей
* @return - список отправителей
*/
public List<string> getFrom() {
return this.from;
}

/**
* Устанавливает список получателей
* @param to - список получателей
*/
public void setTo(List<string> to) {
this.to = to;
}
/**
* Возвращает список получателей
* @return - список получателей
*/
public List<string> getTo() {
return to;
}

/**
* Устанавливает тему письма
* @param subject - тема письма
*/
public void setSubject(String subject) {
this.subject = subject;
}
/**
* Возвращает тему письма
* @return - тема письма
*/
public String getSubject() {
return subject;
}

/**
* Устанавливает дату отправки письма
* @param sendDate - дата отправки письма
*/
public void setSendDate(Date sendDate) {
this.sendDate = sendDate;
}
/**
* Возвращает дату отправки письма
* @return - дата отправки письма
*/
public Date getSendDate() {
return sendDate;
}

/**
* Устанавливает содержание письма
* @param content - содержание письма
*/
public void setContent(String content) {
this.content = content;
}
/**
* Возвращает содержание письма
* @return - содержание письма
*/
public String getContent() {
return content;
}

/**
* Устанавливает идентификатор письма
* @param messageId - идентификатор письма
*/
public void setMessageId(String messageId) {
this.messageId = messageId;
}
/**
* Возвращает идентификатор письма
* @return - идентификатор письма
*/
public String getMessageId() {
return messageId;
}

/**
* Устанавливает ссылки на связанные письма
* @param references - ссылки на связанные письма
*/
public void setReferences(String references) {
this.references = references;
}
/**
* Возвращает ссылки на связанные письма
* @return - ссылки на связанные письма
*/
public String getReferences() {
return references;
}
}


Обработка входящих писем


Для обработки входящих писем воспользуемся следующим кодом:
/**
* Обработка части письма
* 
* @param email - объект EMail, который заполняеться из письма
* @param m - Часть письма
* @param level - Уровень структуры письма
* @throws MessagingException
* @throws IOException
*/
private static void ProcessingPart(EMail email, Part m, Integer level)
throws MessagingException, IOException {
if (m instanceof Message)
ProcessingInfoPart(email, (Message) m);

String filename = m.getFileName();

if ((filename == null || filename == "") && m.isMimeType("text/plain")) {
// Текст сообщения
email.setContent((String) m.getContent());
} else if (m.isMimeType("multipart/*")) {
// Рекурсивный разбор иерархии
Multipart mp = (Multipart) m.getContent();
level++;
int count = mp.getCount();
for (int i = 0; i < count; i++) {
ProcessingPart(email, mp.getBodyPart(i), level);
}
} else if (m.isMimeType("message/rfc822")) {
// Вложенное сообщение
level++;
ProcessingPart(email, (Part) m.getContent(), level);
level--;
}

if (level != 0 && !m.isMimeType("multipart/*") && filename != null) {
// Сохранения атачей
String disp = m.getDisposition();
// many mailers don't include a Content-Disposition
if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT)) {

List<efile> efiles = email.getAttachedFile();
InputStream in = null;
try {
in = ((MimeBodyPart) m).getInputStream();
byte[] content = DataUtil.GetBytesFromStream(in);

EFile efile = new EFile();
efile.setContent(content);
efile.setMimeType(((MimeBodyPart) m).getContentType());
efile.setFileName(MimeUtility.decodeText(filename));
efiles.add(efile);
} catch (IOException ex) {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
}
}
}

/**
* Обработка информационной части письма
* 
* @param email - объект для сохранения email
* @param m - входящий объект письма
* @throws MessagingException
* @throws UnsupportedEncodingException
*/
private static void ProcessingInfoPart(EMail email, Message m)
throws MessagingException, UnsupportedEncodingException {

// Обработка основных параметров письма
AddAddress(m.getFrom(), email, false, true);
AddAddress(m.getRecipients(Message.RecipientType.TO), email, true,
false);

email.setSubject(m.getSubject());

Date d = (m.getSentDate());
if (d != null)
email.setSendDate(d);

String msgId = GetElementOrNull(m.getHeader("Message-Id"));
if (msgId != null)
email.setMessageId(msgId);

String refs = GetElementOrNull(m.getHeader("References"));
if (refs == null) {
refs = GetElementOrNull(m.getHeader("In-Reply-To"));
}
if (msgId != null) {
if (refs != null)
refs = MimeUtility.unfold(refs) + " " + msgId;
else
refs = msgId;
}
if (refs != null)
email.setReferences(MimeUtility.fold(12, refs));

// Обработка флагов сообщения
Flags flags = m.getFlags();
Flags.Flag[] sf = flags.getSystemFlags();
for (int i = 0; i < sf.length; i++) {
Flags.Flag f = sf[i];
if (f == Flags.Flag.ANSWERED)
email.setEmailType(EMailType.Answered);
else if (f == Flags.Flag.DELETED)
email.setEmailType(EMailType.Deleted);
else if (f == Flags.Flag.DRAFT)
email.setEmailType(EMailType.Draft);
else if (f == Flags.Flag.FLAGGED)
email.setEmailType(EMailType.Flagged);
else if (f == Flags.Flag.RECENT)
email.setEmailType(EMailType.Recent);
else if (f == Flags.Flag.SEEN)
email.setEmailType(EMailType.Seen);
else
continue;
}

// x-mail
String[] hdrs = m.getHeader("X-Mailer");
if (hdrs != null)
email.setXMailer(hdrs[0]);
else
email.setXMailer("");
}

/**
* Добавляет адрес получателя/отправителя
* 
* @throws UnsupportedEncodingException
*/
private static void AddAddress(Address[] address, EMail email,
Boolean addTo, Boolean addFrom) throws UnsupportedEncodingException {
if ((!addTo && !addFrom) || (addTo && addFrom)) {
throw new IllegalArgumentException(
"Не установлен не один из флагов addTo, addFrom или оба установлены!");
}

List<string> result = new ArrayList<string>();
if (address == null || address.length == 0)
return;
for (int i = 0; i < address.length; i++)
result.add(MimeUtility.decodeText(address[i].toString()));
if (addTo)
email.setTo(result);
if (addFrom)
email.setFrom(result);
}

/**
* Возвращает первый не null элемент массива и если таких элементов нет, то
* null
* 
* @param mas - массив
* @return Первый не null элемент массива и если таких элементов нет, то
*         null
*/
private static String GetElementOrNull(String[] mas) {
if (mas != null && mas.length > 0) {
for (int i = 0; i < mas.length; i++)
if (mas[i] != null && mas[i] != "")
return mas[i];
}
return null;
}
</pre>
После получения письма выполняем следующий код и вот в переменной email будет уже обработанное письмо:
<pre ace-mode="ace/mode/java" class="code">Message m = null; // полученое письмо
EMail email = new EMail();
int level = 0;
ProcessingPart(email, m, level);
</pre><h2>Обработка исходящих писем</h2>С другой стороны если вы имеете объект класса EMail, то как отправить письмо с прикрепленными файлами. Данная задачи имеет очень простое решение которое продемонстрировано ниже:
<pre ace-mode="ace/mode/java" class="code">/**
  * Создание письма для отправки почтой
  * @param email - объект письма класса EMail
  * @param session - сессия
  * @return письмо для отправки почтой
  * @throws MessagingException
  * @throws IOException
  */
 public static MimeMessage CreateMessage(EMail email, Session session) throws MessagingException, IOException{
  MimeMessage mess = new MimeMessage(session);
  mess.setSubject(email.getSubject());
  
  for (int i = 0; i < email.getTo().size(); i++) {
   mess.addRecipient(Message.RecipientType.TO, new InternetAddress(
     email.getTo().get(i)));
  }
  mess.setSentDate(new Date());
  
  if (email.getReplyFile() != null || email.getAttachedFile().size() > 0) {
   // если есть атачи
   MimeMultipart mp = new MimeMultipart();
   MimeBodyPart tp = new MimeBodyPart();
   tp.setText(email.getReplyContent()); // добавление тела
   mp.addBodyPart(tp);

   for (int i = 0; i < email.getAttachedFile().size(); i++) {
    // файлы атачей
    MimeBodyPart mbp2 = CreateMimeBodyPartFileAttached(email
      .getAttachedFile().get(i));
    mp.addBodyPart(mbp2);
   }

   mess.setContent(mp);
  } else
   mess.setText(email.getReplyContent());
  return mess;
 }

 /**
  * Создает и возвращает часть с атачем
  * 
  * @param file - объект Файла(EFile)
  * @return - часть с атачем
  * @throws MessagingException
  * @throws IOException
  */
 private static MimeBodyPart CreateMimeBodyPartFileAttached(EFile file)
   throws MessagingException, IOException {
  // крепим атач
  MimeBodyPart mbp = new MimeBodyPart();
  mbp.setFileName(MimeUtility.encodeText(file.getFileName()));
  if (file.getMimeType().indexOf("text/xml") != -1
    || file.getMimeType().indexOf("text/plain") != -1
    || file.getMimeType().indexOf("text/html") != -1) {
   String mimeType = (file.getMimeType().indexOf("text/xml") != -1 ? "text/xml"
     : (file.getMimeType().indexOf("text/plain") != -1 ? "text/plain"
       : (file.getMimeType().indexOf("text/html") != -1 ? "text/html"
         : "")));
   String str = new String(file.getContent(), "UTF-8");
   mbp.setText(str);
  } else {
   mbp.setDataHandler(new DataHandler(file.getContent(), file
     .getMimeType()));
  }
  mbp.setDisposition(Part.ATTACHMENT);
  return mbp;
 }

Как обрабатывать и получить письмо для отправки стало понятно. У некоторых может возникнуть вопрос, а почему статья называется "JavaMail в пивном соусе", ответ прост - после 3 литров пиваса и при работе с JavaMail вы получите как раз такой эффект.

Комментариев нет:

Отправить комментарий