1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

わかってみれば大したことないExchange OnlineからJavaMailでメール受信にハマったこと

Last updated at Posted at 2019-08-02

はじめに

Java(Kotlin)アプリでExchange Onlineとメール送受信することになり、簡単に調べがついたメール送信をしてみた。

build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
  id("org.springframework.boot") version "2.1.6.RELEASE"
  kotlin("jvm") version "1.3.41"
  kotlin("plugin.spring") version "1.3.41"
}
repositories {
  mavenCentral()
}
dependencies {
  implementation(platform("org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE"))
  implementation("org.springframework.boot:spring-boot-starter-mail")
  implementation(kotlin("stdlib-jdk8"))
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
  jvmTarget = "1.8"
}
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
  jvmTarget = "1.8"
}
application.yml
spring:
  mail:
    host: smtp.office365.com
    port: 587
    username: め〜るあどれす
    password: ぱすわ〜ど
    properties:
      mail:
        smtp:
          starttls:
            enable: true
Application.kt
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.mail.SimpleMailMessage
import org.springframework.mail.javamail.JavaMailSender

@SpringBootApplication
class Application(val mailSender: JavaMailSender): CommandLineRunner {
  override fun run(vararg args: String?) {
    val mailMessage = SimpleMailMessage().apply {
      setTo("宛先め〜るあどれす")
      from = "め〜るあどれす"
      subject = "けんめい"
      text = "ほんぶん"
    }
    mailSender.send(mailMessage)
  }
}

fun main( args: Array<String>) {
  runApplication<Application>(*args)
}
  • 今までMaven専門できたけど、GroovyじゃなくてKotlinで書けるようになったというのでGradleに挑戦中。だから記述内容が最適化は自信なし。これからもGradleを積極的に使うつもりだけど、時々Mavenより判りやすいという話を聞くけど、自由度が高いから当然判りづらいという感想。
  • プロパティでmail.smtp.ssl.enable=trueだと、javax.net.ssl.SSLException: Unsupported or unrecognized SSL messageが発生するので、こちらを参考にした。mail.smtp.authはなくても、デバッグログ的に動きに差はなかった。

このように簡単にメール送信ができたので、Exchange Onlineとはいえ普通?のメールサーバと同じで受信も簡単にできるだろうと思ってしまった。最終的にはその通りなのだが、途中で躓くと疑心暗鬼にかられて右往左往してしまった。

ちょっと雲行きが...

メール送信できたから受信も当然できると言いふらしてしまい、いざ実装という段階になって、あれ!?と思ったのが、JavaMailSenderがあるspring-context-support-5.1.8.RELEASE.jarにJavaMailReciverはない。JavaMail自身は受信もできるのに何故?。spring integrationにはメール受信もあるけど、わざわざ組み込む気にはなれずJavaMailを直接使うことにした。
しかし、いろいろな実装をラッピングして使いやすくしてくれるSpring Frameworkにメール受信がないってことは、何か共通化しにくい事情があるのでは?と思ってしまった。

そしてハマった

JavaMailでの受信ロジックだけど、それほど警戒することはないものだった。

val props = Properties()
// セッションを生成
val session = Session.getInstance(props)
// プロトコルを選択
val store = session.getStore("imaps")
// サーバに接続
store.connect("outlook.office365.com", 993, "め〜るあどれす", "ぱすわ〜ど")
// フォルダを選択
val folder = store.getFolder("INBOX")
folder.open(Folder.READ_ONLY)
// メール受信
folder.messages.map {
  println(it.subject)
}
folder.close(false)
store.close()

するとstore.connectメソッドの呼び出しでjavax.mail.AuthenticationFailedException: AUTHENTICATE failedが発生。session.debug = trueを指定して詳細なログを取得すると

DEBUG: setDebug: JavaMail version 1.6.2
DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle]
DEBUG IMAPS: mail.imap.fetchsize: 16384
DEBUG IMAPS: mail.imap.ignorebodystructuresize: false
DEBUG IMAPS: mail.imap.statuscachetimeout: 1000
DEBUG IMAPS: mail.imap.appendbuffersize: -1
DEBUG IMAPS: mail.imap.minidletime: 10
DEBUG IMAPS: closeFoldersOnStoreFailure
DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. 
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAPS: AUTH: PLAIN
DEBUG IMAPS: AUTH: XOAUTH2
DEBUG IMAPS: protocolConnect login, host=outlook.office365.com, user=め〜るあどれす, password=<non-null>
DEBUG IMAPS: AUTHENTICATE PLAIN command trace suppressed
DEBUG IMAPS: AUTHENTICATE PLAIN command result: A1 NO AUTHENTICATE failed.

なんか認証に失敗している?ここが迷走の始まり。
プロトコルをpop3sに、ポート番号を995で試したけど

DEBUG: setDebug: JavaMail version 1.6.2
DEBUG: getProvider() returning javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle]
DEBUG POP3: mail.pop3s.rsetbeforequit: false
DEBUG POP3: mail.pop3s.disabletop: false
DEBUG POP3: mail.pop3s.forgettopheaders: false
DEBUG POP3: mail.pop3s.cachewriteto: false
DEBUG POP3: mail.pop3s.filecache.enable: false
DEBUG POP3: mail.pop3s.keepmessagecontent: false
DEBUG POP3: mail.pop3s.starttls.enable: false
DEBUG POP3: mail.pop3s.starttls.required: false
DEBUG POP3: mail.pop3s.finalizecleanclose: false
DEBUG POP3: mail.pop3s.apop.enable: false
DEBUG POP3: mail.pop3s.disablecapa: false
DEBUG POP3: connecting to host "outlook.office365.com", port 995, isSSL true
+OK The Microsoft Exchange POP3 service is ready. 
CAPA
+OK
TOP
UIDL
SASL PLAIN
USER
.
DEBUG POP3: authentication command trace suppressed
DEBUG POP3: authentication command failed
QUIT
+OK Microsoft Exchange Server POP3 server signing off.

やはり認証で失敗している。
そこでネットで情報を漁ると、メールアドレスではなくて@より前で認証しないとダメとか、それだとドメインが判らないだろうからoutlook.office365.comの先でプロキシ?かリダイレクト?されているExchangeサーバに直接接続しないとダメじゃないかとか、などなど半日程度試行錯誤を繰り返しました。

こたえ

Exchange管理コンソールでユーザのメール接続設定でIMAPやPOP3が無効になってました。
上記の直接Exchangeサーバに接続しなきゃって時に、管理者の人にお願いして管理コンソールにアクセスさせてもらいました。直接は結局TCP/IPが通らずダメでしたが、この時にみたドキュメントに「既定では、POP3 と IMAP4 は Exchange Online のすべてのユーザーに対して有効になっています。」だがユーザ毎に無効化できるってことで確認してみたら、まんまと無効化されてました。
そこで有効化して、しばらくすると(5~10分)、すんなり動きました!

image.png

1
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?