E-Mails empfangen

E-Mail-Nachrichten werden an Ihre Anwendung als HTTP-Anfragen gesendet. Zur Verarbeitung eingehender E-Mail-Nachrichten müssen Sie E-Mail-Adressen mit Servlets in Ihrer Anwendungskonfiguration verknüpfen und dann den Servlet-Code in Ihre App einbinden. Die eingehende E-Mail generiert HTTP-Anfragen, die zur Verarbeitung an die entsprechenden Servlets übergeben werden.

Anwendung für den Empfang von E-Mails konfigurieren

Wenn Sie eine neue Anwendung erstellen, sind eingehende E-Mails standardmäßig deaktiviert. Wenn Sie eingehende E-Mails nicht ausdrücklich aktivieren, werden an Ihre Anwendung gesendete Nachrichten ignoriert.

Zum Aktivieren des Dienstes für eingehende E-Mails ändern Sie die Konfigurationsdateien appengine-web.xml und web.xml:

E-Mails in appengine-web.xml aktivieren

Ändern Sie appengine-web.xml, indem Sie einen inbound-services-Abschnitt hinzufügen, der den Dienst für eingehende E-Mails aktiviert:

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

E-Mail-Nachrichten werden mit der folgenden URL als HTTP POST-Anfragen an Ihre Anwendung gesendet:

/_ah/mail/<ADDRESS>

<ADDRESS> ist eine vollständige E-Mail-Adresse, einschließlich des Domainnamens. Beachten Sie, dass Ihre Anwendung, selbst wenn sie in einer benutzerdefinierten Domain bereitgestellt wird, keine E-Mails an die Adressen in dieser Domain empfangen kann.

E-Mails in web.xml aktivieren

Ändern Sie web.xml, indem Sie E-Mail-URLs Servlets zuordnen:

<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 den obigen Snippets stimmt /_ah/mail/* mit allen E-Mails überein, die an die Anwendung adressiert sind. E-Mail-Servlets werden in der Version Ihrer Anwendung ausgeführt, die derzeit in App Engine ausgeführt wird.

Musterbasierte Verteilung eingehender Nachrichten

Wenn Ihre Anwendung den Musterabgleich nutzt, kann die Verwendung von Filtern auf der Grundlage der folgenden Code-Snippets eine gute Idee sein.

Konkreter Handler

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

Der obige konkrete Handler wird mit dem folgenden Snippet in web.xml registriert:

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

Beachten Sie, dass security-constraint-Anweisungen für Filter nicht möglich sind. Sicherheitsrichtlinien für den Handler müssen auf andere Weise eingeführt werden.

Abstrakter Handler

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

Eingehende E-Mails verarbeiten

Das JavaMail-API enthält die MimeMessage-Klasse, mit deren Hilfe Sie eingehende E-Mail-Nachrichten analysieren können. MimeMessage hat einen Konstruktor, der einen java.io.InputStream und eine JavaMail-Sitzung akzeptiert, die eine leere Konfiguration enthalten kann.

So erstellen Sie eine MimeMessage-Instanz:

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) {
      // ...
    }
    // ...
  }
}

Anschließend können Sie mit verschiedenen Methoden das message-Objekt analysieren:

  • Rufen Sie getFrom() auf, um den Absender der Nachricht zurückzugeben.
  • Rufen Sie getContentType() auf, um den Nachrichteninhaltstyp zu extrahieren. Die getContent()-Methode gibt ein Objekt zurück, das die Multipart-Schnittstelle implementiert.
  • Rufen Sie getCount() auf, um die Anzahl der Teile zu ermitteln.
  • Rufen Sie getBodyPart(int index) auf, um einen bestimmten Teil des Nachrichtentexts zurückzugeben.

Nachdem Sie Ihre Anwendung für die Verarbeitung eingehender E-Mails eingerichtet haben, können Sie mit der Entwicklungsserverkonsole eingehende E-Mail-Nachrichten simulieren. Weitere Informationen, einschließlich zum Starten des Entwicklungsservers, finden Sie unter Java-Entwicklungsserver. Nachdem Sie Ihre Anwendung auf dem lokalen Entwicklungsserver gestartet haben, können Sie auf Ihre Anwendung zugreifen. Rufen Sie hierfür die URL http://localhost:8888/_ah/admin/ auf und ersetzen Sie dabei den Wert 8888 durch den von Ihnen verwendeten Port, sofern Sie nicht den Standardport für den lokalen Entwicklungsserver übernehmen.

Klicken Sie im Entwicklungsserver links auf "Inbound Mail" (Eingehende E-Mails), füllen Sie das angezeigte Formular aus und klicken Sie auf "Send Email" (E-Mail senden).