I've written a simple class sending an HTML email with an embedded image (cf. below) via GMail SMTP. It works perfectly fine when run locally from Eclipse.
The same code in a GAE mail servlet handler produce the infamous "Converting attachment data failed" error. So it really seems to be a problem in GAE javamail implementation. /* * Copyright (C) 2009 Francois Masurel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/ >. */ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import javax.mail.Message; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; /** * @author Francois * */ public class GMailSMTP { private static final String SMTP_HOST_NAME = "smtp.gmail.com"; private static final int SMTP_HOST_PORT = 465; private static final String SMTP_AUTH_USER = "x...@gmail.com"; private static final String SMTP_AUTH_PWD = "yyy"; public static void main(String[] args) throws Exception{ new GMailSMTP().test(); } public void test() throws Exception{ Properties props = new Properties(); props.put("mail.transport.protocol", "smtps"); props.put("mail.smtps.host", SMTP_HOST_NAME); props.put("mail.smtps.auth", "true"); // props.put("mail.smtps.quitwait", "false"); String from = SMTP_AUTH_USER; String to = SMTP_AUTH_USER; String subject = "Testing SMTP-SSL"; String htmlText = "<h1>Hello</h1><img src=\"cid:image\">"; byte[] imgData = this.obtainByteData("enveloppe.gif"); Session mailSession = Session.getDefaultInstance(props); mailSession.setDebug(true); Message msg = new MimeMessage(mailSession); msg.setFrom(new InternetAddress(from)); msg.addRecipient(Message.RecipientType.TO, new InternetAddress (to)); msg.setSubject(subject); Multipart mp = new MimeMultipart("related"); MimeBodyPart htmlPart = new MimeBodyPart(); htmlPart.setContent(htmlText, "text/html"); mp.addBodyPart(htmlPart); MimeBodyPart attachment = new MimeBodyPart(); attachment.setFileName("test.gif"); attachment.setContent(imgData, "image/gif"); attachment.setHeader("Content-ID","<image>"); mp.addBodyPart(attachment); msg.setContent(mp); Transport transport = mailSession.getTransport(); transport.connect (SMTP_HOST_NAME, SMTP_HOST_PORT, SMTP_AUTH_USER, SMTP_AUTH_PWD); transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO)); transport.close(); } /** * Constructs a byte array and fills it with data that is read from the * specified resource. * @param filename the path to the resource * @return the specified resource as a byte array * @throws java.io.IOException if the resource cannot be read, or the * bytes cannot be written, or the streams cannot be closed */ private byte[] obtainByteData(String filename) throws IOException { InputStream inputStream = getClass().getResourceAsStream (filename); ByteArrayOutputStream outputStream = new ByteArrayOutputStream (1024); byte[] bytes = new byte[512]; // Read bytes from the input stream in bytes.length-sized chunks and write // them into the output stream int readBytes; while ((readBytes = inputStream.read(bytes)) > 0) { outputStream.write(bytes, 0, readBytes); } // Convert the contents of the output stream into a byte array byte[] byteData = outputStream.toByteArray(); // Close the streams inputStream.close(); outputStream.close(); return byteData; } } On Nov 18, 11:11 pm, "Ikai L (Google)" <ika...@google.com> wrote: > What I mean is, is this code working on a different mail server? > > On Wed, Nov 18, 2009 at 2:00 PM, mably <fm2...@mably.com> wrote: > > I'm just sending a simple mail from my Gmail account with an embedded > > gif image. > > > I can perfectly read it from my mail servlet handler but when I try to > > relay it (cf. code from first message) I get this annoying "Converting > > attachment data failed" error which seems to be specific to GAE. > > > Here is the mail sent data : > > > MIME-Version: 1.0 > > Sender: x...@gmail.com > > Received: by 10.142.204.15 with HTTP; Wed, 18 Nov 2009 13:57:20 -0800 > > (PST) > > Date: Wed, 18 Nov 2009 22:57:20 +0100 > > Delivered-To: x...@gmail.com > > X-Google-Sender-Auth: c9f34852bdb4f249 > > Message-ID: > > <75c1488c0911181357w4e8efdc2r7e82d8e1c3e03...@mail.gmail.com> > > Subject: Test > > From: Francois MASUREL <x...@mably.com> > > To: contact-test <contact-t...@webwinewatch.appspotmail.com> > > Content-Type: multipart/related; boundary=001636e90e61aa516e0478ac5398 > > > --001636e90e61aa516e0478ac5398 > > Content-Type: multipart/alternative; > > boundary=001636e90e61aa516b0478ac5397 > > > --001636e90e61aa516b0478ac5397 > > Content-Type: text/plain; charset=UTF-8 > > > [image: > > ? > > > ui=2&view=att&th=125094c9bff3199b&attid=0.1&disp=attd&realattid=ii_125094c9bff3199b&zw] > > > --001636e90e61aa516b0478ac5397 > > Content-Type: text/html; charset=UTF-8 > > Content-Transfer-Encoding: quoted-printable > > > <img title=3D"? > > ui=3D2&view=3Datt&th=3D125094c9bff3199b&attid=3D= > > 0.1&disp=3Dattd&realattid=3Dii_125094c9bff3199b&zw" > > alt=3D"?ui= > > > =3D2&view=3Datt&th=3D125094c9bff3199b&attid=3D0.1&disp=3Dat= > > td&realattid=3Dii_125094c9bff3199b&zw" > > src=3D"cid:ii_125094c9bff319= > > 9b"><br> > > <br> > > > --001636e90e61aa516b0478ac5397-- > > --001636e90e61aa516e0478ac5398 > > Content-Type: image/gif; name="enveloppe.gif" > > Content-Transfer-Encoding: base64 > > Content-ID: <ii_125094c9bff3199b> > > X-Attachment-Id: ii_125094c9bff3199b > > > R0lGODlhEAAQAPeYAP39/tHR5MrK4fLy99PT6NfX6Nvb6/ > > f3+ff3+uDg7sPD3fHx9ra206qqyrKy > > 0eLi8Onp8bCwz > > +jo8cvL4WVlm7y81cLC2fPz96ysyrCwzcXF3c7O487O4tDQ5Le30+fn8cvL4ufn > > 8PDw9/Ly+fDw9PLy+N7e66Skx8/ > > P46mpymBglNLS5KKixoWFsYaGs56ewNXV5pqawKyszuTk7pyc > > wdra6Pr6/ > > Ht7qnt7qXl5qry82LGx0MbG3pCQsrOz0qyszZubucjI3eLi7eDg6eDg7X5+rJSUu9zc > > 54uLtvz8/b+/2KenyPX1+K6uzpmZwOvr9a6uz8XF3Ovr9tLS5uPj8Hx8qvv7/ > > ZiYwLm50NPT5tjY > > 6K+v0M7O5IGBqtzc68/ > > P3mpqnoeHsLCwynJypNjY60ZGgJ2dw1hYjc7O4bi40nh4qWlpnNjY5fn5 > > +5SUvcTE2oCAqbOz0Le31tzc7L292vj4+sPD2by81unp8s/P5s3N3fPz > > +VxckqOjyHZ2psLC23p6 > > pt3d7d7e7PDw+L292JOTu/z8/Kury7Ozyra20ubm8MTE1/b2/Pn5/ > > Hd3qJCQvOnp876+2tHR5tHR > > 4oaGrbW10pmZv/7+/v/// > > wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > > > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > > > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > > > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > > > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > > > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAJgALAAAAAAQABAA > > > AAjlADEJHCiwzSQjamYQXIjAAo0fAq5gWChwgB03PiBdkhDkxgKCITywiLLn0qUkU2A4ESPQRKIm > > K5iYNIlHCREefg5gMjNBBICZAKx4SUGlQA4smOJw > > +BAAjaJLABh1aBCITJ8uNmrIuDRAS4Uldwyk > > > OZQFhQIKXxCcEGLSkCBLOKowoKNDARJKmN5AMQmghIBIEfKAICTnURlMFwotuNQogYYHcwJsYDDm > > DCKBGXZcGiQpgIECf1zwAUJiIIQWI6RwSUAghooeQyi > > +cPCEwBYwcI5QFMimSCVHgPTsHlgnzJpF > > OncHBAA7 > > --001636e90e61aa516e0478ac5398-- > > > On Nov 18, 10:34 pm, "Ikai L (Google)" <ika...@google.com> wrote: > > > François, > > > > I'm not familiar with any standards with regard to inline images. Do you > > > have this working outside of App Engine? Do you have working code from > > that? > > > If there are discrepancies in our implementation of javax.mail.* and > > > standard implementations we should be aware. > > > > On Mon, Nov 16, 2009 at 10:30 PM, mably <fm2...@mably.com> wrote: > > > > In fact standards attachments works. > > > > > But it's not what I'm trying do do. > > > > > I'm need to relay HTML messages with inline images and this is still > > > > not working. > > > > > Is it a kind of limitation of GAE or is it supposed to work ? > > > > > Thanx for your help. > > > > > François > > > > > On 16 nov, 23:09, mably <fm2...@mably.com> wrote: > > > > > Hi Ikai, thanx for you help. > > > > > > I've copy pasted your code on my webapp (webwinewatch), I've no error > > > > > but the mail isn't correctly relayed, all attachements are removed. > > > > > > I've just modified the sender, from and recipient lines : > > > > > > message.setSender(new InternetAddress("<myaddress>@gmail.com", > > "Relay > > > > > account")); > > > > > message.setFrom(message.getSender()); > > > > > message.setRecipient(Message.RecipientType.TO, message.getSender()); > > > > > > Do you have any clue ? > > > > > > You can test it, sending an email to : contact- > > > > > t...@webwinewatch.appspotmail.com > > > > > > Thanx again for your help. > > > > > > On 16 nov, 21:35, "Ikai L (Google)" <ika...@google.com> wrote: > > > > > > > I couldn't reproduce your exact error, but I was able to put > > together a > > > > > > working example of an inbound email handler to relay messages. I'm > > > > going to > > > > > > expand the documentation about processing inbound emails. Here's > > some > > > > > > working code:http://pastie.org/701517 > > > > > > > Does this example help any? Code is also pasted below, but it'll be > > > > easier > > > > > > for you to look at the Pastie. > > > > > > > import javax.servlet.http.HttpServlet; > > > > > > import javax.servlet.http.HttpServletRequest; > > > > > > import javax.servlet.http.HttpServletResponse; > > > > > > import javax.servlet.ServletException; > > > > > > import javax.mail.*; > > > > > > import javax.mail.util.ByteArrayDataSource; > > > > > > import javax.mail.internet.MimeMessage; > > > > > > import javax.mail.internet.MimeMultipart; > > > > > > import javax.mail.internet.MimeBodyPart; > > > > > > import javax.mail.internet.InternetAddress; > > > > > > import javax.activation.DataHandler; > > > > > > import java.io.IOException; > > > > > > import java.io.InputStream; > > > > > > import java.util.logging.Logger; > > > > > > import java.util.Properties; > > > > > > > public class MailHandlerServlet extends HttpServlet { > > > > > > private static final Logger log = > > > > > > Logger.getLogger(MailHandlerServlet.class.getName()); > > > > > > private static final String RECIPIENT = "recipi...@gmail.com"; > > > > > > private static final String SENDER = "sen...@google.com"; > > > > > > > protected void doPost(HttpServletRequest request, > > > > HttpServletResponse > > > > > > response) throws ServletException, IOException { > > > > > > Properties props = new Properties(); > > > > > > Session session = Session.getDefaultInstance(props, null); > > > > > > try { > > > > > > MimeMessage message = new MimeMessage(session, > > > > > > request.getInputStream()); > > > > > > > Object content = message.getContent(); // You could > > also > > > > > > probably just use message.getInputStream() here > > > > > > // and avoid the > > > > > > conditional type check > > > > > > > if (content instanceof String) { > > > > > > log.info("Received a string"); > > > > > > } else if (content instanceof InputStream) { > > > > > > // My somewhat limited testing indicates that this > > is > > > > always > > > > > > getting returned as an > > > > > > // InputStream > > > > > > > InputStream inputStream = (InputStream) content; > > > > > > ByteArrayDataSource inboundDataSource = new > > > > > > ByteArrayDataSource(inputStream, message.getContentType()); > > > > > > Multipart inboundMultipart = new > > > > > > MimeMultipart(inboundDataSource); > > > > > > > // Set the body with whatever text you want > > > > > > Multipart outboundMultipart = new MimeMultipart(); > > > > > > MimeBodyPart messageBodyPart = new MimeBodyPart(); > > > > > > messageBodyPart.setText("Set your body here"); > > > > > > outboundMultipart.addBodyPart(messageBodyPart); > > > > > > > // Loop over the multipart message coming in and > > > > > > // append them to the outbound Multipart object > > > > > > for (int i = 0; i < inboundMultipart.getCount(); > > i++) { > > > > > > BodyPart part = > > inboundMultipart.getBodyPart(i); > > > > > > /* > > > > > > The content-disposition header is optional: > > > > > > http://www.ietf.org/rfc/rfc1806.txt > > > > > > > This header specifies the filename and type > > of > > > > > > a MIME part. > > > > > > */ > > > > > > if(part.getDisposition() == null) { > > > > > > // This is just a plain text email > > > > > > } else { > > > > > > // We have something interesting. Let's > > parse > > > > it. > > > > > > > // Create a new ByteArrayDataSource with > > this > > > > part > > > > > > MimeBodyPart inboundMimeBodyPart = > > > > (MimeBodyPart) > > > > > > part; > > > > > > InputStream is = part.getInputStream(); > > > > > > ByteArrayDataSource mimePartDataSource = > > new > > > > > > ByteArrayDataSource(is, inboundMimeBodyPart.getContentType()); > > > > > > > // Create a new outbound MimeBodyPart and > > set > > > > this > > > > > > as the handler > > ... > > read more » -- You received this message because you are subscribed to the Google Groups "Google App Engine for Java" group. To post to this group, send email to google-appengine-j...@googlegroups.com. To unsubscribe from this group, send email to google-appengine-java+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=.