обработка входящей почты движка приложения - PullRequest
2 голосов
/ 25 августа 2010

Я занимаюсь разработкой приложения Google App Engine.
Я хочу получать письма по адресу "%username%@appid.appspotmail.com", где% username% принадлежит пользователю приложения.
Я простоне могу понять, что определить в web.xml файле.
Любое подобное решение, например, отправка по почте:

  • '%username%.usermailbox@appid.appspotmail.com'
  • 'usermailbox.%username%@appid.appspotmail.com'

допустимо (если это облегчает использование подстановочных знаков).

Я пытался (как подсказал Гопи)
сопоставить соответствующий сервлет с <url-pattern>/_ah/mail/user.*</url-pattern> в файле web.xml.Это не работает.
Клиент получает сообщение об отказе, тогда как в журналах сервера отображается соответствующий запрос, полученный приложением, но отклоненный с 404. Нет"Ни один обработчик не соответствует этому URL-адресу".Информация добавляется в запись журнала.Кроме того, при получении сгенерированного URL я не получаю «Эта страница не поддерживает GET», а просто 404.
Если я, тем не менее, отправляю письмо, чтобы сказать «info@appid.appspotmail.com»,журналы показывают 404 (что они должны, так как он не отображается в web.xml).Кроме того, для такого запроса «URL не соответствует ни одному обработчику».Информация добавляется в соответствующую запись журнала.

Само собой разумеется, что Входящая почта найдена в Сконфигурированных сервисах .

Ответы [ 6 ]

3 голосов
/ 30 ноября 2012

