tags:

views:

1675

answers:

6

Hi All,

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

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

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:

 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.

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

A: 

Is there an error with hostname resolution going on?

Dave
The InternetAddress constructor doesn't attempt to resolve hostnames...
matt b
A: 

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 mails
message.setRecipients(Message.RecipientType.CC,addr);

Sorry for my english. It's not good.

Agusti-N
+1  A: 

So it's Transport.send that is raising the exception, not the InternetAddress constructor?

I wonder if that means that it is the SMTP server that is giving you the error, not the Java library itself.

Dave Costa
+2  A: 

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.

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

Javadoc for InternetAddress constructor

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

Alex B
+2  A: 

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

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:

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.

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

Steven M. Cherry
A: 

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.

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

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