Receber email

As mensagens de email são enviadas para a sua app como pedidos HTTP. Para processar mensagens de email recebidas, tem de associar endereços de email a servlets na configuração da aplicação e, em seguida, incluir o código do servlet na sua app. O email recebido gera pedidos HTTP que são transmitidos aos servlets adequados para processamento.

Configurar a sua aplicação para receber emails

Quando cria uma nova aplicação, o email recebido está desativado por predefinição. Se não ativar explicitamente, as mensagens de email recebidas enviadas para a sua app são ignoradas.

Para ativar o serviço de email recebido, modifique os ficheiros de configuração appengine-web.xml e web.xml:

Ativar o email em appengine-web.xml

Modifique appengine-web.xml adicionando uma secção inbound-services que ativa o serviço de email recebido:

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

As mensagens de email são enviadas para a sua app como pedidos HTTP POST através do seguinte URL:

/_ah/mail/<ADDRESS>

em que <ADDRESS> é um endereço de email completo, incluindo o nome de domínio. Tenha em atenção que, mesmo que a sua app esteja implementada num domínio personalizado, não pode receber emails enviados para endereços nesse domínio.

Ativar email em web.xml

Modifique web.xml mapeando URLs de email para 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>

Nos fragmentos acima, /_ah/mail/* corresponde a todos os emails enviados para a app. Os servlets de correio são executados na versão atualmente publicada da sua app no App Engine.

Encaminhamento de mensagens recebidas com base em padrões

Se a sua app usar a correspondência de padrões, considere usar uma abordagem baseada em filtros com base nos seguintes fragmentos de código.

Manipulador de betão

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

O controlador concreto acima é registado através do seguinte fragmento no ficheiro 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>

Tenha em atenção que as diretivas security-constraint não são possíveis em filtros. As políticas de segurança no controlador têm de ser introduzidas de outra forma.

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

Processamento de emails recebidos

A API JavaMail inclui a classe MimeMessage, que pode usar para analisar mensagens de email recebidas. MimeMessage tem um construtor que aceita um java.io.InputStream e uma sessão do JavaMail, que pode ter uma configuração vazia.

Crie uma instância MimeMessage como esta:

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

Em seguida, pode usar vários métodos para analisar o objeto message:

  • Chame getFrom() para devolver o remetente da mensagem.
  • Chame getContentType() para extrair o tipo de conteúdo da mensagem. O método getContent() devolve um objeto que implementa a interface Multipart.
  • Ligue para getCount() para determinar o número de peças
  • Diga getBodyPart(int index) para devolver uma parte específica do corpo.

Depois de configurar a sua app para processar emails recebidos, pode usar a consola do servidor de desenvolvimento para simular mensagens de email recebidas. Para saber mais, incluindo como iniciar o servidor de desenvolvimento, consulte o artigo O servidor de desenvolvimento em Java. Depois de iniciar a aplicação no servidor de desenvolvimento local, pode aceder à aplicação visitando o URL http://localhost:8888/_ah/admin/, substituindo o valor 8888 pela porta que estiver a usar se não usar a porta predefinida para o servidor de desenvolvimento local.

No servidor de desenvolvimento, clique em Correio recebido no lado esquerdo, preencha o formulário apresentado e clique em Enviar email.