Это изменение произошло, когда App Engine начал использовать настоящий веб-сервер Java (и поэтому объяснение Тоби уместно ... к сожалению, я не могу восстановить свой логин, чтобы проголосовать за него!).Я рекомендую использовать фильтр.Я играл с фильтром ниже, когда писал игрушечное приложение для GAE.После того, как вы определили базовый класс в конце этого поста, вы можете создать серию обработчиков почты (как показано ниже).Все, что вам нужно сделать, это зарегистрировать каждый фильтр в файле web.xml для обработки /_ah/mail/*.

public class HandleDiscussionEmail extends MailHandlerBase {

  public HandleDiscussionEmail() { super("discuss-(.*)@(.*)"); }

  @Override
  protected boolean processMessage(HttpServletRequest req, HttpServletResponse res)
    throws ServletException 
  { 
    MimeMessage msg = getMessageFromRequest(req); 
    Matcher match = getMatcherFromRequest(req);
    ...
 }

}

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 <code>false</code>, control is passed
   * o the next filter in the chain. If the implementation returns
   * <code>true</code>, 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;
  }



}
2 голосов
/ 06 февраля 2011

следующее дает правдоподобное объяснение, благодаря шаблон URL и шаблоны что относится к http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index2.html (выделите раздел 11.2)

В шаблоне url подстановочный знак * ведет себя иначе, чем можно было бы предположить, это рассматривается как нормальный символ, за исключением -когда строка заканчивается / * для "отображения пути" или начинается с *. для "карт расширения"

Жаль, было бы неплохо сопоставлять адреса получателей электронной почты с подстановочными знаками для различных сервлетов, как показано в примерах документов Google API. Сейчас я использую абсолютные совпадения, которые не так чисты, как нужно включить appid.

0 голосов
/ 06 декабря 2011

Я уверен, что проблема в том, что вы пытаетесь использовать .*. Выражения URL в web.xml представляют собой глобусы, а не регулярные выражения, поэтому вместо них следует использовать * - .* будет соответствовать только строкам, начинающимся с точки.

0 голосов
/ 02 августа 2011

У меня была похожая проблема (с использованием Python, поэтому файлы конфигурации yaml, а не XML), и причина оказалась в том, что я поставил:

- url: /_ah/mail/.+ 
  script: handle_incoming_email.py 
  login: admin

перед существующей записью для всех:

- url: /.*
  script: main.py

Это выдало 404 с на сервере и «Ошибка отправки сообщения» при отправке тестовых сообщений.

Перемещение после записи все-таки решило проблему.

0 голосов
/ 26 августа 2010

Ну ... Попробовав каждое возможное решение / отображение URL, я выбрал быстрый и уродливый вариант.
Суть в том, чтобы иметь один почтовый сервлет "перехватить все", чтобы он работал в качестве диспетчера для других,конкретные, сервлеты.Это как гигант switch, где параметром является URL-адрес запроса.
Это НЕ то, что я хотел, но он работает и, кажется, единственный, который делает.

У меня есть один сервлет IncomingMail, который обрабатывает ВСЕ входящие письма.period.
Итак, теперь единственное сопоставление URL-адресов в /_ah/mail/ выглядит следующим образом:

<servlet>
    <servlet-name>IncomingMail</servlet-name>
    <servlet-class>IncomingMail</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>IncomingMail</servlet-name>
    <url-pattern>/_ah/mail/*</url-pattern>
</servlet-mapping>

Кроме того, у меня есть следующий сервлет, отображенный как "plain-old-servlet":
(обратите внимание на <url-pattern>, а не на сервлет с отображением почты)

<servlet>
    <servlet-name>GetUserMail</servlet-name>
    <servlet-class>GetUserMail</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>GetUserMail</servlet-name>
    <url-pattern>/serv/userMail</url-pattern>
</servlet-mapping>

Универсальный сервлет (в конечном итоге) будет выглядеть как гигантский переключатель:

public class IncomingMail extends HttpServlet {
    private final String USER_MAIL_PREFIX="http://appid.appspot.com/_ah/mail/user.";
    private final String USER_MAIL_SERVLET="/serv/userMail";
    ...
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String url = req.getRequestURL().toString();
        System.out.println("IncomingMail called, with URL: "+url);
        String email;
        String servlet;

        if (url.startsWith(USER_MAIL_PREFIX)) {
            email=url.replace(USER_MAIL_PREFIX, "");
            servlet=USER_MAIL_SERVLET;
        }//userMail 
        if (url.startsWith(OTHER_PREFIX)) {
            //Redirect to OTHER servlet
        }
        ...
        System.out.println("forward to '"+servlet+"', with email '"+email+"'");
        RequestDispatcher dispatcher=req.getRequestDispatcher(servlet);
        try {
            req.setAttribute("email", email);
            dispatcher.forward(req, resp);
        } catch (ServletException e) {              
            System.err.println(e);
        }           

    }
}

Сервлет-адресат (в данном случае GetUserMail) делает getRequestParameter("email"), чтобы увидеть конкретный конечный почтовый ящик.
Он будет получать все письма, отправленные на 'user.%un%@appid.appspotmail.com',где% un% - это имя пользователя в пространстве приложения.
Параметр электронной почты, полученный сервлетом, будет иметь форму «%un%@appid.appspotmail.com» без префиксного имени.
Каждый такой »конкретный «сервлет» получит «свою вырезку» из сервлета диспетчера почты с параметром электронной почты, уже не имеющим префикса распознавания.

Одна заметка, которую я добавлю под защитой:
Если вы беспокоитесь о фальшивкезапросы к «конкретным сервлетам», просто определите их все под общим virtual namespace скажет /servmail/ на вашем сайте и определит новый <security-constraint>, чтобы запросы могли отправляться только внутри самого приложения.
Примерно так (внутри web.xml):

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>MailServlets</web-resource-name>
            <description>policy for specific mail servlets</description>
            <url-pattern>/servmail/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

БудетЯ до сих пор люблю слышать от кого-то, что пытался и пытался сделать подстановочный знак <url-pattern> сопоставление почты, кроме универсального.

0 голосов
/ 25 августа 2010

Я думаю, что размещение записи, аналогичной приведенной ниже, в вашем файле web.xml должно соответствовать вашему второму случаю 'usermailbox.%username%@appid.appspotmail.com

<servlet>
  <servlet-name>handlemail</servlet-name>
  <servlet-class>HandleMyMail</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>handlemail</servlet-name>
  <url-pattern>/_ah/mail/usermailbox.*</url-pattern>
</servlet-mapping>
...