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