Java 8 has reached end of support and will be deprecated on January 31, 2026. After deprecation, you won't be able to deploy Java 8 applications, even if your organization previously used an organization policy to re-enable deployments of legacy runtimes. Your existing Java 8 applications will continue to run and receive traffic after their deprecation date. We recommend that you migrate to the latest supported version of Java.

Receiving Email

Email messages are sent to your app as HTTP requests. To process incoming email messages, you must associate email addresses with servlets in your application configuration, and then include the servlet code with your app. The incoming email generates HTTP requests that are passed to the appropriate servlets for handling.

Configuring your application to receive email

When you create a new application, incoming email is disabled by default. If you don't explicitly enable incoming email messages sent to your app are ignored.

To enable the incoming email service, modify the appengine-web.xml and web.xml configuration files:

Enabling email in appengine-web.xml

Modify appengine-web.xml by adding an inbound-services section that enables the incoming email service:

<inbound-services>
<!--Usedtohandleincomingmail.-->
<service>mail</service>
<!--Usedtohandlebouncedmailnotifications.-->
<service>mail_bounce</service>
</inbound-services>

Email messages are sent to your app as HTTP POST requests using the following URL:

/_ah/mail/<ADDRESS>

where <ADDRESS> is a full email address, including domain name. Note that even if your app is deployed on a custom domain, your app can't receive email sent to addresses in that domain.

Enabling email in web.xml

Modify web.xml by mapping email URLs to servlets:

<servlet>
<servlet-name>mailhandler</servlet-name>
<servlet-class>com.example.appengine.mail.MailHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mailhandler</servlet-name>
<url-pattern>/_ah/mail/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>mail</web-resource-name>
<url-pattern>/_ah/mail/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>

In the above snippets, /_ah/mail/* matches all email addressed to the app. Mail servlets run in the currently serving version of your app in App Engine.

Pattern-based dispatching of incoming messages

If your app uses pattern matching, consider using a filter-based approach based on the following code snippets.

Concrete handler

publicclass HandleDiscussionEmailextendsMailHandlerBase{
privatestaticfinalLoggerlog=Logger.getLogger(HandleDiscussionEmail.class.getName());
publicHandleDiscussionEmail(){super("discuss-(.*)@(.*)");}
@Override
protectedbooleanprocessMessage(HttpServletRequestreq,HttpServletResponseres)
throwsServletException
{
log.info("Received e-mail sent to discuss list.");
MimeMessagemsg=getMessageFromRequest(req);
Matchermatch=getMatcherFromRequest(req);
// ...
returntrue;
}
}

The above concrete handler is registered using the following snippet in web.xml:

<filter>
<filter-name>HandleDiscussionEmail</filter-name>
<filter-class>com.example.appengine.mail.HandleDiscussionEmail</filter-class>
</filter>
<filter-mapping>
<filter-name>HandleDiscussionEmail</filter-name>
<url-pattern>/_ah/mail/*</url-pattern>
</filter-mapping>

Note that security-constraint directives are not possible on filters; security policies on the handler will have to be introduced some other way.

Abstract handler

publicabstractclass MailHandlerBaseimplementsFilter{
privatePatternpattern=null;
protectedMailHandlerBase(Stringpattern){
if(pattern==null||pattern.trim().length()==0)
{
thrownewIllegalArgumentException("Expected non-empty regular expression");
}
this.pattern=Pattern.compile("/_ah/mail/"+pattern);
}
@Overridepublicvoidinit(FilterConfigconfig)throwsServletException{}
@Overridepublicvoiddestroy(){}
/**
 * Process the message. A message will only be passed to this method
 * if the servletPath of the message (typically the recipient for
 * appengine) satisfies the pattern passed to the constructor. If
 * the implementation returns false, control is passed
 * to the next filter in the chain. If the implementation returns
 * true, the filter chain is terminated.
 *
 * The Matcher for the pattern can be retrieved via
 * getMatcherFromRequest (e.g. if groups are used in the pattern).
 */
protectedabstractbooleanprocessMessage(HttpServletRequestreq,HttpServletResponseres)throwsServletException;
@Override
publicvoiddoFilter(ServletRequestsreq,ServletResponsesres,FilterChainchain)
throwsIOException,ServletException{
HttpServletRequestreq=(HttpServletRequest)sreq;
HttpServletResponseres=(HttpServletResponse)sres;
MimeMessagemessage=getMessageFromRequest(req);
Matcherm=applyPattern(req);
if(m!=null && processMessage(req,res)){
return;
}
chain.doFilter(req,res);// Try the next one
}
privateMatcherapplyPattern(HttpServletRequestreq){
Matcherm=pattern.matcher(req.getServletPath());
if(!m.matches())m=null;
req.setAttribute("matcher",m);
returnm;
}
protectedMatchergetMatcherFromRequest(ServletRequestreq){
return(Matcher)req.getAttribute("matcher");
}
protectedMimeMessagegetMessageFromRequest(ServletRequestreq)throwsServletException{
MimeMessagemessage=(MimeMessage)req.getAttribute("mimeMessage");
if(message==null){
try{
Propertiesprops=newProperties();
Sessionsession=Session.getDefaultInstance(props,null);
message=newMimeMessage(session,req.getInputStream());
req.setAttribute("mimeMessage",message);
}catch(MessagingExceptione){
thrownewServletException("Error processing inbound message",e);
}catch(IOExceptione){
thrownewServletException("Error processing inbound message",e);
}
}
returnmessage;
}
}

Handling incoming email

The JavaMail API includes the MimeMessage class which you can use to parse incoming email messages. MimeMessage has a constructor that accepts a java.io.InputStream and a JavaMail session, which can have an empty configuration.

Create a MimeMessage instance like this:

importjava.io.IOException;
importjava.util.logging.Logger;
importjava.util.Properties;
importjavax.mail.MessagingException;
importjavax.mail.Session;
importjavax.mail.internet.MimeMessage;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
publicclass MailHandlerServletextendsHttpServlet{
privatestaticfinalLoggerlog=Logger.getLogger(MailHandlerServlet.class.getName());
@Override
publicvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsIOException{
Propertiesprops=newProperties();
Sessionsession=Session.getDefaultInstance(props,null);
try{
MimeMessagemessage=newMimeMessage(session,req.getInputStream());
log.info("Received mail message.");
}catch(MessagingExceptione){
// ...
}
// ...
}
}

You can then use various methods to parse the message object:

  • Call getFrom() to return the sender of the message.
  • Call getContentType() to extract the message content type. The getContent() method returns an object that implements the Multipart interface.
  • Call getCount() to determine the number of parts
  • Call getBodyPart(int index) to return a particular body part.

After you set up your app to handle incoming email, you can use the development server console to simulate incoming email messages. To learn more, including how to start the development server, see The Java Development Server. After you start your application in the local development server, you can access your application by visiting the URL http://localhost:8888/_ah/admin/, replacing the value 8888 with whatever port you are using if you don't use the default port for the local development server.

In the development server, click Inbound Mail on the left side, fill out the form that appears, and click Send Email.

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025年12月09日 UTC.