こんにちは。サイオステクノロジーの木村です。
こちらの公開情報によると、Exchange Online での基本認証の廃止に伴い、Exchange Onlineで SMTP AUTH プロトコルを使用したメール送信について、基本認証での接続は非推奨になりました。
Exchange Online で基本認証が無効になった場合でも、SMTP AUTH は引き続き基本認証が使用できるようですが、先進認証での方法に切り替えることが推奨されています。
そこで今回は、Javaでの実装を例に、SMTP AUTH にてメール送信する際に先進認証(OAuth 認証)で行う方法をご紹介します。
アプリケーションの登録
OAuth を使用するには、アプリケーションを Azure AD に登録する必要があります。以下にその手順を記載します。
1. 管理者でAzureポータル(https://portal.azure.com/)にログインします。
2. メニューより「Azure Active Directory」をクリックします。
3. 「アプリの登録」をクリックし「+新規登録」をクリックします。
4. アプリケーションの登録ページで、以下を入力し「登録」をクリックします。
- 名前:任意の名称
- サポートされているアカウントの種類:この組織ディレクトリのみに含まれるアカウント
- リダイレクトURI(省略可能):何も入力しない
5. 表示された [アプリケーション (クライアント) ID] と、[ディレクトリ (テナント) ID ]の値をメモしておきます。
6. 「証明書とシークレット」をクリックし、「+新しいクライアントシークレット」をクリックします。
7. 説明を入力して有効期限を選択し「追加」をクリックします。
8. 作成されたクライアントシークレット の値をメモしておきます。
9. 「APIのアクセス許可」をクリックし、「+アクセス許可の追加」をクリックします。
10. 「所属する組織で使用しているAPI」タブを選択し、検索欄に「Office 365 Exchange Online」と入力して検索されたものをクリックします。
11. 「アプリケーションの許可」をクリックします。
12. 「SMTP.Send.App」にチェックを入れ、「アクセス許可の追加」をクリックします。
13. 「[テナント名]に管理者の同意を与えます」をクリックします。
14. 「はい」をクリックします。
以上でアプリケーションの登録は完了です。
Exchange に サービスプリンシパル を登録
アプリケーションの登録の手順で登録したアプリケーションで Exchange Online に接続できるようにするために、アプリケーションのサービスプリンシパル をExchange に登録します。以下にその手順を記載します。
オブジェクトID を確認
アプリケーションのサービスプリンシパル をExchange に登録する際に、「オブジェクトID」を指定する必要があるため、以下の手順で「オブジェクトID」を確認します。([アプリの登録] の [概要] のオブジェクトID とは異なる値です。)
1. メニューより「Azure Active Directory」をクリックします。
2. 「エンタープライズ アプリケーション」をクリックします。
3. すべてのアプリケーションの一覧にて、アプリケーションの登録の手順で作成したアプリケーションを検索し、クリックします。
4. プロパティに表示される「オブジェクトID」をコピーしてメモしておきます。
サービスプリンシパル の登録とアクセス権の付与
アプリケーションのサービスプリンシパル を Exchange へ登録し、メールボックスへのアクセス権を付与します。これらの操作は、PowerShellで行います。
1. PowerShellを管理者で起動し、以下のコマンドを実行して、ExchangeOnlineManagement をインストールし、モジュールを読み込みます。
Install-Module -Name ExchangeOnlineManagement
Import-module ExchangeOnlineManagement
2. 以下のコマンドを実行して Exchange Online に接続します。
Connect-ExchangeOnline -Organization
3. 以下のコマンドを実行して、アプリケーションのサービスプリンシパルを Exchange に登録します。
New-ServicePrincipal -AppId [APPLICATION_ID] -ServiceId [OBJECT_ID]
- APPLICATION_ID:「アプリケーションの登録」の 5. の手順でメモした アプリケーション (クライアント) ID
- OBJECT_ID:「オブジェクトID を確認」の 4. の手順でメモした オブジェクトID
4. 以下のコマンドを実行して、アプリケーションのサービスプリンシパルに、メール送信時に送信元に指定するアカウントのメールボックスへのアクセス権を付与します。
Add-MailboxPermission -Identity "xxx@xxx.onmicrosoft.com(送信元に指定するアカウントのメールアドレス)" -User [APPLICATION_ID] -AccessRights FullAccess
※ 送信元に指定するアカウントのメールボックスの SMTP AUTH が無効の場合は、以下のコマンドで有効に設定しておきます。
Set-CASMailbox -Identity "xxx@xxx.onmicrosoft.com(送信元に指定するアカウントのメールアドレス)" -SmtpClientAuthenticationDisabled $false
メール送信
メール送信時のユーザー認証の実装には、Java 用 Microsoft 認証ライブラリ「Microsoft Authentication Library (MSAL) for Java」を使用します。(Microsoft Authentication Library (MSAL)については、こちらを参照。)
メール送信にはJavaMailを使用します。
Mavenの場合、pom.xmlへ以下のように依存関係を追加します。
pom.xml
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.13.10</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.1</version>
</dependency>
以下のようにコードを実装します。
App.java
import java.util.Collections;
import java.util.Properties;
import java.util.Set;
import com.microsoft.aad.msal4j.ClientCredentialFactory;
import com.microsoft.aad.msal4j.ClientCredentialParameters;
import com.microsoft.aad.msal4j.ConfidentialClientApplication;
import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.IClientCredential;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.Message;
public class App
{
public static void main( String[] args )
{
String CLIENT_ID = "<クライアントID>";
String AUTHORITY = "https://login.microsoftonline.com/<テナントID>/";
String CLIENT_SECRET = "<クライアントシークレット>";
Set SCOPE = Collections.singleton("https://outlook.office365.com/.default");
String FROM_ADDRESS = "<送信元メールアドレス>";
try {
//アクセストークン取得
IClientCredential credential = ClientCredentialFactory.createFromSecret(CLIENT_SECRET);
ConfidentialClientApplication cca = ConfidentialClientApplication
.builder(CLIENT_ID, credential)
.authority(AUTHORITY)
.build();
ClientCredentialParameters parameters =
ClientCredentialParameters
.builder(SCOPE)
.build();
IAuthenticationResult result = cca.acquireToken(parameters).join();
//メール送信
Properties properties = new Properties();
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.auth.mechanisms", "XOAUTH2");
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.ssl.protocols", "TLSv1.3");
Session session = Session.getInstance(properties);
Transport transport = session.getTransport("smtp");
transport.connect("smtp.office365.com", 587, FROM_ADDRESS, result.accessToken());
MimeMessage message = new MimeMessage(session);
message.addRecipients(Message.RecipientType.TO, "<送信先メールアドレス>");
message.setFrom(new InternetAddress(FROM_ADDRESS));
message.setSubject("テストメール", "ISO-2022-JP");
message.setText("テスト", "ISO-2022-JP");
transport.sendMessage(message, message.getAllRecipients());
}catch (Exception ex) {
ex.printStackTrace();
}
}
}
- クライアントID:「アプリケーションの登録」の 5. の手順でメモした アプリケーション (クライアント) ID
- テナントID:「アプリケーションの登録」の 5. の手順でメモした テナントID
- クライアントシークレット:「アプリケーションの登録」の 8. の手順でメモした クライアントシークレット
App.java を実行すると、送信先メールアドレスにメールが送信されます。
※ 当記事の検証で使用したJavaのバージョン:17