001/**************************************************************** 002 * Licensed to the Apache Software Foundation (ASF) under one * 003 * or more contributor license agreements. See the NOTICE file * 004 * distributed with this work for additional information * 005 * regarding copyright ownership. The ASF licenses this file * 006 * to you under the Apache License, Version 2.0 (the * 007 * "License"); you may not use this file except in compliance * 008 * with the License. You may obtain a copy of the License at * 009 * * 010 * http://www.apache.org/licenses/LICENSE-2.0 * 011 * * 012 * Unless required by applicable law or agreed to in writing, * 013 * software distributed under the License is distributed on an * 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * 015 * KIND, either express or implied. See the License for the * 016 * specific language governing permissions and limitations * 017 * under the License. * 018 ****************************************************************/ 019 020package org.apache.james.mime4j.samples.dom; 021 022import java.awt.BasicStroke; 023import java.awt.Color; 024import java.awt.Graphics2D; 025import java.awt.RenderingHints; 026import java.awt.image.BufferedImage; 027import java.io.IOException; 028import java.util.Date; 029 030import javax.imageio.ImageIO; 031 032import org.apache.james.mime4j.dom.BinaryBody; 033import org.apache.james.mime4j.dom.MessageWriter; 034import org.apache.james.mime4j.dom.Multipart; 035import org.apache.james.mime4j.dom.TextBody; 036import org.apache.james.mime4j.field.address.AddressBuilder; 037import org.apache.james.mime4j.message.BodyPart; 038import org.apache.james.mime4j.message.MessageImpl; 039import org.apache.james.mime4j.message.DefaultMessageWriter; 040import org.apache.james.mime4j.message.MultipartImpl; 041import org.apache.james.mime4j.storage.Storage; 042import org.apache.james.mime4j.storage.StorageBodyFactory; 043import org.apache.james.mime4j.storage.StorageOutputStream; 044import org.apache.james.mime4j.storage.StorageProvider; 045 046/** 047 * Creates a multipart/mixed message that consists of a text/plain and an 048 * image/png part. The image is created on the fly; a similar technique can be 049 * used to create PDF or XML attachments, for example. 050 */ 051public class MultipartMessage { 052 053 public static void main(String[] args) throws Exception { 054 // 1) start with an empty message 055 056 MessageImpl message = new MessageImpl(); 057 058 // 2) set header fields 059 060 // Date and From are required fields 061 message.setDate(new Date()); 062 message.setFrom(AddressBuilder.DEFAULT.parseMailbox("John Doe <jdoe@machine.example>")); 063 064 // Message-ID should be present 065 message.createMessageId("machine.example"); 066 067 // set some optional fields 068 message.setTo(AddressBuilder.DEFAULT.parseMailbox("Mary Smith <mary@example.net>")); 069 message.setSubject("An image for you"); 070 071 // 3) set a multipart body 072 073 Multipart multipart = new MultipartImpl("mixed"); 074 075 // a multipart may have a preamble 076 multipart.setPreamble("This is a multi-part message in MIME format."); 077 078 // first part is text/plain 079 StorageBodyFactory bodyFactory = new StorageBodyFactory(); 080 BodyPart textPart = createTextPart(bodyFactory, "Why so serious?"); 081 multipart.addBodyPart(textPart); 082 083 // second part is image/png (image is created on the fly) 084 BufferedImage image = renderSampleImage(); 085 BodyPart imagePart = createImagePart(bodyFactory, image); 086 multipart.addBodyPart(imagePart); 087 088 // setMultipart also sets the Content-Type header field 089 message.setMultipart(multipart); 090 091 // 4) print message to standard output 092 093 MessageWriter writer = new DefaultMessageWriter(); 094 writer.writeMessage(message, System.out); 095 096 // 5) message is no longer needed and should be disposed of 097 098 message.dispose(); 099 } 100 101 /** 102 * Creates a text part from the specified string. 103 */ 104 private static BodyPart createTextPart(StorageBodyFactory bodyFactory, String text) { 105 // Use UTF-8 to encode the specified text 106 TextBody body = bodyFactory.textBody(text, "UTF-8"); 107 108 // Create a text/plain body part 109 BodyPart bodyPart = new BodyPart(); 110 bodyPart.setText(body); 111 bodyPart.setContentTransferEncoding("quoted-printable"); 112 113 return bodyPart; 114 } 115 116 /** 117 * Creates a binary part from the specified image. 118 */ 119 private static BodyPart createImagePart(StorageBodyFactory bodyFactory, 120 BufferedImage image) throws IOException { 121 // Create a binary message body from the image 122 StorageProvider storageProvider = bodyFactory.getStorageProvider(); 123 Storage storage = storeImage(storageProvider, image, "png"); 124 BinaryBody body = bodyFactory.binaryBody(storage); 125 126 // Create a body part with the correct MIME-type and transfer encoding 127 BodyPart bodyPart = new BodyPart(); 128 bodyPart.setBody(body, "image/png"); 129 bodyPart.setContentTransferEncoding("base64"); 130 131 // Specify a filename in the Content-Disposition header (implicitly sets 132 // the disposition type to "attachment") 133 bodyPart.setFilename("smiley.png"); 134 135 return bodyPart; 136 } 137 138 /** 139 * Stores the specified image in a Storage object. 140 */ 141 private static Storage storeImage(StorageProvider storageProvider, 142 BufferedImage image, String formatName) throws IOException { 143 // An output stream that is capable of building a Storage object. 144 StorageOutputStream out = storageProvider.createStorageOutputStream(); 145 146 // Write the image to our output stream. A StorageOutputStream can be 147 // used to create attachments using any API that supports writing a 148 // document to an output stream, e.g. iText's PdfWriter. 149 ImageIO.write(image, formatName, out); 150 151 // Implicitly closes the output stream and returns the data that has 152 // been written to it. 153 return out.toStorage(); 154 } 155 156 /** 157 * Draws an image; unrelated to Mime4j. 158 */ 159 private static BufferedImage renderSampleImage() { 160 System.setProperty("java.awt.headless", "true"); 161 162 final int size = 100; 163 164 BufferedImage img = new BufferedImage(size, size, 165 BufferedImage.TYPE_BYTE_GRAY); 166 167 Graphics2D gfx = img.createGraphics(); 168 gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 169 RenderingHints.VALUE_ANTIALIAS_ON); 170 gfx.setStroke(new BasicStroke(size / 40f, BasicStroke.CAP_ROUND, 171 BasicStroke.JOIN_ROUND)); 172 173 gfx.setColor(Color.BLACK); 174 gfx.setBackground(Color.WHITE); 175 gfx.clearRect(0, 0, size, size); 176 177 int b = size / 30; 178 gfx.drawOval(b, b, size - 1 - 2 * b, size - 1 - 2 * b); 179 180 int esz = size / 7; 181 int ex = (int) (0.27f * size); 182 gfx.drawOval(ex, ex, esz, esz); 183 gfx.drawOval(size - 1 - esz - ex, ex, esz, esz); 184 185 b = size / 5; 186 gfx.drawArc(b, b, size - 1 - 2 * b, size - 1 - 2 * b, 200, 140); 187 188 return img; 189 } 190 191}