Réception d'e-mails

Les e-mails sont envoyés à votre application en tant que requêtes HTTP. Pour traiter les e-mails entrants, vous devez associer les adresses e-mail aux servlets dans la configuration de votre application, puis inclure le code du servlet dans votre application. L'e-mail entrant génère des requêtes HTTP qui sont transmises aux servlets appropriés en vue de leur traitement.

Configurer votre application pour recevoir des e-mails

Lorsque vous créez une application, le traitement des e-mails entrants est désactivé par défaut. Si vous n'activez pas explicitement cette fonctionnalité dans votre application, les e-mails entrants sont ignorés.

Pour activer le service de messagerie entrante, modifiez les fichiers de configuration appengine-web.xml et web.xml :

Activer le traitement des e-mails dans appengine-web.xml

Modifiez appengine-web.xml en ajoutant une section inbound-services qui active le service de messagerie entrante :

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

Les e-mails sont envoyés à votre application en tant que requêtes HTTP POST à l'aide de l'URL suivante :

/_ah/mail/<ADDRESS>

<ADDRESS> est une adresse e-mail complète, y compris le nom de domaine. Notez que, même si votre application est déployée sur un domaine personnalisé, vous ne pouvez pas recevoir de messages envoyés aux adresses de ce domaine.

Activer le traitement des e-mails dans le fichier web.xml

Modifiez web.xml en mappant des URL de messagerie à des 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>

Dans les extraits ci-dessus, /_ah/mail/* correspond à tous les e-mails adressés à l'application. Les servlets de messagerie s'exécutent dans la version actuellement diffusée de votre application dans App Engine.

Distribution des messages entrants basée sur un motif

Si votre application utilise un filtrage par motif, vous pouvez envisager d'utiliser une approche basée sur le filtrage, inspirée des extraits de code suivants.

Gestionnaire concret

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

Le gestionnaire concret ci-dessus est enregistré à l'aide de l'extrait suivant dans 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>

Notez que les instructions security-constraint ne sont pas possibles sur les filtres. les règles de sécurité du gestionnaire devront être introduites d'une autre manière.

Gestionnaire abstrait

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

Gérer les e-mails reçus

L'API JavaMail inclut la classe MimeMessage que vous pouvez utiliser pour analyser les e-mails reçus. MimeMessage comporte un constructeur qui accepte un objet java.io.InputStream et une session JavaMail, dont la configuration peut être vide.

Créez une instance MimeMessage comme suit:

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

Vous pouvez ensuite employer différentes méthodes pour analyser l'objet message.

  • Appelez getFrom() pour renvoyer l'expéditeur du message.
  • Appelez getContentType() pour extraire le type de contenu du message. La méthode getContent() renvoie un objet qui implémente l'interface Multipart.
  • Appelez getCount() pour déterminer le nombre d'éléments
  • Appelez getBodyPart(int index) pour renvoyer une partie du corps du message.

Une fois que vous avez configuré votre application pour gérer les e-mails entrants, vous pouvez utiliser la console du serveur de développement pour simuler l'arrivée de courriers. Pour en savoir plus, en particulier sur le lancement du serveur de développement, consultez la section dédiée au Serveur de développement Java. Après avoir démarré votre application sur le serveur de développement local, vous pouvez y accéder au moyen de l’URL http://localhost:8888/_ah/admin/, en remplaçant la valeur 8888 par le port que vous avez choisi (si vous n’utilisez pas le port par défaut du serveur de développement local).

Sur le serveur de développement, cliquez sur Inbound Mail (Courrier entrant) dans la partie gauche, remplissez le formulaire qui s'affiche, puis cliquez sur Send Email (Envoyer un e-mail).