Java tutorial
/* * Copyright (c) 2008-2011, Martijn Brinkers, Djigzo. * * This file is part of Djigzo email encryption. * * Djigzo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License * version 3, 19 November 2007 as published by the Free Software * Foundation. * * Djigzo 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with Djigzo. If not, see <http://www.gnu.org/licenses/> * * Additional permission under GNU AGPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, * wsdl4j-1.6.1.jar (or modified versions of these libraries), * containing parts covered by the terms of Eclipse Public License, * tyrex license, freemarker license, dom4j license, mx4j license, * Spice Software License, Common Development and Distribution License * (CDDL), Common Public License (CPL) the licensors of this Program grant * you additional permission to convey the resulting work. */ package mitm.common.mail; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import javax.activation.DataHandler; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimePart; import javax.mail.util.ByteArrayDataSource; import mitm.common.util.FileConstants; import mitm.common.util.MiscStringUtils; import mitm.common.util.SizeUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.DeferredFileOutputStream; public class MailUtils { public static final byte[] CRLF_BYTES = new byte[] { '\r', '\n' }; @SuppressWarnings("rawtypes") public static void writeMessageRaw(MimePart part, OutputStream output) throws IOException, MessagingException { Enumeration lines = part.getAllHeaderLines(); /* step through all header lines */ while (lines.hasMoreElements()) { String header = (String) lines.nextElement(); output.write(MiscStringUtils.toAsciiBytes(header)); output.write(CRLF_BYTES); } output.write(CRLF_BYTES); InputStream input; /* * If message is created from a stream Javamail will return the raw stream. If * the message is created from 'scratch' getRawInputStream throws a * MessagingException. We will therefore first try the raw version and if * that fails we will try getInputStream. * * Only MimeMessage has getRawInputStream so we check whether the part * is a MimeMessage */ if (part instanceof MimeMessage) { try { input = ((MimeMessage) part).getRawInputStream(); } catch (MessagingException e) { /* * Could be that we are using Javamail 1.3 which does not support * getRawInputStream. Use the inputStream instead */ input = part.getInputStream(); } } else { input = part.getInputStream(); } IOUtils.copy(input, output); } /** * Saves the MimePart to the output stream * @param part * @param output * @throws IOException * @throws MessagingException */ public static void writeMessage(MimePart part, OutputStream output) throws IOException, MessagingException { /* * we need to store the result in a temporary buffer so we can fall back * on a different procedure when writeTo fails. If not, MimePart#writeTo might * fail halfway and some data has already been written to output. */ DeferredFileOutputStream buffer = new DeferredFileOutputStream(SizeUtils.MB, FileConstants.TEMP_FILE_PREFIX, null, null); /* * First try the writeTo method. Sometimes this will fail when the message uses * an unsupported or corrupt encoding. For example the content encoding says that * the message is base64 encoded but it is not. */ try { part.writeTo(buffer); /* * Need to close the DeferredFileOutputStream before we can write */ buffer.close(); /* * writeTo was successful so we can copy the result to the final output */ buffer.writeTo(output); } catch (IOException e) { writeMessageRaw(part, output); } catch (MessagingException e) { writeMessageRaw(part, output); } finally { /* * Delete any possible temp file used by DeferredFileOutputStream. */ FileUtils.deleteQuietly(buffer.getFile()); } } public static void writeMessage(MimePart part, File outputFile) throws IOException, MessagingException { FileOutputStream output = new FileOutputStream(outputFile); try { writeMessage(part, output); } finally { output.close(); } } /** * Loads a message from the given file using the default mail session * @param file file containing the RFC822 message source * @return the loaded file * @throws FileNotFoundException * @throws MessagingException */ public static MimeMessage loadMessage(File file) throws FileNotFoundException, MessagingException { InputStream input = new BufferedInputStream(new FileInputStream(file)); try { return loadMessage(input); } finally { IOUtils.closeQuietly(input); } } /** * Loads a message from the input stream using the default mail session * @param input * @return * @throws MessagingException */ public static MimeMessage loadMessage(InputStream input) throws MessagingException { MimeMessage message = new MimeMessage(MailSession.getDefaultSession(), input); return message; } /** * Checks whether the message can be converted to RFC2822 raw message source. Messages that * contain unsupported encoding types, corrupts content transfer encoding etc. will result * in a MessagingException or IOException. * @param message * @throws MessagingException * @throws IOException */ public static void validateMessage(MimeMessage message) throws MessagingException, IOException { OutputStream bitsink = new OutputStream() { @Override public void write(int ignore) { } }; message.writeTo(bitsink); } /** * Checks whether the message can be converted to RFC2822 raw message source. Messages that * contain unsupported encoding types, corrupts content transfer encoding etc. will result * in a MessagingException or IOException. * @param message * @throws MessagingException * @throws IOException */ public static void validateMessage(Part part) throws MessagingException, IOException { OutputStream bitsink = new OutputStream() { @Override public void write(int ignore) { } }; part.writeTo(bitsink); } /** * Creates a new MimeMessage which is a duplicate of the source message. */ public static MimeMessage cloneMessage(MimeMessage sourceMessage) throws MessagingException { return new MimeMessage(sourceMessage); } /** * Returns the Part as a byte array. The Part is converted to a byte array using MimeMessage.writeTo. * If a message contains a corrupt body (like incorrect base64) writeTo can throw an exception. */ public static byte[] partToByteArray(Part part) throws IOException, MessagingException { /* * create a buffer with some 'guess' of the size plus some constant value. If size is unknown size = -1 so * the buffer will be 1023. */ ByteArrayOutputStream bos = new ByteArrayOutputStream(part.getSize() + 1024); part.writeTo(bos); return bos.toByteArray(); } /** * Converts the bytes to a MimeMessage * @throws MessagingException */ public static MimeMessage byteArrayToMessage(byte[] bytes) throws MessagingException { ByteArrayInputStream bis = new ByteArrayInputStream(bytes); MimeMessage message = loadMessage(bis); return message; } /** * Converts any 8bit encoded parts to 7bit. Returns true if a part (or all parts) were converted from * 8bit to 7bit. * * @param part * @throws MessagingException */ public static boolean convertTo7Bit(MimePart part) throws MessagingException, IOException { boolean converted = false; if (part.isMimeType("multipart/*")) { Multipart parts = (Multipart) part.getContent(); int count = parts.getCount(); for (int i = 0; i < count; i++) { boolean partConverted = convertTo7Bit((MimePart) parts.getBodyPart(i)); if (partConverted) { converted = true; } } } else if ("8bit".equalsIgnoreCase(part.getEncoding())) { String encoding = part.isMimeType("text/*") ? "quoted-printable" : "base64"; /* * We need to use a ByteArrayDataSource to make sure it will always be encoded */ part.setDataHandler( new DataHandler(new ByteArrayDataSource(part.getInputStream(), part.getContentType()))); part.setHeader("Content-Transfer-Encoding", encoding); part.addHeader("X-MIME-Autoconverted", "from 8bit to " + encoding + " by Djigzo"); converted = true; } return converted; } }