488 lines
No EOL
18 KiB
Java
488 lines
No EOL
18 KiB
Java
package com.alexanderlogistics;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.PrintWriter;
|
|
import java.io.StringWriter;
|
|
import java.util.Map;
|
|
import java.util.Properties;
|
|
|
|
import org.apache.http.client.ClientProtocolException;
|
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
import org.apache.http.client.methods.HttpPost;
|
|
import org.apache.http.entity.ContentType;
|
|
import org.apache.http.entity.StringEntity;
|
|
import org.apache.http.impl.client.CloseableHttpClient;
|
|
import org.apache.http.impl.client.HttpClients;
|
|
import org.apache.http.message.BasicHeader;
|
|
import org.eclipse.angus.mail.imap.IMAPFolder;
|
|
import org.imixs.archive.importer.mail.IMAPImportHelper;
|
|
import org.junit.Ignore;
|
|
import org.junit.Test;
|
|
|
|
import com.fasterxml.jackson.databind.JavaType;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
import jakarta.mail.Address;
|
|
import jakarta.mail.BodyPart;
|
|
import jakarta.mail.Folder;
|
|
import jakarta.mail.Message;
|
|
import jakarta.mail.MessagingException;
|
|
import jakarta.mail.Multipart;
|
|
import jakarta.mail.Part;
|
|
import jakarta.mail.Session;
|
|
import jakarta.mail.Store;
|
|
import jakarta.mail.internet.MimeBodyPart;
|
|
import jakarta.mail.internet.MimeUtility;
|
|
import junit.framework.Assert;
|
|
|
|
/**
|
|
* This test shows how to access outlook via oauth2
|
|
*
|
|
* See: https://www.java-forum.org/thema/javamail-mit-oauth2-an-o365.199133/
|
|
*
|
|
* @author rsoika
|
|
*
|
|
*/
|
|
public class TestIMAPOutlookOAuth {
|
|
|
|
private static final String TENANT_ID = "51e2f038-0a96-41be-801d-bb4118aa018e";
|
|
private static final String CLIENT_ID = "39e9eec5-6939-47dc-9729-3438a9898e63";
|
|
// private static final String CLIENT_SECRET =
|
|
// "A6x8Q~EWVUyt~gfyTHtIJf4ig.F9tajUpEEXMaCL";
|
|
|
|
private static final String CLIENT_SECRET = "0lG8Q~UigK0f7n-cR8SSiSXhVChkBD3Qm1CqvbID";
|
|
|
|
/*
|
|
* Neue Daten
|
|
*
|
|
* Wert: zDL8Q~iEy8AX~dEmIOHrVv3aBTCZLrHIFmShibZ_
|
|
* Geheime ID: bcaa558a-3300-4498-94e1-2267f418afd5
|
|
*/
|
|
|
|
@Test
|
|
public void TestMailboxImixs() {
|
|
Store store = null;
|
|
String token = null;
|
|
try {
|
|
// try to connect...
|
|
token = getAuthToken();
|
|
Assert.assertNotNull(token);
|
|
store = connect(token, "imixs@alexander-logistics.com");
|
|
Assert.assertNotNull(store);
|
|
|
|
if (!store.isConnected()) {
|
|
// not connected!
|
|
} else {
|
|
// read inbox....
|
|
IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
|
|
inbox.open(Folder.READ_WRITE);
|
|
// fetches all messages from the INBOX...
|
|
Message[] messages = inbox.getMessages();
|
|
System.out.println("..." + messages.length + " new messages found");
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
} catch (MessagingException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Debug reading first mail....
|
|
*/
|
|
@Test
|
|
@Ignore
|
|
public void TestMailboxImixsDebug() {
|
|
Store store = null;
|
|
String token = null;
|
|
try {
|
|
// try to connect...
|
|
token = getAuthToken();
|
|
Assert.assertNotNull(token);
|
|
store = connect(token, "imixs@alexander-logistics.com");
|
|
Assert.assertNotNull(store);
|
|
|
|
if (!store.isConnected()) {
|
|
// not connected!
|
|
} else {
|
|
// read inbox....
|
|
IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
|
|
inbox.open(Folder.READ_WRITE);
|
|
// fetches all messages from the INBOX...
|
|
Message[] messages = inbox.getMessages();
|
|
System.out.println("..." + messages.length + " new messages found");
|
|
for (Message message : messages) {
|
|
Address[] fromAddress = null;
|
|
String subject = null;
|
|
|
|
// if we can not open the mail (messaging Exception) than we simply skipp this
|
|
// mail see Issue #175
|
|
try {
|
|
System.out.println("...try to open first message...");
|
|
fromAddress = message.getFrom();
|
|
subject = message.getSubject();
|
|
} catch (MessagingException me) {
|
|
System.out.println("...Failed to read message from inbox: " + me.getMessage());
|
|
Assert.fail();
|
|
}
|
|
|
|
System.out.println("......received mail from: " + fromAddress[0].toString());
|
|
System.out.println("......subject = " + subject);
|
|
|
|
Object contentObject = message.getContent();
|
|
if (contentObject instanceof Multipart) {
|
|
System.out.println("......found multipart");
|
|
// here we are save to cast the content to Mulipart
|
|
Multipart multiPart = (Multipart) message.getContent();
|
|
System.out.println("......multipartcount = " + multiPart.getCount());
|
|
for (int i = 0; i < multiPart.getCount(); i++) {
|
|
|
|
BodyPart bodyPart = multiPart.getBodyPart(i);
|
|
if (bodyPart instanceof MimeBodyPart) {
|
|
MimeBodyPart mimeBodyPart = (MimeBodyPart) multiPart.getBodyPart(i);
|
|
if (Part.ATTACHMENT.equalsIgnoreCase(mimeBodyPart.getDisposition())) {
|
|
|
|
String fileName = mimeBodyPart.getFileName();
|
|
if (fileName == null) {
|
|
System.out.println("...skip detaching file, because of missing filename");
|
|
continue; // skip this attachment
|
|
}
|
|
|
|
// decode filename (issue #202)
|
|
fileName = MimeUtility.decodeText(fileName);
|
|
System.out.println("... filename = " + fileName);
|
|
// detach only add PDF files?
|
|
|
|
// add this attachment
|
|
InputStream input = mimeBodyPart.getInputStream();
|
|
byte[] content = IMAPImportHelper.readAllBytes(input);
|
|
String contentType = mimeBodyPart.getContentType();
|
|
|
|
System.out.println("mimetype=" + contentType);
|
|
|
|
System.out.println("content size=" + content.length);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
} catch (MessagingException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
}
|
|
|
|
}
|
|
|
|
@Test
|
|
public void TestMailboxImixsBHV() {
|
|
Store store = null;
|
|
String token = null;
|
|
try {
|
|
// try to connect...
|
|
token = getAuthToken();
|
|
Assert.assertNotNull(token);
|
|
store = connect(token, "Imixsbhv@alexander-logistics.com");
|
|
|
|
Assert.assertNotNull(store);
|
|
|
|
if (!store.isConnected()) {
|
|
// not connected!
|
|
} else {
|
|
// read inbox....
|
|
IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
|
|
inbox.open(Folder.READ_WRITE);
|
|
// fetches all messages from the INBOX...
|
|
Message[] messages = inbox.getMessages();
|
|
System.out.println("..." + messages.length + " new messages found");
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
} catch (MessagingException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
}
|
|
|
|
}
|
|
|
|
@Test
|
|
@Ignore
|
|
public void TestMailboxImixsPL() {
|
|
Store store = null;
|
|
String token = null;
|
|
try {
|
|
// try to connect...
|
|
token = getAuthToken();
|
|
Assert.assertNotNull(token);
|
|
store = connect(token, "imixspl@alexander-logistics.com");
|
|
|
|
Assert.assertNotNull(store);
|
|
|
|
if (!store.isConnected()) {
|
|
// not connected!
|
|
} else {
|
|
// read inbox....
|
|
IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
|
|
inbox.open(Folder.READ_WRITE);
|
|
// fetches all messages from the INBOX...
|
|
Message[] messages = inbox.getMessages();
|
|
System.out.println("..." + messages.length + " new messages found");
|
|
|
|
System.out.println("...read message subjects...");
|
|
|
|
for (Message message : messages) {
|
|
Address[] fromAddress = null;
|
|
String subject = null;
|
|
// if we can not open the mail (messaging Exception) than we simply skipp this
|
|
// mail see Issue #175
|
|
try {
|
|
fromAddress = message.getFrom();
|
|
subject = message.getSubject();
|
|
} catch (MessagingException me) {
|
|
System.out.println("...Failed to read message from inbox: " + me.getMessage());
|
|
Assert.fail();
|
|
}
|
|
|
|
System.out.println("......received mail from: " + fromAddress[0].toString());
|
|
System.out.println("......subject = " + subject);
|
|
|
|
Object contentObject = message.getContent();
|
|
if (contentObject instanceof Multipart) {
|
|
System.out.println("......multipart objects found");
|
|
|
|
// here we are save to cast the content to Mulipart
|
|
Multipart multiPart = (Multipart) message.getContent();
|
|
for (int i = 0; i < multiPart.getCount(); i++) {
|
|
|
|
BodyPart bodyPart = multiPart.getBodyPart(i);
|
|
if (bodyPart instanceof MimeBodyPart) {
|
|
MimeBodyPart mimeBodyPart = (MimeBodyPart) multiPart.getBodyPart(i);
|
|
if (Part.ATTACHMENT.equalsIgnoreCase(mimeBodyPart.getDisposition())) {
|
|
|
|
String fileName = mimeBodyPart.getFileName();
|
|
if (fileName == null) {
|
|
System.out.println("...skip detaching file, because of missing filename");
|
|
continue; // skip this attachment
|
|
}
|
|
|
|
// add this attachment
|
|
InputStream input = mimeBodyPart.getInputStream();
|
|
byte[] content = IMAPImportHelper.readAllBytes(input);
|
|
String contentType = mimeBodyPart.getContentType();
|
|
|
|
System.out
|
|
.println("...Attachment '" + fileName + "' is ok - size=" + content.length);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
System.out.println("...completed!");
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
} catch (MessagingException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
}
|
|
|
|
}
|
|
|
|
@Test
|
|
public void TestMailboxImixsDWC() {
|
|
Store store = null;
|
|
String token = null;
|
|
try {
|
|
// try to connect...
|
|
token = getAuthToken();
|
|
Assert.assertNotNull(token);
|
|
store = connect(token, "Imixsae@alexander-logistics.com");
|
|
|
|
Assert.assertNotNull(store);
|
|
|
|
if (!store.isConnected()) {
|
|
// not connected!
|
|
} else {
|
|
// read inbox....
|
|
IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
|
|
inbox.open(Folder.READ_WRITE);
|
|
// fetches all messages from the INBOX...
|
|
Message[] messages = inbox.getMessages();
|
|
System.out.println("..." + messages.length + " new messages found");
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
} catch (MessagingException e) {
|
|
e.printStackTrace();
|
|
Assert.fail();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* This method returns a connection to an javax.mail.store
|
|
*/
|
|
public Store connect(String oauth2AccessToken, String userEmailId) {
|
|
|
|
try {
|
|
|
|
String host = "outlook.office365.com";
|
|
String port = "993";
|
|
Store store = null;
|
|
|
|
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
|
|
Properties props = new Properties();
|
|
|
|
props.put("mail.imaps.ssl.enable", "true");
|
|
props.put("mail.imaps.sasl.enable", "true");
|
|
props.put("mail.imaps.port", port);
|
|
props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
|
|
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
|
|
|
|
props.put("mail.imaps.auth.login.disable", "true");
|
|
props.put("mail.imaps.auth.plain.disable", "true");
|
|
|
|
props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY);
|
|
props.setProperty("mail.imaps.socketFactory.fallback", "false");
|
|
props.setProperty("mail.imaps.socketFactory.port", port);
|
|
props.setProperty("mail.imaps.starttls.enable", "true");
|
|
|
|
// optional set imap user?
|
|
// props.put("mail.imap.user", userEmailId);
|
|
|
|
props.put("mail.imaps.auth.plain.disable", "true");
|
|
props.put("mail.debug", "true");
|
|
props.put("mail.debug.auth", "true");
|
|
|
|
Session session = Session.getInstance(props);
|
|
session.setDebug(true);
|
|
|
|
store = session.getStore("imaps");
|
|
|
|
System.out.println("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: "
|
|
+ port + ", userEmailId: " + userEmailId + ", AccessToken: " + oauth2AccessToken);
|
|
|
|
store.connect(host, userEmailId, oauth2AccessToken);
|
|
if (store.isConnected()) {
|
|
System.out.println("Connection Established using imap protocol successfully !");
|
|
return store;
|
|
|
|
}
|
|
System.out.println("Store.Connect failed!");
|
|
} catch (Exception e) {
|
|
System.out.println("Store.Connect failed with the errror: " + e.getMessage());
|
|
StringWriter sw = new StringWriter();
|
|
e.printStackTrace(new PrintWriter(sw));
|
|
String exceptionAsString = sw.toString();
|
|
System.out.println(exceptionAsString);
|
|
Assert.fail();
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
/**
|
|
* Helper method to receive a Microsoft access Token
|
|
*
|
|
* https://jwt.ms/
|
|
*
|
|
* "OAuth2": {
|
|
*
|
|
* "Authority":
|
|
* https://login.microsoftonline.com/51e2f038-0a96-41be-801d-bb4118aa018e/v2.0,
|
|
*
|
|
* "ClientId": "39e9eec5-6939-47dc-9729-3438a9898e63",
|
|
*
|
|
* "ClientSecret": "............."
|
|
*
|
|
* }
|
|
*
|
|
*
|
|
* @return
|
|
* @throws IOException
|
|
* @throws ClientProtocolException
|
|
*/
|
|
public String getAuthToken() throws ClientProtocolException, IOException {
|
|
CloseableHttpClient client = HttpClients.createDefault();
|
|
|
|
HttpPost loginPost = new HttpPost("https://login.microsoftonline.com/" + TENANT_ID + "/oauth2/v2.0/token");
|
|
String scopes = "https://outlook.office365.com/.default";
|
|
// scopes="https://outlook.office365.com/IMAP.AccessAsUser.All";
|
|
// scopes="https://graph.microsoft.com/.default";
|
|
// scopes="openid profile offline_access https://outlook.office365.com/SMTP.Send
|
|
// https://outlook.office365.com/POP.AccessAsUser.All
|
|
// https://outlook.office365.com/IMAP.AccessAsUser.All";
|
|
|
|
String encodedBody = "client_id=" + CLIENT_ID + "&scope=" + scopes + "&client_secret=" + CLIENT_SECRET
|
|
+ "&grant_type=client_credentials";
|
|
|
|
loginPost.setEntity(new StringEntity(encodedBody, ContentType.APPLICATION_FORM_URLENCODED));
|
|
|
|
loginPost.addHeader(new BasicHeader("cache-control", "no-cache"));
|
|
CloseableHttpResponse loginResponse = client.execute(loginPost);
|
|
|
|
InputStream inputStream = loginResponse.getEntity().getContent();
|
|
byte[] response = readAllBytes(inputStream);
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
JavaType type = objectMapper.constructType(
|
|
objectMapper.getTypeFactory().constructParametricType(Map.class, String.class, String.class));
|
|
Map<String, String> parsed = new ObjectMapper().readValue(response, type);
|
|
String result = parsed.get("access_token");
|
|
|
|
System.out.println("....access token = " + result);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Helper method to read bytes from strem
|
|
*
|
|
* @param inputStream
|
|
* @return
|
|
* @throws IOException
|
|
*/
|
|
private static byte[] readAllBytes(InputStream inputStream) throws IOException {
|
|
final int bufLen = 4 * 0x400; // 4KB
|
|
byte[] buf = new byte[bufLen];
|
|
int readLen;
|
|
IOException exception = null;
|
|
|
|
try {
|
|
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
|
|
outputStream.write(buf, 0, readLen);
|
|
|
|
return outputStream.toByteArray();
|
|
}
|
|
} catch (IOException e) {
|
|
exception = e;
|
|
throw e;
|
|
} finally {
|
|
if (exception == null)
|
|
inputStream.close();
|
|
else
|
|
try {
|
|
inputStream.close();
|
|
} catch (IOException e) {
|
|
exception.addSuppressed(e);
|
|
}
|
|
}
|
|
}
|
|
} |