接收电子邮件

电子邮件会作为 HTTP 请求发送到您的应用。如需处理传入电子邮件,您必须将电子邮件地址与应用配置中的 Servlet 关联起来,然后在您的应用中添加 Servlet 代码。传入电子邮件会生成 HTTP 请求,这些请求将传递到相应的 Servlet 进行处理。

配置应用以接收电子邮件

在您创建新应用时,系统会默认停用传入电子邮件。如果您未明确启用传入电子邮件,则发送到您的应用的邮件会被忽略。

如需启用传入电子邮件服务,请修改 appengine-web.xmlweb.xml 配置文件:

在 appengine-web.xml 中启用电子邮件

通过添加 inbound-services 部分来修改 appengine-web.xml,该部分可启用传入电子邮件服务:

<inbound-services>
  <!-- Used to handle incoming mail. -->
  <service>mail</service>
  <!-- Used to handle bounced mail notifications. -->
  <service>mail_bounce</service>
</inbound-services>

电子邮件将通过以下网址,作为 HTTP POST 请求发送到您的应用:

/_ah/mail/<ADDRESS>

其中,<ADDRESS> 是包含域名在内的完整电子邮件地址。请注意,即使您的应用部署在自定义网域中,也无法接收发送到该网域中地址的电子邮件。

在 web.xml 中启用电子邮件

通过将电子邮件网址映射到 Servlet 来修改 web.xml

<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>

在上述代码段中,/_ah/mail/* 与发送到应用的所有电子邮件均匹配。在 App Engine 中,邮件 Servlet 在应用的当前服务版本中运行。

基于格式的传入邮件调度

如果您的应用使用格式匹配,您可以考虑按以下代码段使用基于过滤器的方法。

具体处理程序

public class HandleDiscussionEmail extends MailHandlerBase {

  private static final Logger log = Logger.getLogger(HandleDiscussionEmail.class.getName());
  public HandleDiscussionEmail() { super("discuss-(.*)@(.*)"); }

  @Override
  protected boolean processMessage(HttpServletRequest req, HttpServletResponse res)
    throws ServletException
  {
    log.info("Received e-mail sent to discuss list.");
    MimeMessage msg = getMessageFromRequest(req);
    Matcher match = getMatcherFromRequest(req);
    // ...
    return true;
  }
}

上述具体处理程序使用 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>

请注意,security-constraint 指令不适用于过滤器;处理程序上的安全政策必须以其他方式引入。

抽象处理程序

public abstract class MailHandlerBase implements Filter {

  private Pattern pattern = null;

  protected MailHandlerBase(String pattern) {
    if (pattern == null || pattern.trim().length() == 0)
    {
      throw new IllegalArgumentException("Expected non-empty regular expression");
    }
    this.pattern = Pattern.compile("/_ah/mail/"+pattern);
  }

  @Override public void init(FilterConfig config) throws ServletException { }

  @Override public void destroy() { }

  /**
   * 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).
   */
  protected abstract boolean processMessage(HttpServletRequest req, HttpServletResponse res) throws ServletException;

  @Override
  public void doFilter(ServletRequest sreq, ServletResponse sres, FilterChain chain)
      throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) sreq;
    HttpServletResponse res = (HttpServletResponse) sres;

    MimeMessage message = getMessageFromRequest(req);
    Matcher m = applyPattern(req);

    if (m != null && processMessage(req, res)) {
      return;
    }

    chain.doFilter(req, res); // Try the next one

  }

  private Matcher applyPattern(HttpServletRequest req) {
    Matcher m = pattern.matcher(req.getServletPath());
    if (!m.matches()) m = null;

    req.setAttribute("matcher", m);
    return m;
  }

  protected Matcher getMatcherFromRequest(ServletRequest req) {
    return (Matcher) req.getAttribute("matcher");
  }

  protected MimeMessage getMessageFromRequest(ServletRequest req) throws ServletException {
    MimeMessage message = (MimeMessage) req.getAttribute("mimeMessage");
    if (message == null) {
      try {
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);
        message = new MimeMessage(session, req.getInputStream());
        req.setAttribute("mimeMessage", message);

      } catch (MessagingException e) {
        throw new ServletException("Error processing inbound message", e);
      } catch (IOException e) {
        throw new ServletException("Error processing inbound message", e);
      }
    }
    return message;
  }
}

处理传入电子邮件

JavaMail API 包含 MimeMessage 类,您可以使用此类解析传入电子邮件。MimeMessage 具有一个可接受 java.io.InputStream 和 JavaMail 会话的构造函数,该构造函数的配置可以为空。

创建一个 MimeMessage 实例,如下所示:

import java.io.IOException;
import java.util.logging.Logger;
import java.util.Properties;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MailHandlerServlet extends HttpServlet {

  private static final Logger log = Logger.getLogger(MailHandlerServlet.class.getName());

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    Properties props = new Properties();
    Session session = Session.getDefaultInstance(props, null);
    try {
      MimeMessage message = new MimeMessage(session, req.getInputStream());
      log.info("Received mail message.");
    } catch (MessagingException e) {
      // ...
    }
    // ...
  }
}

然后,您可以使用各种方法来解析 message 对象:

  • 调用 getFrom() 可返回邮件的发件人。
  • 调用 getContentType() 可提取邮件内容类型。getContent() 方法可返回实现 Multipart 接口的对象。
  • 调用 getCount() 可确定所含部分的数量
  • 调用 getBodyPart(int index) 可返回特定的正文部分。

在将您的应用设置为处理传入电子邮件后,您可以使用开发服务器控制台模拟传入电子邮件。如需了解更多信息,包括如何启动开发服务器,请参阅 Java 开发服务器。在本地开发服务器中启动您的应用后,您可以通过以下网址访问您的应用:http://localhost:8888/_ah/admin/,如果您使用的不是本地开发服务器的默认端口,请将值 8888 替换成您正在使用的任何端口。

在开发服务器中,点击左侧的“入站邮件”(Inbound Mail),填写显示的表单,然后点击“发送电子邮件”。