Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

email

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.

like image 686
Steven M. Cherry Avatar asked Oct 27 '08 14:10

Steven M. Cherry


2 Answers

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

like image 136
Steven M. Cherry Avatar answered Oct 06 '22 01:10

Steven M. Cherry


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)

like image 41
Alex B Avatar answered Oct 06 '22 01:10

Alex B