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/
Related
I have a piece of Java code (see below), which has not been changed in a while and worked two weeks ago. When I run it now, I suddenly get an "AUTHENTICATE FAILED." I get the error on two different PCs, and I have validated that the credentials used still work when I log into may office365 mailbox using the browser.
Has something changed on the office365 side I should know of?
The error I get is:
javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:732)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at my.application.input.imap.ImapMailBoxReader.processOnMessages(ImapMailBoxReader.java:69)
Digging deeper, the cause seems to be an A3 NO AUTHENTICATE failed. response (line 730 of javax.mail.IMAPStore).
The code I use is the following (using javax.mail version 1.6.2):
package my.application.input.imap;
import my.application.dao.PhysicalTransactionDao;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.search.AndTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.SearchTerm;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.io.*;
import java.util.function.Consumer;
public class ImapMailBoxReader {
private String host;
private String username;
private String password;
public static void main(String[] args) {
ImapMailBoxReader imapReader = new ImapMailBoxReader(
"outlook.office365.com",
"myemail",
"mypassword");
LocalDate startDate = LocalDate.of(2022,4,1);
LocalDate endDate = LocalDate.of(2022,7,1);
imapReader.processOnMessages("Inbox", startDate, endDate, SomeClass::processMessage);
}
public ImapMailBoxReader(String host, String username, String password) {
this.host = host;
this.username = username;
this.password = password;
}
/**
* Returns all messages on or after the given since date, until today. If the given since date is null, all messages
* are returned
* #param folder the folder to search through
* #param since the given since date
* #param mailConsumer the consumer that will process the messages retrieved
*/
public void processOnMessages(String folder, LocalDate since, Consumer<Message> mailConsumer) {
processOnMessages(folder, since, null, mailConsumer);
}
/**
* Runs a given mailconsumer on all messages in the given imap folder that have been received on, or after, the given
* since date and before the given until date. If since is null, all messages are returned up to the until date.
* If until is null, all messages are returned from the since date until now. If both are null, all messages are
* returned.
* #param folder the folder to search through
* #param since if specified, only messages from this date on are returned
* #param mailconsumer the consumer that will be executed on the messages
*/
public void processOnMessages(String folder, LocalDate since, LocalDate until, Consumer<Message> mailconsumer) {
try {
Properties prop = new Properties();
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.setProperty("mail.imap.starttls.enable", "true");
prop.put("mail.imap.starttls.enable", "true");
prop.put("mail.imap.ssl.socketFactory", sf);
//Connect to the server
Session session = Session.getDefaultInstance(prop, null);
Store store = session.getStore("imap");
store.connect(host, username, password);
//open the inbox folder
Folder inbox = store.getFolder(folder);
inbox.open(Folder.READ_ONLY);
Message[] messages;
if (since != null) {
Date startDate = Date.from(since.atStartOfDay(ZoneId.systemDefault()).toInstant());
SearchTerm newerThan = new ReceivedDateTerm(ComparisonTerm.GE, startDate);
if (until != null) {
Date endDate = Date.from(until.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
SearchTerm olderThan = new ReceivedDateTerm(ComparisonTerm.LT, endDate);
SearchTerm both = new AndTerm(olderThan, newerThan);
messages = inbox.search(both);
} else {
messages = inbox.search(newerThan);
}
} else if (until != null) {
Date endDate = Date.from(until.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
SearchTerm olderThan = new ReceivedDateTerm(ComparisonTerm.LT, endDate);
messages = inbox.search(olderThan);
} else {
messages = inbox.getMessages();
}
for (Message m: messages) {
mailconsumer.accept(m);
}
inbox.close(false);
store.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Will search through all attachments of the message, and will pass those with the given extension (if provided)
* to the consumer. Note that the connection to the imap should be open for all this magic to work. this method
* is intended to be called from a messageconsumer during the processOnMessages method from this class.
* #param message the message for which the attachments are needed.
* #param extension if provided, only attachments with this extension will be provided
* #param attachmentConsumer the consumer that will process the attachments
* #throws IOException if for some reason the attachments can't be accessed
* #throws MessagingException for other messaging errors
*/
public static void processOnAttachments(Message message, String extension, Consumer<InputStream> attachmentConsumer)
throws IOException, MessagingException {
Multipart multipart = (Multipart) message.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (bodyPart.getFileName() != null && bodyPart.getFileName().endsWith(extension)) {
attachmentConsumer.accept(bodyPart.getInputStream());
}
}
}
}
Again, this code worked perfectly two weeks ago, nothing was changed on my side and the credentials still work...
All suggestions are appreciated.
You must use OAuth2, legacy security may have been deprecated.
Works with Thunderbird for example.
Just see how to reactivate legacy auth or use OAuth2 with your java client.
#see https://learn.microsoft.com/fr-fr/exchange/troubleshoot/administration/cannot-connect-mailbox-pop-imap-outlook to reactivate legacy
PS : To use shared mailbox, you must user mailbox name as user, and OAuth2 user + password and MFA if needed during Auth part, all that instead of old way (user#domain\sharedmailbox + password)
I have a piece of Java code (see below), which has not been changed in a while and worked two weeks ago. When I run it now, I suddenly get an "AUTHENTICATE FAILED." I get the error on two different PCs, and I have validated that the credentials used still work when I log into may office365 mailbox using the browser.
Has something changed on the office365 side I should know of?
The error I get is:
javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:732)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at my.application.input.imap.ImapMailBoxReader.processOnMessages(ImapMailBoxReader.java:69)
Digging deeper, the cause seems to be an A3 NO AUTHENTICATE failed. response (line 730 of javax.mail.IMAPStore).
The code I use is the following (using javax.mail version 1.6.2):
package my.application.input.imap;
import my.application.dao.PhysicalTransactionDao;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.search.AndTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.SearchTerm;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.io.*;
import java.util.function.Consumer;
public class ImapMailBoxReader {
private String host;
private String username;
private String password;
public static void main(String[] args) {
ImapMailBoxReader imapReader = new ImapMailBoxReader(
"outlook.office365.com",
"myemail",
"mypassword");
LocalDate startDate = LocalDate.of(2022,4,1);
LocalDate endDate = LocalDate.of(2022,7,1);
imapReader.processOnMessages("Inbox", startDate, endDate, SomeClass::processMessage);
}
public ImapMailBoxReader(String host, String username, String password) {
this.host = host;
this.username = username;
this.password = password;
}
/**
* Returns all messages on or after the given since date, until today. If the given since date is null, all messages
* are returned
* #param folder the folder to search through
* #param since the given since date
* #param mailConsumer the consumer that will process the messages retrieved
*/
public void processOnMessages(String folder, LocalDate since, Consumer<Message> mailConsumer) {
processOnMessages(folder, since, null, mailConsumer);
}
/**
* Runs a given mailconsumer on all messages in the given imap folder that have been received on, or after, the given
* since date and before the given until date. If since is null, all messages are returned up to the until date.
* If until is null, all messages are returned from the since date until now. If both are null, all messages are
* returned.
* #param folder the folder to search through
* #param since if specified, only messages from this date on are returned
* #param mailconsumer the consumer that will be executed on the messages
*/
public void processOnMessages(String folder, LocalDate since, LocalDate until, Consumer<Message> mailconsumer) {
try {
Properties prop = new Properties();
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.setProperty("mail.imap.starttls.enable", "true");
prop.put("mail.imap.starttls.enable", "true");
prop.put("mail.imap.ssl.socketFactory", sf);
//Connect to the server
Session session = Session.getDefaultInstance(prop, null);
Store store = session.getStore("imap");
store.connect(host, username, password);
//open the inbox folder
Folder inbox = store.getFolder(folder);
inbox.open(Folder.READ_ONLY);
Message[] messages;
if (since != null) {
Date startDate = Date.from(since.atStartOfDay(ZoneId.systemDefault()).toInstant());
SearchTerm newerThan = new ReceivedDateTerm(ComparisonTerm.GE, startDate);
if (until != null) {
Date endDate = Date.from(until.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
SearchTerm olderThan = new ReceivedDateTerm(ComparisonTerm.LT, endDate);
SearchTerm both = new AndTerm(olderThan, newerThan);
messages = inbox.search(both);
} else {
messages = inbox.search(newerThan);
}
} else if (until != null) {
Date endDate = Date.from(until.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
SearchTerm olderThan = new ReceivedDateTerm(ComparisonTerm.LT, endDate);
messages = inbox.search(olderThan);
} else {
messages = inbox.getMessages();
}
for (Message m: messages) {
mailconsumer.accept(m);
}
inbox.close(false);
store.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Will search through all attachments of the message, and will pass those with the given extension (if provided)
* to the consumer. Note that the connection to the imap should be open for all this magic to work. this method
* is intended to be called from a messageconsumer during the processOnMessages method from this class.
* #param message the message for which the attachments are needed.
* #param extension if provided, only attachments with this extension will be provided
* #param attachmentConsumer the consumer that will process the attachments
* #throws IOException if for some reason the attachments can't be accessed
* #throws MessagingException for other messaging errors
*/
public static void processOnAttachments(Message message, String extension, Consumer<InputStream> attachmentConsumer)
throws IOException, MessagingException {
Multipart multipart = (Multipart) message.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (bodyPart.getFileName() != null && bodyPart.getFileName().endsWith(extension)) {
attachmentConsumer.accept(bodyPart.getInputStream());
}
}
}
}
Again, this code worked perfectly two weeks ago, nothing was changed on my side and the credentials still work...
All suggestions are appreciated.
You must use OAuth2, legacy security may have been deprecated.
Works with Thunderbird for example.
Just see how to reactivate legacy auth or use OAuth2 with your java client.
#see https://learn.microsoft.com/fr-fr/exchange/troubleshoot/administration/cannot-connect-mailbox-pop-imap-outlook to reactivate legacy
PS : To use shared mailbox, you must user mailbox name as user, and OAuth2 user + password and MFA if needed during Auth part, all that instead of old way (user#domain\sharedmailbox + password)
I have a class that downloads files from FTP servers using the Apache FTP Client, and I want to test it. For doing so, I decided to use the FakeFtpServer class from MockFtpServer, but it always fails with the same error: Connection refused (Connection refused).
My test class:
public class FTPConnectionTest {
/** Mock FTP Server */
private static FakeFtpServer FAKE_FTP_SERVER;
/** Mock FTP Server address */
private static String ADDRESS = "localhost";
/** Mock FTP server user name */
private static String USERNAME = "ftpuser";
/** Mock FTP Server password */
private static String PASSWORD = "ftppasswd";
/** Mock FTP Server default root */
private static String ROOT;
/** Mock FTP Server port */
private static int PORT = 0;
/** Test directory in the mock server */
private static String DIRECTORY = "/directory";
/** Test file 1*/
private static String FILE1 = "/Human_satellite.txt";
/** Content of test file 1 */
private static String FILE1_CONTENT = "Ground control to Major Tom...";
/** Test file 1*/
private static String FILE2 = "/wall-e.txt";
/** Content of test file 1 */
private static String FILE2_CONTENT = "If lost in space, use fire extinguisher";
/** Test file 1*/
private static String FILE3 = "/buzz_lightyear.txt";
/** Content of test file 1 */
private static String FILE3_CONTENT = "To infinity, and beyond !";
/**
* Set up a mock FTP server before running the tests
*/
#BeforeClass
public static void setupMock() {
// Create Mock server
FAKE_FTP_SERVER = new FakeFtpServer();
FAKE_FTP_SERVER.setServerControlPort(0); // Automatically finds available port
PORT = FAKE_FTP_SERVER.getServerControlPort();
FAKE_FTP_SERVER.addUserAccount(new UserAccount(USERNAME, PASSWORD, ROOT));
// Get the path to the resources folder where to run the mock FTP
File mockDir = new File("src/test/resources/ftp/mock");
ROOT = mockDir.getAbsolutePath();
// Create mock files
FileSystem fileSystem = new UnixFakeFileSystem();
fileSystem.add(new DirectoryEntry(ROOT));
fileSystem.add(new FileEntry(ROOT + FILE1, FILE1_CONTENT));
fileSystem.add(new DirectoryEntry(ROOT + DIRECTORY));
fileSystem.add(new FileEntry(ROOT + DIRECTORY + FILE2, FILE2_CONTENT));
fileSystem.add(new FileEntry(ROOT + DIRECTORY + FILE3, FILE3_CONTENT));
FAKE_FTP_SERVER.setFileSystem(fileSystem);
FAKE_FTP_SERVER.start();
}
/**
* The the mock FTP Server once the tests are done
*/
#AfterClass
public static void stop() {
FAKE_FTP_SERVER.stop();
}
/**
* Test
*/
#Test
public void testFetchNewFiles () {
// Get output path
String outputPath = "src/test/resources/ftp/result";
File output = new File(outputPath);
outputPath = output.getAbsolutePath();
// Create the connection and get the files
FTPConnection conn = new FTPConnection(ADDRESS, PORT, USERNAME, PASSWORD, outputPath);
conn.fetchNewFiles();
// Check that the files have bin downloaded
File file1 = new File(outputPath + FILE1);
assertTrue(file1.exists());
}
}
And here is the part of the FTP class that fails:
public class FTPConnection {
/** Logger */
private Logger logger;
/** The FTP Client used to connect to the server */
private FTPClient client;
/** The address of the server */
private String server;
/** The port of the server (default 21) */
private int port;
/** The user name to use to connect to the server */
private String user;
/** The password to use to connect to the server */
private String password;
/** The directory where to save the downloaded files */
private String output;
/**
* Constructor
* #param server the address of the FTP server
* #param port the port of the FTP server
* #param user the user name to use to connect to the server
* #param password the password to use to connect to the server
* #param output the output directory where to download the files
*/
public FTPConnection (String server, int port, String user, String password, String output) {
this.logger = LoggerFactory.getLogger(FTPConnection.class);
this.server = server;
this.port = port;
this.user = user;
this.password = password;
this.output = output;
this.client = new FTPClient();
}
/**
* Constructor
* #param server the address of the FTP server
* #param user the user name to use to connect to the server
* #param password the password to use to connect to the server
* #param output the output directory where to download the files
*/
public FTPConnection (String server, String user, String password, String output) {
this(server, 21, user, password, output);
}
public void fetchNewFiles() {
// Connect to the server
try {
this.client.connect(server, port); // That's the line that fails
this.client.login(user, password);
} catch (IOException e) {
logger.error("Error while connecting to FTP server '" + this.server + "': " + e.getMessage());
e.printStackTrace();
return;
}
}
}
And finally an extract of what's going on in the console:
19:24:31.417 [Thread-1] INFO org.mockftpserver.fake.FakeFtpServer - Starting the server on port 0
19:24:31.419 [Thread-1] INFO org.mockftpserver.fake.FakeFtpServer - Actual server port is 34003
19:24:31.444 [main] ERROR com.my.project.importHandler.FTPConnection - Error while connecting to FTP server 'localhost': Connection refused (Connection refused)
*** STACK TRACE ***
19:24:31.457 [Thread-1] DEBUG org.mockftpserver.fake.FakeFtpServer - Cleaning up server...
19:24:31.457 [Thread-1] INFO org.mockftpserver.fake.FakeFtpServer - Server stopped.
Ok, I found it: FAKE_FTP_SERVER.setServerControlPort(0); sets the value of the server port to 0, and the automatic selection of an available port only happens during FAKE_FTP_SERVER.start();. I moved the line PORT = FAKE_FTP_SERVER.getServerControlPort(); after FAKE_FTP_SERVER.start(); and now it works.
I'm trying to send a text message over Apache Camel using the camel-twilio component. Since I never used the Twilio API (neither natively nor using Apache Camel), I'm not sure if I got the parameters right. Here's the method I wrote:
/**
* Sends a text message to the given recipient's number (parameter to)
*
* #param username:
* Twilio username (email)
* #param password:
* Twilio password (in plain text)
* #param accountSid:
* Twilio account sid (from the dashboard)
* #param from:
* registered phone number (starting with country prefix +XX)
* #param to:
* the recipient's phone number (starting with country prefix +XX)
* #param message:
* the message to be sent (plain text)
* #throws Exception
*/
public static void sendTextMessage(String username, String password, String accountSid, String from, String to,
String message) throws Exception {
String route = String.format("twilio:message/creator?username=%s&password=%s&accountSid=%s&from=%s&to=%s",
username, password, accountSid, from, to);
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:message").to(route);
}
});
context.start();
ProducerTemplate producer = context.createProducerTemplate();
producer.sendBody("direct:message", message);
context.stop();
}
The most important line is the creation of the route, the first of the method. When I'm running this method with parameters according to the JavaDoc, I get this error:
Caused by: org.apache.camel.RuntimeCamelException: Missing properties for creator, need one or more from [pathAccountSid, mediaUrl, messagingServiceSid, body]
So I thought to add the parameter messagingServiceSid, providing my accountSid again:
String route = String.format("twilio:message/creator?username=%s&password=%s&accountSid=%s&from=%s&to=%s&messagingServiceSid=%s",
username, password, accountSid, from, to, accountSid);
Now I get this error message:
Caused by: java.lang.IllegalArgumentException: No matching method for message/creator, with arguments [messagingServiceSid, from, to]
What am I doing wrong?
EDIT: These are my Maven dependencies:
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.20.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-twilio</artifactId>
<version>2.20.1</version>
</dependency>
</dependencies>
EDIT 2: Here's the modified and working version of the method:
/**
* Sends a text message to the given recipient's number (parameter to)
*
* #param accountSid:
* Twilio account sid (from the dashboard)
* #param authToken:
* Twilio auth token (from the dashboard)
* #param from:
* registered phone number (starting with country prefix +XX)
* #param to:
* the recipient's phone number (starting with country prefix +XX)
* #param message:
* the message to be sent (plain text)
* #throws Exception
*/
public static void sendTextMessage(String accountSid, String authToken, String from, String to, String message)
throws Exception {
CamelContext context = new DefaultCamelContext();
TwilioComponent twilio = context.getComponent("twilio", TwilioComponent.class);
twilio.getConfiguration().setUsername(accountSid);
twilio.getConfiguration().setPassword(authToken);
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:message")
.setHeader("CamelTwilioTo", constant(new PhoneNumber(to)))
.setHeader("CamelTwilioFrom", constant(new PhoneNumber(from)))
.setHeader("CamelTwilioBody", constant(message))
.to("twilio://message/creator");
}
});
context.start();
ProducerTemplate producer = context.createProducerTemplate();
producer.sendBody("direct:message", message);
context.stop();
}
I have to say that to work efficiently with camel-twilio, you need to have a good understanding on Twilio Java API. In your case, let's get familiar with the MessageCreator API here:
https://www.twilio.com/docs/libraries/reference/twilio-java/7.17.0/com/twilio/rest/api/v2010/account/MessageCreator.html
With that said, first of all, since the username (i.e. accountSid) and password should be something shared in a camel-twilio component, let's set them at the component:
TwilioComponent twilio = context.getComponent("twilio", TwilioComponent.class);
twilio.getConfiguration().setUsername(username);
twilio.getConfiguration().setPassword(password);
(Note most of the time the twilio username and accoundSid refer to the same thing, so you can use only one of them.)
Once the username/password are set up, let's use the MessageCreator. The simplest constructor you can use would be MessageCreator(PhoneNumber to, PhoneNumber from, String body), but since to and from have to be PhoneNumber instances, it's easier to pass them to the endpoint as Camel message headers instead of embedding them to the endpoint URI as endpoint parameters. (NOTE: Any of the camel-twilio endpoint options can be provided in a message header with CamelTwilio prefix.)
This would look something like the following:
public void configure() throws Exception {
from("direct:message")
.setHeader("CamelTwilioTo", constant(new PhoneNumber(to)))
.setHeader("CamelTwilioFrom", constant(new PhoneNumber(from)))
.setHeader("CamelTwilioBody", constant(message))
.to("twilio://message/creator");
}
Note, at this moment, the endpoint URI can be as simple as twilio://message/creator.
Now you should be able to send texts to Twilio.
FYI, there is a working example of camel-twilio with Spring Boot:
https://github.com/tadayosi/demo-camel-hawtio-springboot
I'm using the lightweight server provided in oracle java since java 1.6 and I'm using just to receive POST responses from another server.
Now for 2 or 3 responses it run well but when the load is increased I'm not receiving all the responses from the server, some of them are ignored.
I tried to increase the backlog to 1500 but it's the same thing.
here's how I create the server :
public class HttpServerZipWhip {
private final String SERVER_IP_ADDRESS = "X.X.X.X";
private final Integer SERVER_PORT = 9333;
private final short SERVER_BACKLOG = 1500;
private final String SERVER_CONTEXT = "/message/receive";
/**
* Constructor : Server initiation
* #param muc
* #param smshandle
*/
public HttpServerClass(Muc muc, SMSHandling_impl smshandle){
//Server Initialization
InetSocketAddress addr = new InetSocketAddress(SERVER_IP_ADDRESS, SERVER_PORT);
HttpServer server = null;
try {
server = HttpServer.create(addr, SERVER_BACKLOG);
} catch (IOException e) {
e.printStackTrace();
}
server.createContext(SERVER_CONTEXT, new MyHandler(muc, smshandle));
server.setExecutor(Executors.newCachedThreadPool());
server.start();
}
}