OAuth를 사용하여 메일 서비스에 액세스하기
Contents
[
Hide
]
Aspose.Email에 OAuth 2.0 지원이 추가되어 SMTP, POP3, IMAP, EWS 서버에 액세스할 수 있습니다. 일반적으로 OAuth 2.0 베어러 토큰을 지원하는 모든 서버를 Aspose.Email과 함께 사용할 수 있지만, 당사의 이메일 클라이언트는 Google 메일 서버와 Microsoft Office 365 서버에서 테스트되었습니다. 서버에 대한 액세스는 SmtpClient, Pop3Client, ImapClient 및 EWSClient OAuth를 사용한 구현은 두 가지 방법이 있습니다.
- 액세스 토큰을 이메일 클라이언트의 생성자에 직접 제공합니다. 이 경우 사용자는 액세스 토큰의 수명이 제한되어 있음을 이해해야 합니다. 토큰이 만료되면 이메일 클라이언트를 사용해 서버에 접근할 수 없습니다.
- 다음 기반의 토큰 공급자 맞춤 구현을 제공합니다 ITokenProvider 이메일 클라이언트의 생성자에 인터페이스를 전달합니다. 이 경우 클라이언트는 토큰 만료 시간을 확인하고 요청합니다 ITokenProvider 이전 토큰이 만료된 경우 새 액세스 토큰을 발급받습니다. 이렇게 하면 클라이언트가 토큰을 주기적으로 갱신하며 서버와 무제한으로 작업할 수 있습니다. 많은 서비스가 액세스 토큰을 갱신하는 간단한 방식을 지원합니다. 예를 들어, Google 서비스의 리프레시 토큰을 사용하거나 Microsoft ID 플랫폼의 ROPC 인증 흐름을 사용하여 토큰 공급자를 구현할 수 있습니다.
적절한 서버에 계정 구성
다음 문서는 메일 서비스에 액세스하는 계정을 구성하는 데 도움이 됩니다.
- 대상 Office 365
- 대상 Gmail
액세스 토큰을 사용한 메일 서비스 액세스
다음 코드 예제에서는 액세스 토큰을 사용하여 메일 서비스에 연결하는 방법을 보여줍니다.
// Connecting to SMTP server
try (SmtpClient client = new SmtpClient(
"smtp.gmail.com",
587,
"user1@gmail.com",
"accessToken",
true,
SecurityOptions.SSLExplicit)) {
}
// Connecting to IMAP server
try (ImapClient client = new ImapClient(
"imap.gmail.com",
993,
"user1@gmail.com",
"accessToken",
true,
SecurityOptions.SSLImplicit)) {
}
// Connecting to POP3 server
try (Pop3Client client = new Pop3Client(
"pop.gmail.com",
995,
"user1@gmail.com",
"accessToken",
true,
SecurityOptions.Auto)) {
}
토큰 공급자를 사용한 메일 서비스 액세스
다음 코드 예제에서는 토큰 공급자를 사용하여 메일 서비스에 연결하는 방법을 보여줍니다.
ITokenProvider tokenProvider = TokenProvider.Google.getInstance(
"ClientId",
"ClientSecret",
"RefreshToken");
// Connecting to SMTP server
try (SmtpClient client = new SmtpClient(
"smtp.gmail.com",
587,
"user1@gmail.com",
tokenProvider,
SecurityOptions.SSLExplicit)) {
}
// Connecting to IMAP server
try (ImapClient client = new ImapClient(
"imap.gmail.com",
993,
"user1@gmail.com",
tokenProvider,
SecurityOptions.SSLImplicit)) {
}
// Connecting to POP3 server
try (Pop3Client client = new Pop3Client(
"pop.gmail.com",
995,
"user1@gmail.com",
tokenProvider,
SecurityOptions.Auto)) {
}
Office 365용 맞춤 ITokenProvider 구현
아래 토큰 공급자 구현을 사용하여 Office 365 메일 서비스에 액세스할 수 있습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* Azure resource owner password credential (ROPC) token provider
* https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
* https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
* https://portal.azure.com
* https://developer.microsoft.com/en-us/graph/graph-explorer/#
* token parser https://jwt.io
* </p>
*/
class AzureROPCTokenProvider implements ITokenProvider {
private static final String GRANT_TYPE = "password";
private final String clientId;
private final String clientSecret;
private final String userName;
private final String password;
private final String tenant;
private final String scope;
private OAuthToken token;
public AzureROPCTokenProvider(String tenant, String clientId, String clientSecret,
String userName, String password, String[] scopeAr) {
this.tenant = tenant;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.userName = userName;
this.password = password;
this.scope = joinToStr(scopeAr, " ");
}
public synchronized OAuthToken getAccessToken(boolean ignoreExistingToken) {
if (this.token != null && !this.token.getExpired() && !ignoreExistingToken)
return this.token;
token = null;
Map<String, String> tokenArgs = geToken();
java.util.Calendar c = java.util.Calendar.getInstance();
c.add(java.util.Calendar.SECOND, Integer.parseInt(tokenArgs.get("expires_in")));
token = new OAuthToken(tokenArgs.get("access_token"), TokenType.AccessToken, c.getTime());
return token;
}
public final OAuthToken getAccessToken() {
return getAccessToken(false);
}
public void dispose() {
}
private String getEncodedParameters() {
return "client_id=" + urlEncode(clientId) + "&scope=" + urlEncode(scope) + "&username=" + urlEncode(userName)
+ "&password=" + urlEncode(password) + "&grant_type="
+ urlEncode(GRANT_TYPE);
}
private String getUri() {
if (tenant == null || tenant.trim().isEmpty())
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
else
return "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token";
}
private Map<String, String> geToken() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(getUri()).openConnection();
connection.setRequestMethod("POST");
byte[] requestData = getEncodedParameters().getBytes(StandardCharsets.UTF_8);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" + requestData.length);
final OutputStream st = connection.getOutputStream();
try {
st.write(requestData, 0, requestData.length);
} finally {
st.flush();
st.close();
}
connection.connect();
if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) {
throw new IllegalAccessError("Operation failed: " + connection.getResponseCode() + "/" +
connection.getResponseMessage() + "\r\nDetails:\r\n{2}"
+ readInputStream(connection.getErrorStream()));
}
String responseText = readInputStream(connection.getInputStream());
Map<String, String> result = new HashMap<>();
String[] fromJsonToKeyValue = responseText.replace("{", "").replace("}", "")
.replace("\"", "").replace("\r", "")
.replace("\n", "").split(",");
for (String keyValue : fromJsonToKeyValue) {
String[] pair = keyValue.split(":");
String name = pair[0].trim().toLowerCase();
String value = urlDecode(pair[1].trim());
result.put(name, value);
}
return result;
} catch (IOException e) {
throw new IllegalAccessError(e.getMessage());
}
}
static String urlEncode(String value) {
try {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new IllegalAccessError(e.getMessage());
}
}
static String urlDecode(String value) {
try {
return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new IllegalAccessError(e.getMessage());
}
}
static String readInputStream(InputStream is) {
if (is == null)
return "";
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder result = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
result.append(line);
}
} catch (IOException e) {
// ignore
}
return result.toString();
}
static String joinToStr(String[] arr, String sep) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if (i > 0)
sb.append(sep);
sb.append(arr[i]);
}
return sb.toString();
}
}
다음 코드 예제에서는 사용자 지정 토큰 공급자를 사용하여 Office 365 서비스에 연결하는 방법을 보여줍니다.
ITokenProvider tokenProvider = new AzureROPCTokenProvider(
"Tenant",
"ClientId",
"ClientSecret",
"EMail",
"Password",
scopes);
// Connecting to SMTP server
try (SmtpClient client = new SmtpClient(
"smtp.office365.com",
587,
"Test1@test.onmicrosoft.com",
tokenProvider,
SecurityOptions.SSLExplicit)) {
}
// Connecting to IMAP server
try (ImapClient client = new ImapClient(
"outlook.office365.com",
993,
"Test1@test.onmicrosoft.com",
tokenProvider,
SecurityOptions.SSLImplicit)) {
}
// Connecting to POP3 server
try (Pop3Client client = new Pop3Client(
"outlook.office365.com",
995,
"Test1@test.onmicrosoft.com",
tokenProvider,
SecurityOptions.Auto)) {
}
// Connecting to EWS server
final String mailboxUri = "https://outlook.office365.com/ews/exchange.asmx";
ICredentials credentials = new OAuthNetworkCredential(tokenProvider);
try (IEWSClient ewsClient = EWSClient.getEWSClient(mailboxUri, credentials)) {
}
IMAP, POP3 또는 SMTP를 통해 Office 365에 액세스하기 위한 권한
Office 365 메일 서비스에 액세스하려면 올바른 API 권한을 적용하고 관리자 동의를 부여해야 합니다:

API 권한 / 권한 추가 마법사에서 Microsoft Graph를 선택한 다음 위임된 권한을 선택하면 다음 권한 범위가 나열됩니다:
offline_access
IMAP.AccessAsUser.All
POP.AccessAsUser.All
SMTP.Send
토큰 공급자 예제:
ITokenProvider tokenProvider = new AzureROPCTokenProvider(OAuth.Tenant, OAuth.ClientId, OAuth.ClientSecret, User.EMail, User.Password,
new String[] {
"offline_access",
"https://outlook.office.com/IMAP.AccessAsUser.All", // IMAP scope
"https://outlook.office.com/POP.AccessAsUser.All", // POP3 scope
"https://outlook.office.com/SMTP.Send" // SMTP scope
});