<bean id="publicUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/_ah/mail/*">mailController</prop> </props> </property> </bean>

import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.Properties; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.mail.Address; import javax.mail.Part; import javax.mail.Session; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; public class MailController extends AbstractController { protected final Log logger = LogFactory.getLog(getClass()); @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { Properties props = new Properties(); Session session = Session.getDefaultInstance(props, null); MimeMessage message = new MimeMessage(session, request.getInputStream()); Address[] from = message.getFrom(); String fromAddress = ""; if (from.length > 0) { fromAddress = from[0].toString(); } String contentType = message.getContentType(); InputStream inContent = null; logger.info("Message ContentType: ["+contentType+"]"); if (contentType.indexOf("multipart") > -1) { //Need to get the first part only DataHandler dataHandler = message.getDataHandler(); DataSource dataSource = dataHandler.getDataSource(); MimeMultipart mimeMultipart = new MimeMultipart(dataSource); Part part = mimeMultipart.getBodyPart(0); contentType = part.getContentType(); logger.info("Part ContentType: ["+contentType+"]"); inContent = (InputStream)part.getContent(); } else { //Assume text/plain inContent = (InputStream)message.getContent(); } String encoding = ""; if (contentType.indexOf("charset=") > -1) { encoding = contentType.split("charset=")[1]; } logger.info("Encoding: ["+encoding+"]"); String content; try { content = IOUtils.toString(inContent, encoding.toUpperCase()); } catch (UnsupportedEncodingException e) { content = IOUtils.toString(inContent); } logger.info("Received email from=["+fromAddress+"] subject=["+message.getSubject()+"]"); logger.info("Content: "+content); return null; } }

The getContent() method returns an object that implements the Multipart interface. You can then call getCount() to determine the number of parts and getBodyPart(int index) to return a particular body part.

Nested in org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space: java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Unknown Source) at java.io.ByteArrayOutputStream.write(Unknown Source) at javax.mail.internet.MimeMultipart.readTillFirstBoundary(MimeMultipart.java:244) at javax.mail.internet.MimeMultipart.parse(MimeMultipart.java:181) at javax.mail.internet.MimeMultipart.getBodyPart(MimeMultipart.java:114)

Here's my Spring Controller which, at the moment, receives an email and prints various elements of the message to the log. The instructions here are very good and I only adapted it slightly for Spring.Firstly I added the inbound-services section to my appengine-web.xml file. Next I added a url mapping to my Spring config:Here is the MailController class:Note that on the Google page it saysThis doesn't appear to be quite true. If you call getContent() on MimeMessage it returns a ByteArrayInputStream of the raw bytes for the whole message. According to the documentation here an input stream should only be returned if the content type is unknown. I think this is a bug.You can get around this by parsing the content type yourself as I have done in my example. If message.getContentType() returns a string containing "multipart" then I parse it as a multipart message, otherwise I assume it is "text/plain".In order to extract a single part of the Multipart content you have to pass through a MimeMultipart object. It's here that you can call getCount() and extract the Parts that you want. In my example I just get the first part.Calling getContent() on the Part still returns a stream of bytes so you have to convert it with the correct encoding. You can extract the encoding from the ContentType of the Part. I added a try..catch block around the conversion to a string in case the encoding was not recognized - in which case it falls back to the default.It is vital that you determine whether you have multipart content or not. If you try to parse a "text/plain" message as a multipart then you may well encounter an error like this:The readTillFirstBoundary method fails because in a "text/plain" message there are no boundaries!Note that the development server always sends a multipart message with two parts: text/plain and text/html. GMail also sends emails in this format but lots of other servers just send text/plain.