How to send an email using MS exchange server
I am trying to sent an email using my company's mail server. But I am getting the following exception
Caused by: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.1 Client was not authenticated
at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:1388)
at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:959)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:583)
at javax.mail.Transport.send0(Transport.java:169)
at javax.mail.Transport.send(Transport.java:98)
Here is my sample code,
Properties props = System.getProperties();
// Setup mail server
props.put("mail.smtp.host", "example.server开发者_高级运维.com");
props.put("mail.smtp.auth", "true");
props.put("mail.debug", "true");
props.put("mail.smtp.port", "25");
// Get session
//Session session = Session.getDefaultInstance(props, null);
Session session = Session.getDefaultInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password");
}
});
// Define message
MimeMessage message = new MimeMessage(session);
// Set the from address
message.setFrom(new InternetAddress(from));
// Set the to address
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
// Set the subject
message.setSubject("Hello JavaMail");
// Set the content
message.setText("Welcome to JavaMail");
// Send message
Transport.send(message);
What piece of code is wrong? As as username and password , I am using my company's email address and password.
The 5.7.1 is probably caused by exchange and not your code. You may just need to enable relaying on the server. Either for anonymous users or from a certain IP address. I'm not an expert on Exchange but I have got this working before. Here is the last solution I tested that works:
If a 5.7.1 error is encountered when trying to send an email via SMTP on an exchange server when the user has been authenticated..
For ref the issue you just had was caused by a setting on the Exchange 2007 server – this would not normally be a problem on 2003 server
Fixed by doing below...
You can set this authentication setting via the GUI
- In Server configuration / Hub Transport / Default <ServerName>
- Right click, properties, Permission Groups
- Check "Anonymous users" and then click OK
Obviously anon users is not too secure but you could see if this solves the problem.
When I will use a MS Exhange SMTP Server to send an email, I use the above maven dependency.
<dependency>
<groupId>com.microsoft.ews-java-api</groupId>
<artifactId>ews-java-api</artifactId>
<version>2.0</version>
</dependency>
For that reason I created a class that represents an email client for MS Exchange Servers. I use log4j for logging.
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Below the MS Exchange client class (I use the builder pattern for the construction of the object for thread safety),
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
import microsoft.exchange.webservices.data.core.service.item.EmailMessage;
import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
import microsoft.exchange.webservices.data.credential.WebCredentials;
import microsoft.exchange.webservices.data.property.complex.MessageBody;
import org.apache.log4j.Logger;
/**
* A client to connect to a MS Exchange SMTP Server.
*/
public final class ExchangeClient {
private static final Logger LOGGER = Logger.getLogger(ExchangeClient.class);
private final String hostname;
private final ExchangeVersion exchangeVersion;
private final String domain;
private final String username;
private final String password;
private final String subject;
private final String recipientTo;
private final List<String> recipientCc;
private final List<String> recipientBcc;
private final List<String> attachments;
private final String message;
private ExchangeClient(ExchangeClientBuilder builder) {
this.hostname = builder.hostname;
this.exchangeVersion = builder.exchangeVersion;
this.domain = builder.domain;
this.username = builder.username;
this.password = builder.password;
this.subject = builder.subject;
this.recipientTo = builder.recipientTo;
this.recipientCc = builder.recipientCc;
this.recipientBcc = builder.recipientBcc;
this.attachments = builder.attachments;
this.message = builder.message;
}
public static class ExchangeClientBuilder {
private String hostname;
private ExchangeVersion exchangeVersion;
private String domain;
private String username;
private String password;
private String subject;
private String recipientTo;
private List<String> recipientCc;
private List<String> recipientBcc;
private List<String> attachments;
private String message;
public ExchangeClientBuilder() {
this.exchangeVersion = ExchangeVersion.Exchange2010_SP1;
this.hostname = "";
this.username = "";
this.password = "";
this.subject = "";
this.recipientTo = "";
this.recipientCc = new ArrayList<>(0);
this.recipientBcc = new ArrayList<>(0);
this.attachments = new ArrayList<>(0);
this.message = "";
}
/**
* The hostname of the Exchange Web Service. It will be used for
* connecting with URI https://hostname/ews/exchange.asmx
*
* @param hostname the hostname of the MS Exchange Smtp Server.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder hostname(String hostname) {
this.hostname = hostname;
return this;
}
/**
* The Exchange Web Server version.
*
* @param exchangeVersion the Exchange Web Server version.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder exchangeVersion(ExchangeVersion exchangeVersion) {
this.exchangeVersion = exchangeVersion;
return this;
}
/**
* The domain of the MS Exchange Smtp Server.
*
* @param domain the domain of the Active Directory. The first part of
* the username. For example: MYDOMAIN\\username, set the MYDOMAIN.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder domain(String domain) {
this.domain = domain;
return this;
}
/**
* The username of the MS Exchange Smtp Server. The second part of the
* username. For example: MYDOMAIN\\username, set the username.
*
* @param username the username of the MS Exchange Smtp Server.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder username(String username) {
this.username = username;
return this;
}
/**
* The password of the MS Exchange Smtp Server.
*
* @param password the password of the MS Exchange Smtp Server.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder password(String password) {
this.password = password;
return this;
}
/**
* The subject for this send.
*
* @param subject the subject for this send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder subject(String subject) {
this.subject = subject;
return this;
}
/**
* The recipient for this send.
*
* @param recipientTo the recipient for this send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder recipientTo(String recipientTo) {
this.recipientTo = recipientTo;
return this;
}
/**
* You can specify one or more email address that will be used as cc
* recipients.
*
* @param recipientCc the first cc email address.
* @param recipientsCc the other cc email address for this send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder recipientCc(String recipientCc, String... recipientsCc) {
// Prepare the list.
List<String> recipients = new ArrayList<>(1 + recipientsCc.length);
recipients.add(recipientCc);
recipients.addAll(Arrays.asList(recipientsCc));
// Set the list.
this.recipientCc = recipients;
return this;
}
/**
* You can specify a list with email addresses that will be used as cc
* for this email send.
*
* @param recipientCc the list with email addresses that will be used as
* cc for this email send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder recipientCc(List<String> recipientCc) {
this.recipientCc = recipientCc;
return this;
}
/**
* You can specify one or more email address that will be used as bcc
* recipients.
*
* @param recipientBcc the first bcc email address.
* @param recipientsBcc the other bcc email address for this send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder recipientBcc(String recipientBcc, String... recipientsBcc) {
// Prepare the list.
List<String> recipients = new ArrayList<>(1 + recipientsBcc.length);
recipients.add(recipientBcc);
recipients.addAll(Arrays.asList(recipientsBcc));
// Set the list.
this.recipientBcc = recipients;
return this;
}
/**
* You can specify a list with email addresses that will be used as bcc
* for this email send.
*
* @param recipientBcc the list with email addresses that will be used
* as bcc for this email send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder recipientBcc(List<String> recipientBcc) {
this.recipientBcc = recipientBcc;
return this;
}
/**
* You can specify one or more email address that will be used as cc
* recipients.
*
* @param attachment the first attachment.
* @param attachments the other attachments for this send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder attachments(String attachment, String... attachments) {
// Prepare the list.
List<String> attachmentsToUse = new ArrayList<>(1 + attachments.length);
attachmentsToUse.add(attachment);
attachmentsToUse.addAll(Arrays.asList(attachments));
// Set the list.
this.attachments = attachmentsToUse;
return this;
}
/**
* You can specify a list with email attachments that will be used for
* this email send.
*
* @param attachments the list with email attachments that will be used
* for this email send.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder attachments(List<String> attachments) {
this.attachments = attachments;
return this;
}
/**
* The body of the email message.
*
* @param message the body of the email message.
* @return the builder for chain usage.
*/
public ExchangeClientBuilder message(String message) {
this.message = message;
return this;
}
/**
* Build a mail.
*
* @return an EmailApacheUtils object.
*/
public ExchangeClient build() {
return new ExchangeClient(this);
}
}
public boolean sendExchange() {
// The Exchange Server Version.
ExchangeService exchangeService = new ExchangeService(exchangeVersion);
// Credentials to sign in the MS Exchange Server.
ExchangeCredentials exchangeCredentials = new WebCredentials(username, password, domain);
exchangeService.setCredentials(exchangeCredentials);
// URL of exchange web service for the mailbox.
try {
exchangeService.setUrl(new URI("https://" + hostname + "/ews/Exchange.asmx"));
} catch (URISyntaxException ex) {
LOGGER.error("An exception occured while creating the uri for exchange service.", ex);
return false;
}
// The email.
EmailMessage emailMessage;
try {
emailMessage = new EmailMessage(exchangeService);
emailMessage.setSubject(subject);
emailMessage.setBody(MessageBody.getMessageBodyFromText(message));
} catch (Exception ex) {
LOGGER.error("An exception occured while setting the email message.", ex);
return false;
}
// TO recipient.
try {
emailMessage.getToRecipients().add(recipientTo);
} catch (ServiceLocalException ex) {
LOGGER.error("An exception occured while sstting the TO recipient(" + recipientTo + ").", ex);
return false;
}
// CC recipient.
for (String recipient : recipientCc) {
try {
emailMessage.getCcRecipients().add(recipient);
} catch (ServiceLocalException ex) {
LOGGER.error("An exception occured while sstting the CC recipient(" + recipient + ").", ex);
return false;
}
}
// BCC recipient
for (String recipient : recipientBcc) {
try {
emailMessage.getBccRecipients().add(recipient);
} catch (ServiceLocalException ex) {
LOGGER.error("An exception occured while sstting the BCC recipient(" + recipient + ").", ex);
return false;
}
}
// Attachements.
for (String attachmentPath : attachments) {
try {
emailMessage.getAttachments().addFileAttachment(attachmentPath);
} catch (ServiceLocalException ex) {
LOGGER.error("An exception occured while setting the attachment.", ex);
return false;
}
}
try {
emailMessage.send();
LOGGER.debug("An email is send.");
} catch (Exception ex) {
LOGGER.error("An exception occured while sending an email.", ex);
return false;
}
return true;
}
}
A working example,
// import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
ExchangeClient client = new ExchangeClient.ExchangeClientBuilder()
.hostname("webmail.domainOfWeb.com")
.exchangeVersion(ExchangeVersion.Exchange2010)
.domain("ActiveDirectoryDomain")
.username("ActiveDirectoryUsername")
.password("ActiveDirectoryPassword")
.recipientTo("recipient@whatever.com")
.recipientCc("recipient@whatever.com") // Ignore it in case you will not use Cc recipients.
.recipientBcc("recipient@whatever.com") // Ignore it in case you will not use Bcc recipients.
.attachments("/home/username/image.png") // Ignore it in case you will not use attachements.
.subject("Test Subject")
.message("Test Message")
.build();
client.sendExchange();
Mail.jar (Version 1.4.0) has a compatibility issue with MS Exchange Server and throws 530 5.7.1 Client was not authenticated
, even when Username and password are configured.
Upgrading the mail API to 1.4.4 OR 1.4.7 should resolve the issue.
Mail API's 1.4.7 can be download from the following URL: http://www.oracle.com/technetwork/java/javamail/index.html
In some companies, the Exchange server SMTP support is disable and you cannot ask them to enable it. In these cases, a reasonable solution is this one:
http://davmail.sourceforge.net/
Simple Java Mail worked for me. The only thing you have to check is for correct hostname, username, port and password TransportStrategy.SMTP_TLS
:
new Mailer(host, port, username, password, TransportStrategy.SMTP_TLS).sendMail(email);
I had to use javamail + exchange. The messages returned were helpless. Thanks to the stack, I got some hints.
Add this to your code
props.put("mail.smtp.starttls.enable","true");
Think of adding the certificates of the machines used too. To find them, just go to your browser, export them and import to the cacerts file in use.
Please use the following code parts instead of Transport.send(message);
MimeMessage message = new MimeMessage(session);
message.saveChanges();
Transport transport = session.getTransport("smtp");
transport.connect(host, "user", "pwd");
transport.sendMessage(message, message.getAllRecipients());
transport.close();
I have tested in the local and it is working
The ews-java-api package is at end of life.
From https://github.com/OfficeDev/ews-java-api
Starting July 19th 2018, Exchange Web Services (EWS) will no longer receive feature updates. While the service will continue to receive security updates and certain non-security updates, product design and features will remain unchanged. This change also applies to the EWS SDKs for Java and .NET. More information here: https://developer.microsoft.com/en-us/graph/blogs/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/
精彩评论