我正在开发Google App Engine应用程序
我希望收到'%usernamename%@appid.appspotmail.com'下的邮件,其中%username%属于该应用程序的用户。
我只是无法弄清楚在web.xml
文件中定义什么
任何类似的解决方案,如邮件:
是可以接受的(如果使用通配符更容易)。
我试过(按照Gopi的建议)
将相关的servlet映射到<url-pattern>/_ah/mail/user.*</url-pattern>
文件中的web.xml
。它不起作用。
客户端收到退回邮件,而服务器日志会显示应用程序收到的相关请求,但会被404拒绝。否“没有处理程序与此网址匹配。” INFO被添加到日志条目中。另外,在获取生成的URL时,我没有得到“这个页面不支持GET”,而是一个普通的404.
但是,如果我发送邮件说'info@appid.appspotmail.com',则日志显示404(它们应该,因为它没有映射到web.xml中)。此外,对于此类请求,“没有处理程序与此URL匹配”。 INFO被添加到相关的日志条目中。
毋庸置疑,在已配置服务下找到接收邮件。
答案 0 :(得分: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;
}
}
答案 1 :(得分:2)
以下提供了一个可信的解释,谢谢 url-pattern and wildcards 指的是 http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index2.html(滚动到第11.2节)
在url-pattern中,*通配符的行为与人们假设的行为不同, 除了以外,它被视为普通人物 - 当字符串以/ *表示“路径映射”时 - 或者以*开头。用于“扩展映射”
太糟糕了,如果将Google电子邮件收件人地址与不同的servlet相匹配,那本来很不错,如Google的API doc示例所示。我现在使用的绝对匹配并不像appid那样干净。
答案 2 :(得分: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>
答案 3 :(得分:0)
嗯......在尝试了所有可能的解决方案/ url-mapping之后,我选择了快速而丑陋的解决方案
要点是拥有一个“全部捕获”邮件servlet,作为其他特定servlet的调度程序。 就像一个巨人switch
,其中参数是请求网址
这不是我想要的,但它有效,似乎是唯一有效的。
我有一个servlet IncomingMail
来处理所有传入的邮件。期。
现在,/_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,映射为“普通的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收到的email参数的格式为'%un%@ appid.appspotmail.com',没有辨别前缀。
每个这样的“特定”servlet都会从邮件调度程序servlet中获得“剪切”,其中email参数已经没有识别前缀。
我将在安全性下添加一条注释:
如果您担心对“特定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>
邮件映射,而不是一个全能的邮件映射。
答案 4 :(得分:0)
我有类似的问题(使用Python,所以yaml配置文件而不是XML),原因是因为我把:
- url: /_ah/mail/.+
script: handle_incoming_email.py
login: admin
在现有的全包条目之前:
- url: /.*
script: main.py
这会在服务器上显示404,并在发送测试消息时显示“消息发送失败”。
在catch-all条目解决问题后移动它。
答案 5 :(得分:0)
我很确定问题只是你正在尝试使用.*
。 web.xml
中的网址表达式是整数,而不是正则表达式,因此您应该只使用*
代替 - .*
只会匹配以点开头的字符串。