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.
--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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With