Reputation: 773
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.
Upvotes: 4
Views: 9968
Reputation: 11
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)
Upvotes: 1