/* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.activiti.engine.impl.mail; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import javax.mail.Address; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.Part; import javax.mail.internet.MimeMultipart; import org.activiti.engine.impl.persistence.entity.AttachmentEntity; import org.activiti.engine.impl.persistence.entity.ByteArrayEntity; import org.activiti.engine.impl.util.IoUtil; import org.activiti.engine.impl.util.json.JSONObject; public class MailTransformer { private static Logger log = Logger.getLogger(MailTransformer.class.getName()); public static int ATTACHMENT_SIZE_LIMIT = 1024*1024*10; // 10MB protected Message message; protected boolean containsHtml = false; protected StringBuilder messageText = new StringBuilder(); protected StringBuilder messageHtml = new StringBuilder(); protected List<String> recipients = new ArrayList<String>(); protected List<AttachmentEntity> attachments = new ArrayList<AttachmentEntity>(); public MailTransformer(Message message) throws Exception { this.message = message; processRecipients(message); processContentPart(0, message); AttachmentEntity attachment = new AttachmentEntity(); attachment.setName(message.getSubject()); attachment.setType("email"); attachments.add(attachment); JSONObject jsonMail = new JSONObject(); jsonMail.put("recipients", recipients); jsonMail.put("sentDate", message.getSentDate()); jsonMail.put("receivedDate", message.getReceivedDate()); jsonMail.put("subject", message.getSubject()); jsonMail.put("htmlContent", getHtml()); String jsonMailString = jsonMail.toString(2); byte[] bytes = jsonMailString.getBytes(); attachment.setContent(new ByteArrayEntity(bytes)); log.fine("=== json =========================="); log.fine(jsonMailString); log.fine("=== attachments =========================="); for (AttachmentEntity attachmentForLogging: attachments) { log.fine(attachmentForLogging.getName()+" | "+attachmentForLogging.getType()+" | "+attachmentForLogging.getContent().getBytes().length); } } public String getHtml() { return (containsHtml ? messageHtml.toString() : messageText.toString()); } public List<AttachmentEntity> getAttachments() { return attachments; } protected void processContentPart(int indent, Part part) throws Exception { if (part.getContent() instanceof MimeMultipart) { log(indent, "--- multipart "+getMimeType(part)+" ----------------------------------"); MimeMultipart mimeMultipart = (MimeMultipart) part.getContent(); for (int i=0; i<mimeMultipart.getCount(); i++) { BodyPart bodyPart = mimeMultipart.getBodyPart(i); processContentPart(indent+1, bodyPart); } } else { log(indent, "--- part "+getMimeType(part)+" ----------------------------------"); if (part.isMimeType("text/plain")) { String contentText = (String) part.getContent(); log(indent, "adding plain text: "+contentText); messageText.append(contentText); } else if (part.isMimeType("text/html")){ String rawHtml = (String) part.getContent(); log(indent, "raw html: "+rawHtml); String cleanedUpHtml = htmlExtractBodyContent(rawHtml); log(indent, "adding cleaned up html: "+cleanedUpHtml); containsHtml = true; messageHtml.append(cleanedUpHtml); } else { String fileName = part.getFileName(); log(indent, "unknown content part | "+part.getContentType()+" | "+part.getDisposition()+" | "+Arrays.toString(part.getHeader("Content-ID"))+" | "+fileName+" | "+part.getContent().getClass().getName()); if (part.getSize()!=-1 && part.getSize()<ATTACHMENT_SIZE_LIMIT && (part.getContent() instanceof InputStream)) { String attachmentName = null; String attachmentType = null; String[] contentIdArray = part.getHeader("Content-ID"); if (contentIdArray!=null && contentIdArray.length>0) { attachmentName = contentIdArray[0].trim(); if (attachmentName.startsWith("<") && attachmentName.endsWith(">")) { attachmentName = attachmentName.substring(1, attachmentName.length()-2).trim(); } attachmentType = getImageMimeType(attachmentName); } else if (Part.INLINE.equalsIgnoreCase(part.getDisposition())) { attachmentName = fileName; attachmentType = getImageMimeType(attachmentName); messageText.append("<img id=\"cid:"+fileName+"\" src=\"cid:"+fileName+"\" />"); messageHtml.append("<img id=\"cid:"+fileName+"\" src=\"cid:"+fileName+"\" />"); } if (attachmentName==null) { attachmentName = fileName; attachmentType = "email-attachment"; } AttachmentEntity attachment = new AttachmentEntity(); attachment.setName(attachmentName); attachment.setType(attachmentType); attachments.add(attachment); byte[] bytes = IoUtil.readInputStream((InputStream)part.getContent(), "mail attachment "+attachmentName); attachment.setContent(new ByteArrayEntity(bytes)); } } } } protected String getImageMimeType(String attachmentName) { int lastDotIndex = attachmentName.lastIndexOf('.'); if (lastDotIndex!=-1) { String extension = attachmentName.substring(lastDotIndex+1); if ("jpg".equals(extension)) { extension = "jpeg"; } return "image/"+extension; } return "email-inline-image"; } private static final String INDENT_WHITESPACE = " "; void log(int indent, String msg) { log.fine(INDENT_WHITESPACE.substring(0, indent*2)+msg.replaceAll("\\s", " ")); } protected void processRecipients(Message message) throws Exception { for (Address recipientAddress: message.getAllRecipients()) { String recipient = recipientAddress.toString(); int ltIndex = recipient.indexOf('<'); int atIndex = recipient.indexOf('@'); int gtIndex = recipient.indexOf('>'); if ( (ltIndex!=-1) && (atIndex!=-1) && (gtIndex!=-1) && (ltIndex<atIndex) && (atIndex<gtIndex) ) { recipient = recipient.substring(ltIndex+1, gtIndex); } recipients.add(recipient); } } public String htmlExtractBodyContent(String rawHtml) { String html = rawHtml.trim(); html = htmlRemoveOuterTag(html, "html"); html = html.trim(); html = htmlRemoveStartTag(html, "head"); html = htmlRemoveOuterTag(html, "body"); html = htmlRemoveStartTag(html, "head"); return html; } protected String htmlRemoveStartTag(String html, String tagName) { int endIndex = -1; if (html.startsWith("<"+tagName)) { endIndex = html.indexOf("</"+tagName+">"); } else if (html.startsWith("<"+tagName.toUpperCase())) { endIndex = html.indexOf("</"+tagName.toUpperCase()+">"); } if (endIndex!=-1) { endIndex += tagName.length()+3; html = html.substring(endIndex); } return html; } protected String htmlRemoveOuterTag(String html, String tagName) { html = html.trim(); if ( (html.startsWith("<"+tagName)) || (html.startsWith("<"+tagName.toUpperCase())) ) { int endIndex = html.indexOf('>'); html = html.substring(endIndex+1, html.length()-(tagName.length()+3)); } return html; } public String getMimeType(Part part) throws Exception { String mimeType = part.getContentType(); int semicolonIndex = mimeType.indexOf(';'); if (semicolonIndex!=-1) { mimeType = mimeType .substring(0, semicolonIndex); } mimeType = mimeType.trim(); mimeType = mimeType.toLowerCase(); return mimeType; } public List<String> getRecipients() { return recipients; } public void setRecipients(List<String> recipients) { this.recipients = recipients; } public Message getMessage() { return message; } }