org.codemonkey.simplejavamail.util.MimeMessageParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simple-java-mail Show documentation
Show all versions of simple-java-mail Show documentation
A light weight wrapper for the JavaMail SMTP API
The newest version!
/*
* heavily modified version based on org.apache.commons.mail.util.MimeMessageParser.html
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.codemonkey.simplejavamail.util;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.util.ByteArrayDataSource;
import java.io.*;
import java.util.*;
/**
* heavily modified version based on org.apache.commons.mail.util.MimeMessageParser.html
* Parses a MimeMessage and stores the individual parts such a plain text,
* HTML text and attachments.
*
* @version current: MimeMessageParser.java 2016-02-25 Benny Bottema
*/
public class MimeMessageParser {
private static final List DEFAULT_HEADERS = new ArrayList();
static {
// taken from: protected javax.mail.internet.InternetHeaders constructor
/*
* When extracting information to create an Email, we're not interested in the following headers:
*/
DEFAULT_HEADERS.add("Return-Path");
DEFAULT_HEADERS.add("Received");
DEFAULT_HEADERS.add("Resent-Date");
DEFAULT_HEADERS.add("Resent-From");
DEFAULT_HEADERS.add("Resent-Sender");
DEFAULT_HEADERS.add("Resent-To");
DEFAULT_HEADERS.add("Resent-Cc");
DEFAULT_HEADERS.add("Resent-Bcc");
DEFAULT_HEADERS.add("Resent-Message-Id");
DEFAULT_HEADERS.add("Date");
DEFAULT_HEADERS.add("From");
DEFAULT_HEADERS.add("Sender");
DEFAULT_HEADERS.add("Reply-To");
DEFAULT_HEADERS.add("To");
DEFAULT_HEADERS.add("Cc");
DEFAULT_HEADERS.add("Bcc");
DEFAULT_HEADERS.add("Message-Id");
DEFAULT_HEADERS.add("In-Reply-To");
DEFAULT_HEADERS.add("References");
DEFAULT_HEADERS.add("Subject");
DEFAULT_HEADERS.add("Comments");
DEFAULT_HEADERS.add("Keywords");
DEFAULT_HEADERS.add("Errors-To");
DEFAULT_HEADERS.add("MIME-Version");
DEFAULT_HEADERS.add("Content-Type");
DEFAULT_HEADERS.add("Content-Transfer-Encoding");
DEFAULT_HEADERS.add("Content-MD5");
DEFAULT_HEADERS.add(":");
DEFAULT_HEADERS.add("Content-Length");
DEFAULT_HEADERS.add("Status");
// extra headers that should be ignored, which may originate from nested attachments
DEFAULT_HEADERS.add("Content-Disposition");
DEFAULT_HEADERS.add("size");
DEFAULT_HEADERS.add("filename");
DEFAULT_HEADERS.add("Content-ID");
DEFAULT_HEADERS.add("name");
DEFAULT_HEADERS.add("From");
}
private final Map attachmentList = new HashMap();
private final Map cidMap = new HashMap();
private final Map headers = new HashMap();
private final MimeMessage mimeMessage;
private String plainContent;
private String htmlContent;
/**
* Constructs an instance with the MimeMessage to be extracted.
*
* @param message the message to parse
*/
public MimeMessageParser(final MimeMessage message) {
this.mimeMessage = message;
}
/**
* Does the actual extraction.
*
* @return this instance
*/
public MimeMessageParser parse() throws MessagingException, IOException {
this.parse(mimeMessage);
return this;
}
/**
* @return the 'to' recipients of the message
*/
public List getTo() throws MessagingException {
return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.TO));
}
/**
* @return the 'cc' recipients of the message
*/
public List getCc() throws MessagingException {
return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.CC));
}
/**
* @return the 'bcc' recipients of the message
*/
public List getBcc() throws MessagingException {
return getInternetAddresses(this.mimeMessage.getRecipients(Message.RecipientType.BCC));
}
private List getInternetAddresses(Address[] recipients) {
List addresses = (recipients != null) ? Arrays.asList(recipients) : new ArrayList();
List mailAddresses = new ArrayList();
for (Address address : addresses) {
if (address instanceof InternetAddress) {
mailAddresses.add((InternetAddress) address);
}
}
return mailAddresses;
}
/**
* @return the 'from' field of the message
*/
public InternetAddress getFrom() throws MessagingException {
final Address[] addresses = this.mimeMessage.getFrom();
if (addresses == null || addresses.length == 0) {
return null;
}
return (InternetAddress) addresses[0];
}
/**
* @return the 'replyTo' address of the email
*/
public InternetAddress getReplyTo() throws MessagingException {
final Address[] addresses = this.mimeMessage.getReplyTo();
if (addresses == null || addresses.length == 0) {
return null;
}
return (InternetAddress) addresses[0];
}
/**
* @return the mail subject
*/
public String getSubject() throws MessagingException {
return this.mimeMessage.getSubject();
}
/**
* Extracts the content of a MimeMessage recursively.
*
* @param part the current MimePart
* @throws MessagingException parsing the MimeMessage failed
* @throws IOException parsing the MimeMessage failed
*/
protected void parse(final MimePart part)
throws MessagingException, IOException {
extractCustomUserHeaders(part);
if (isMimeType(part, "text/plain") && plainContent == null
&& !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
plainContent = (String) part.getContent();
} else {
if (isMimeType(part, "text/html") && htmlContent == null
&& !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
htmlContent = (String) part.getContent();
} else {
if (isMimeType(part, "multipart/*")) {
final Multipart mp = (Multipart) part.getContent();
final int count = mp.getCount();
// iterate over all MimeBodyPart
for (int i = 0; i < count; i++) {
parse((MimeBodyPart) mp.getBodyPart(i));
}
} else {
final DataSource ds = createDataSource(part);
// If the diposition is not provided, the part should be treat as attachment
if (part.getDisposition() == null || Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
this.attachmentList.put(part.getContentID(), ds);
} else if (Part.INLINE.equalsIgnoreCase(part.getDisposition())) {
this.cidMap.put(part.getContentID(), ds);
} else {
throw new IllegalStateException("invalid attachment type");
}
}
}
}
}
private void extractCustomUserHeaders(MimePart part) throws MessagingException {
Enumeration e = part.getAllHeaders();
while (e.hasMoreElements()) {
Object headerObj = e.nextElement();
if (headerObj instanceof Header) {
Header header = (Header) headerObj;
if (isCustomUserHeader(header)) {
headers.put(header.getName(), header.getValue());
}
}
}
}
private boolean isCustomUserHeader(Header header) {
return !DEFAULT_HEADERS.contains(header.getName());
}
/**
* Checks whether the MimePart contains an object of the given mime type.
*
* @param part the current MimePart
* @param mimeType the mime type to check
* @return {@code true} if the MimePart matches the given mime type, {@code false} otherwise
* @throws MessagingException parsing the MimeMessage failed
* @throws IOException parsing the MimeMessage failed
*/
private boolean isMimeType(final MimePart part, final String mimeType)
throws MessagingException, IOException {
// Do not use part.isMimeType(String) as it is broken for MimeBodyPart
// and does not really check the actual content type.
try {
final ContentType ct = new ContentType(part.getDataHandler().getContentType());
return ct.match(mimeType);
} catch (final ParseException ex) {
return part.getContentType().equalsIgnoreCase(mimeType);
}
}
/**
* Parses the MimePart to create a DataSource.
*
* @param part the current part to be processed
* @return the DataSource
* @throws MessagingException creating the DataSource failed
* @throws IOException creating the DataSource failed
*/
protected DataSource createDataSource(final MimePart part)
throws MessagingException, IOException {
final DataHandler dataHandler = part.getDataHandler();
final DataSource dataSource = dataHandler.getDataSource();
final String contentType = getBaseMimeType(dataSource.getContentType());
final byte[] content = this.getContent(dataSource.getInputStream());
final ByteArrayDataSource result = new ByteArrayDataSource(content, contentType);
final String dataSourceName = getDataSourceName(part, dataSource);
result.setName(dataSourceName);
return result;
}
/**
* Determines the name of the data source if it is not already set.
*
* @param part the mail part
* @param dataSource the data source
* @return the name of the data source or {@code null} if no name can be determined
* @throws MessagingException accessing the part failed
* @throws UnsupportedEncodingException decoding the text failed
*/
protected String getDataSourceName(final Part part, final DataSource dataSource)
throws MessagingException, UnsupportedEncodingException {
String result = dataSource.getName();
if (result == null || result.length() == 0) {
result = part.getFileName();
}
if (result != null && result.length() > 0) {
result = MimeUtility.decodeText(result);
} else {
result = null;
}
return result;
}
/**
* Read the content of the input stream.
*
* @param is the input stream to process
* @return the content of the input stream
* @throws IOException reading the input stream failed
*/
private byte[] getContent(final InputStream is)
throws IOException {
int ch;
byte[] result;
final ByteArrayOutputStream os = new ByteArrayOutputStream();
final BufferedInputStream isReader = new BufferedInputStream(is);
final BufferedOutputStream osWriter = new BufferedOutputStream(os);
while ((ch = isReader.read()) != -1) {
osWriter.write(ch);
}
osWriter.flush();
result = os.toByteArray();
osWriter.close();
return result;
}
/**
* Parses the mimeType.
*
* @param fullMimeType the mime type from the mail api
* @return the real mime type
*/
private String getBaseMimeType(final String fullMimeType) {
final int pos = fullMimeType.indexOf(';');
if (pos >= 0) {
return fullMimeType.substring(0, pos);
}
return fullMimeType;
}
/**
* @return {@link #cidMap}
*/
public Map getCidMap() {
return cidMap;
}
/**
* @return {@link #headers}
*/
public Map getHeaders() {
return headers;
}
/**
* @return {@link #plainContent}
*/
public String getPlainContent() {
return plainContent;
}
/**
* @return {@link #attachmentList}
*/
public Map getAttachmentList() {
return attachmentList;
}
/**
* @return {@link #htmlContent}
*/
public String getHtmlContent() {
return htmlContent;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy