当地址正常时使用 javax.mail 获取无效地址

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/240166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:54:44  来源:igfitidea点击:

Getting Invalid Address with javax.mail when the addresses are fine

javaemail

提问by Steven M. Cherry

I'm using the javax.mail system, and having problems with "Invalid Address" exceptions. Here's the basics of the code:

我正在使用 javax.mail 系统,并且遇到了“无效地址”异常的问题。以下是代码的基础知识:

    // Get system properties
    Properties props = System.getProperties();

    // Setup mail server
    props.put("mail.smtp.host", m_sending_host);

    // Get session
    Session session = Session.getDefaultInstance(props, new Authenticator(){
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(m_sending_user, m_sending_pass);
        }
    });


    // Define message
    MimeMessage message = new MimeMessage(session);
    message.setFrom(new InternetAddress(m_sending_from));
    message.addRecipient(Message.RecipientType.TO, 
        new InternetAddress(vcea.get(i).emailaddr));
    message.setSubject( replaceEnvVars(subject) );
    message.setText(replaceEnvVars(body));

    // Send message
    try {
        Transport.send(message);
    } catch (Exception e){
        Log.Error("Error sending e-mail to addr (%s): %s",
                vcea.get(i).emailaddr, e.getLocalizedMessage() );

    }

The issue is that the above code does work, sometimes. But for some e-mail addresses that I know to be valid (because I can send to them via a standard e-mail client), the above code will throw an "Invalid Address" exception when trying to send.

问题是上面的代码有时确实有效。但是对于一些我知道有效的电子邮件地址(因为我可以通过标准电子邮件客户端发送给他们),上面的代码在尝试发送时会抛出“无效地址”异常。

Any clues or hints would be greatly appreciated.

任何线索或提示将不胜感激。

--Update: problem with authentication.

--更新:身份验证问题。

Ok, here's what I've discovered was going on. When receiving e-mail, the code above correctly sets up authentication and the Authenticator.getPasswordAuthentication() callback is actually invoked.

好的,这就是我发现正在发生的事情。接收电子邮件时,上面的代码正确设置了身份验证并实际调用了 Authenticator.getPasswordAuthentication() 回调。

Not so when sending e-mail. You have to do a bit more. Add this:

发送电子邮件时并非如此。你必须多做一点。添加这个:

    // Setup mail server
    props.put("mail.smtp.host", m_sending_host);
    props.put("mail.smtp.auth", "true");

which will force the javax.mail API to do the login authentication. And then use an actual Transport instance instead of the static .send() method:

这将强制 javax.mail API 进行登录验证。然后使用实际的 Transport 实例而不是静态的 .send() 方法:

    Transport t = session.getTransport(m_sending_protocol);
    t.connect(m_sending_user, m_sending_pass);

...

...

        // Send message
        try {
            t.sendMessage(message, message.getAllRecipients());
        } catch (Exception e){

Without forcing the authentication, the mail server saw me as an unauthorized relay, and just shut me down. The difference between the addresses that "worked" and the addresses that didn't was that the ones that "worked" were all local to the mail server. Therefore, it simply accepted them. But for any non-local "relay" addresses, it would reject the message because my authentication information hadn't been presented by the javax.mail API when I thought it would have.

没有强制认证,邮件服务器将我视为未经授权的中继,然后将我关闭。“有效”的地址和无效的地址之间的区别在于,“有效”的地址都是邮件服务器本地的。因此,它只是接受了它们。但是对于任何非本地“中继”地址,它会拒绝该消息,因为 javax.mail API 没有提供我认为应该提供的身份验证信息。

Thanks for the clues to prompt me to look at the mail server side of things as well.

感谢提示我也查看邮件服务器端的线索。

采纳答案by Steven M. Cherry

--Update: problem with authentication.

--更新:身份验证问题。

Ok, here's what I've discovered was going on. When receiving e-mail, the code above correctly sets up authentication and the Authenticator.getPasswordAuthentication() callback is actually invoked.

好的,这就是我发现正在发生的事情。接收电子邮件时,上面的代码正确设置了身份验证并实际调用了 Authenticator.getPasswordAuthentication() 回调。

Not so when sending e-mail. You have to do a bit more. Add this:

发送电子邮件时并非如此。你必须多做一点。添加这个:

// Setup mail server
props.put("mail.smtp.host", m_sending_host);
props.put("mail.smtp.auth", "true");

which will force the javax.mail API to do the login authentication. And then use an actual Transport instance instead of the static .send() method:

这将强制 javax.mail API 进行登录验证。然后使用实际的 Transport 实例而不是静态的 .send() 方法:

Transport t = session.getTransport(m_sending_protocol);
t.connect(m_sending_user, m_sending_pass);

...

...

    // Send message
    try {
        t.sendMessage(message, message.getAllRecipients());
    } catch (Exception e){

Without forcing the authentication, the mail server saw me as an unauthorized relay, and just shut me down. The difference between the addresses that "worked" and the addresses that didn't was that the ones that "worked" were all local to the mail server. Therefore, it simply accepted them. But for any non-local "relay" addresses, it would reject the message because my authentication information hadn't been presented by the javax.mail API when I thought it would have.

没有强制认证,邮件服务器将我视为未经授权的中继,然后将我关闭。“有效”的地址和无效的地址之间的区别在于,“有效”的地址都是邮件服务器本地的。因此,它只是接受了它们。但是对于任何非本地“中继”地址,它会拒绝该消息,因为 javax.mail API 没有提供我认为应该提供的身份验证信息。

Thanks for the clues to prompt me to look at the mail server side of things as well.

感谢提示我也查看邮件服务器端的线索。

回答by Agusti-N

Try this:

尝试这个:

String to="[email protected]";
String cc="[email protected],[email protected]"; //The separator ',' works good

message.setRecipients(Message.RecipientType.TO,new InternetAddress[] { 
new InternetAddress(to) }); // This is only one mail

InternetAddress[] addr = parseAddressList(cc); //Here add all the rest of the mails
message.setRecipients(Message.RecipientType.CC,addr);

Sorry for my english. It's not good.

对不起我的英语不好。这不好。

回答by Alex B

I would change the call to InternetAddress to use the "strict" interpretation and see if you get further errors on the addresses you are having trouble with.

我会更改对 InternetAddress 的调用以使用“严格”解释,并查看是否在遇到问题的地址上出现更多错误。

message.addRecipient(Message.RecipientType.TO, 
        new InternetAddress(vcea.get(i).emailaddr, true ));
//                                                 ^^^^ turns on strict interpretation

Javadoc for InternetAddress constructor

InternetAddress 构造函数的 Javadoc

If this fails, it will throw an AddressExceptionwhich has a method called getPos()which returns the position of the failure (Javadoc)

如果失败,它会抛出一个返回失败位置的AddressException方法getPos()Javadoc

回答by Steven M. Cherry

This seems to me like a problem that happened at my work. If the code you are showing is being concurrent, then using directly System.getProperties could be a problem, because the host value you put on them can be overwritten by next request, while still keeping the user and password from the overwritten host.

在我看来,这就像我工作中发生的一个问题。如果您显示的代码是并发的,那么直接使用 System.getProperties 可能会出现问题,因为您放置在它们上的主机值可能会被下一个请求覆盖,同时仍然保留来自被覆盖主机的用户和密码。

In our case, we solved that using a clone of the System.getProperties() hashtable.

在我们的例子中,我们使用 System.getProperties() 哈希表的克隆解决了这个问题。

Hope that helps (this problem was really hard to track).

希望有所帮助(这个问题真的很难追踪)。

回答by Alex Cheptsov

A good hint for those using the ssl encryption in the smtp configuration, you should enable it by specifying the property mail.smtp.ssl.enable, as shown below:

对于在 smtp 配置中使用 ssl 加密的人来说,这是一个很好的提示,您应该通过指定属性来启用它mail.smtp.ssl.enable,如下所示:

props.put("mail.smtp.ssl.enable", "true");

Otherwise it can lead to similar problems as described above.

否则,它可能会导致与上述类似的问题。