2

我正在开发一个 Google App Engine 应用程序。
我希望在 '%username%@appid.appspotmail.com' 下接收邮件,其中 %username% 属于应用程序的用户。
我只是不知道在web.xml文件中定义什么。
任何类似的解决方案,例如邮寄至:

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

是可以接受的(如果使用通配符更容易)。

我已经尝试(如 Gopi 所建议的)
将相关的 servlet 映射到<url-pattern>/_ah/mail/user.*</url-pattern>文件web.xml中。它不工作。
客户端收到退回消息,而服务器日志显示应用收到的相关请求,但以 404 被拒绝。没有“没有处理程序与此 URL 匹配”。INFO 被添加到日志条目中。此外,在获取生成的 URL 时,我没有收到“此页面不支持 GET”,而是一个普通的 404。
但是,如果我发送邮件说“info@appid.appspotmail.com”,日志显示一个 404(他们应该这样做,因为它没有在 web.xml 中映射)。此外,对于这样的请求,“没有处理程序匹配此 URL”。INFO 被添加到相关的日志条目中。

不用说,传入的邮件是在 Configured Services 下找到的

4

6 回答 6

3

当 App Engine 开始使用真正的 Java Web 服务器时发生了这种变化(因此 Toby 的解释是正确的……遗憾的是,我似乎无法恢复我的登录来投票!)。我的建议是使用过滤器。在为 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;
  }



}
于 2012-11-30T18:23:40.503 回答
2

以下提供了一个合理的解释,这要归功于 引用 http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index2.html的url-pattern 和通配符(滚动到第 11.2 节)

在 url 模式中, * 通配符的行为与人们所假设的不同,它被视为普通字符,除了 - 当字符串以 /* 结尾时用于“路径映射” - 或者它以 * 开头。对于“扩展映射”

太糟糕了,将通配符匹配电子邮件收件人地址到不同的 servlet 会很好,如 Google 的 API 文档示例中所述。我现在使用的是绝对匹配,它不像 appid 需要包含的那样干净。

于 2011-02-06T20:51:56.317 回答
0

我认为将类似于下面的条目放入您的 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>
于 2010-08-25T17:06:40.130 回答
0

好吧......在尝试了所有可能的解决方案/url映射之后,我选择了一个又快又丑的解决方案。
要点是拥有一个“包罗万象”的邮件 servlet,作为其他特定 servlet 的调度程序。它就像一个巨人switch,其中参数是请求 URL。
这不是我想要的,但它有效,而且似乎是唯一有效的。

我有一个IncomingMail处理所有传入邮件的 servlet。时期。
所以现在,唯一的 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>

此外,我有以下 servlet,映射为“plain-old-servlet”:(
注意<url-pattern>,不是“邮件映射”servlet)

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

包罗万象的 servlet(最终会)看起来像一个巨大的开关:

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

    }
}

目标 servlet(GetUserMail在本例中)执行getRequestParameter("email"), 以查看特定的目标邮箱。
它将接收发送到“user.%un%@appid.appspotmail.com”的所有邮件,其中 %un% 是应用程序空间中的用户名。
servlet 接收到的电子邮件参数的格式为“%un%@appid.appspotmail.com”,没有识别前缀。
每个这样的“特定” servlet 都会从邮件调度程序 servlet 中获得“其切割”,其中电子邮件参数已经没有识别前缀。

我将在安全性下添加一个注释:
如果您担心对“特定 servlet”的虚假请求,只需将它们全部定义/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>邮件映射,而不是包罗万象的。

于 2010-08-26T08:56:18.903 回答
0

我有一个类似的问题(使用 Python,所以是 yaml 配置文件而不是 XML),原因原来是因为我放了:

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

在现有的全部条目之前:

- url: /.*
  script: main.py

这在发送测试消息时在服务器上产生 404 和“消息发送失败”。

在全部条目之后移动它可以解决问题。

于 2011-08-01T22:10:26.727 回答
0

我相当确定问题只是您尝试使用.*. 中的URL 表达式web.xml是 glob,而不是正则表达式,因此您应该使用 just*代替 -.*只会匹配以点开头的字符串。

于 2011-12-05T23:04:06.820 回答