I was able to receive an email from the article Last time, but in the end I didn't see the light of day in my work. About a year later, there was talk of developing an app to receive new emails, and when I was assured that it would be an easy win, the world would be like this. .. ..
If you need to remodel in less than a year, it is humanity that you want to deal with from the beginning. I heard that it is necessary to play with the Exchange Online side if I check in advance, so I can not use the current operating environment, I applied for free Exchange Online for one month, and it is an advanced authentication based on OAuth 2.0 I tried to receive.
By the way, the application for development is a resident application that periodically outputs the mail received by the mail account dedicated to the application to a text file, and as an authentication method, [ROPC flow recommended not to use](https:: //docs.microsoft.com/ja-jp/azure/active-directory/develop/v2-oauth-ropc) is assumed, so the following is an implementation example.
I referred to the Tutorial for the general processing flow and this procedure.
Log in to the Azure Active Directory admin center with the account that the app uses to receive emails, and click [Azure Active Directory]-[App Registration]-[New Registration].
Enter the name of the app. This time, the app is used only for a specific account, so select [Accounts included only in this organization directory]. I don't use the redirect URI, so don't touch it. Then click [Register].
Set [Allow public client flow] to [Yes] and click [Save].
In [Add Permission] of [API Permission], add [IMAP.AccessAsUser.All] from [Delegated Permission] of [Microsoft Graph]. This time, the logged-in account is also the administrator, so just click [Give administrator consent to ~].
I used Spring Boot 2.3.4 and Kotlin for simplification. In the dependency of spring initializer, add only Java Mail Sender (that is, spring-boot-starter-mail) and add Microsoft Authentication Library for Java to pom.xml after creating the project.
pom.xml
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.7.1</version>
</dependency>
Implement CommandLineRunner and write the process in the run method.
@SpringBootApplication
class SampleMailApplication : CommandLineRunner {
override fun run(vararg args: String?) {
//Implementation
}
}
This procedure of the tutorial referenced above is not cool. What's the rest of the C # article, "Open App.xaml"? .. .. I had no choice but to look it up on the net and it started working with the following code.
import com.microsoft.aad.msal4j.PublicClientApplication
import com.microsoft.aad.msal4j.UserNamePasswordParameters
//Omitted
override fun run(vararg args: String?) {
//Specify the application ID on the overview page of the registered application
val applicationId = "..."
// ...Specify the directory ID on the overview page in the part
val authEndpoint = "https://login.microsoftonline.com/.../oauth2/v2.0/authorize"
//Specify according to the protocol to be used
val scope = setOf("https://outlook.office365.com/IMAP.AccessAsUser.All",
"https://outlook.office365.com/SMTP.Send")
//Specify the email address of your account
val username = "..."
//Specify the password for the account
val password = "..."
val pca = PublicClientApplication.builder(applicationId)
.authority(authEndpoint)
.build()
val parameters = UserNamePasswordParameters
.builder(scope, username, password.toCharArray())
.build()
val result = pca.acquireToken(parameters).join()
println("Access token: ${result.accessToken()}")
var props = Properties()
//OAuth 2 for authentication.Use 0
props["mail.imaps.auth.mechanisms"] = "XOAUTH2"
var session: Session = Session.getInstance(props)
val store: Store = session.getStore("imaps")
//Use access token for password
store.connect("outlook.office365.com", 993, username, result.accessToken())
val folderInbox: Folder = store.getFolder("INBOX")
folderInbox.open(Folder.READ_ONLY)
folderInbox.messages.forEach { println("subject: ${it.subject}") }
The first point is mail.imaps.auth.mechanisms [Description](https://github.com/eclipse-ee4j/mail/blob/c3096cbeaf566f36998e96ff384378059f291ce8/mail/src/main/java/com/sun/mail/imap According to /package.html#L405-L410), the default value is all supported authentication except XOAUTH2, and Exchange Online uses basic authentication. Therefore, specify XOAUTH2 to enable OAuth 2.0 authentication.
Then, just specify the access token instead of the password, and you can receive emails with OAuth 2.0 authentication.
For the time being, I would like to try OAuth 2.0 authentication for SMTP basic authentication, which will be abolished soon. However, instead of OAuth 2.0 authentication, even basic authentication
javax.mail.AuthenticationFailedException: 535 5.7.3 Authentication unsuccessful
Isn't it![Authenticated SMTP on mailbox is on](https://docs.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission#use-the -microsoft-365-admin-center-to-enable-or-disable-smtp-auth-on-specific-mailboxes). .. ..
The page says, "If the authentication policy disables Basic SMTP Authentication, the client will not be able to use the SMTP Authentication Protocol even if you enable the settings described in this article." If you set [Enable Defaults] to [No]](https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/concept-fundamentals-security-defaults), the mail will be sent successfully. However, when I set [Enable Security Defaults] back to [Yes], the error no longer occurs. (It is undeniable that something else has been tampered with ...)
I don't know what it is ...
For the time being, the successful transmission logic is also described.
val props = Properties()
props["mail.smtp.auth"] = "true"
props["mail.smtp.auth.mechanisms"] = "XOAUTH2";
props["mail.smtp.starttls.enable"] = "true"
val session = Session.getInstance(props)
val transport = session.getTransport("smtp")
transport.connect("smtp.office365.com", 587, username, result.accessToken())
val sendMessage = MimeMessage(session)
sendMessage.addRecipients(Message.RecipientType.TO, username)
sendMessage.setFrom(username)
sendMessage.subject = "Send"
sendMessage.setText("Transmission test")
transport.sendMessage(sendMessage, sendMessage.allRecipients)
In addition, although the transmission itself has been completed, the final delivery has not been completed with "550 5.7.501 Service unavailable. Spam abuse detected from IP range." From the destination. This is because emails from the onmicrosoft.com domain are filtered as spam, and a trial send from Outlook will give the same result, so I don't think it's a logical issue.