Como receber e-mail

Mensagens de e-mail são enviadas para seu aplicativo como solicitações HTTP. Para processar mensagens de e-mail recebidas, você precisa associar endereços de e-mail a servlets na configuração do seu aplicativo e, em seguida, incluir o código do servlet com o aplicativo. O e-mail recebido gera solicitações HTTP que são transmitidas aos servlets apropriados para manipulação.

Como configurar o aplicativo para receber e-mails

Quando você cria um novo aplicativo, a opção de e-mails recebidos fica desativada por padrão. Ative as mensagens de e-mail recebidas pelo seu aplicativo para que não sejam ignoradas.

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

Como ativar o serviço de e-mail em appengine-web.xml

Modifique appengine-web.xml adicionando uma seção inbound-services que ativa o serviço de e-mail de entrada:

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

Mensagens de e-mail são enviadas para seu aplicativo como solicitações HTTP POST usando este URL:

/_ah/mail/<ADDRESS>

em que <ADDRESS> é um endereço de e-mail completo, incluindo o nome do domínio. Mesmo que seu aplicativo seja implantado em um domínio personalizado, não é possível receber e-mails enviados para endereços nesse domínio.

Como ativar o serviço de e-mail em web.xml

Modifique web.xml mapeando URLs de e-mail 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 snippets acima, /_ah/mail/* corresponde a todos os e-mails endereçados ao aplicativo. Os servlets de e-mail são executados na versão atualmente em exibição do seu aplicativo no Google App Engine.

Despacho baseado em padrões de mensagens recebidas

Se o aplicativo usa correspondência de padrões, utilize uma abordagem baseada em filtro com base nos snippets de código a seguir.

Gerenciador concreto

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 gerenciador de concreto acima é registrado usando o seguinte snippet em 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>

Observe que as diretivas security-constraint não são possíveis em filtros. As políticas de segurança no gerenciador precisarão ser introduzidas de outra forma.

Gerenciador abstrato

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

Como processar os e-mails recebidos

A API do JavaMail inclui a classe MimeMessage que pode ser usada para analisar mensagens de e-mail recebidas. MimeMessage tem um construtor que aceita um java.io.InputStream e uma sessão 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, é possível usar vários métodos para analisar o objeto message.

  • Chame getFrom() para retornar o remetente da mensagem.
  • Chame getContentType() para extrair o tipo de conteúdo da mensagem. O método getContent() retorna um objeto que implementa a interface Multipart.
  • Chamar getCount() para determinar o número de partes
  • Chame getBodyPart(int index) para retornar uma parte específica do corpo.

Depois de configurar seu aplicativo para processar os e-mails recebidos, é possível usar o console do servidor de desenvolvimento para simular mensagens de e-mail recebidas. Para saber mais, incluindo como iniciar o servidor de desenvolvimento, consulte o servidor de desenvolvimento Java. Depois de iniciar o aplicativo no servidor de desenvolvimento local, é possível acessá-lo pelo URL http://localhost:8888/_ah/admin/, substituindo o valor 8888 por qualquer porta usada, caso não seja a padrão.

No servidor de desenvolvimento, clique em "Inbound Mail" no lado esquerdo, preencha o formulário que aparece e clique em "Send Email".