接收電子郵件

電子郵件將以 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/* 會比對所有寄給應用程式的電子郵件。郵件 Servlet 會在 App Engine 中目前提供服務的應用程式版本中執行。

傳入電子郵件的模式分派

如果應用程式使用模式比對,請考慮依據下列程式碼片段使用篩選器方法。

具體處理常式

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 值替換為您使用的任何通訊埠。

在開發伺服器中,按一下左側的 [傳入郵件],填寫顯示的表單,然後按一下 [傳送電子郵件]。