MSGraph Email Poller

Overview

Need to poll emails from your Exchange server? This smart service can be used in a poller process and extract the data from the Microsoft Exchange server. Messages are stored in the Appian Document System, as well as the attachments. Meta data is stored in a database table for further processing.

This plug-in provides an alternative to sending emails to an Appian process model when inbound email integration is requested. Instead of the email being forwarded to Appian, this plug-in reads the emails directly from the Exchange mailbox using the MS Graph API as described below:

  • Reads the mailbox using the MS Graph API
  • Convert the email to an EML file stored as an Appian document; Item attachments (calendar invites, messages) are kept in the eml file, File attachments removed from it and stored separately in the document management system.
  • Store all email file attachments as separate Appian documents
  • Store all email metadata (subject, author, recipients, etc...) into a set of tables in the database

Key Features & Functionality

All information how to deploy, configure and use the smart service is in the 'MS Graph Mail Poller.pdf' document in the downloaded zip. Extract the files in the ZIP and follow the instructions in the document.

Anonymous
  • Hi, I'm trying to configure the pulgin and I have followed the steps in the documentation also added the log4j to debug and I'm getting below error:

    2021-08-09 18:35:18,140 [Appian Work Item - 493 - execution02 : UnattendedJavaActivityRequest] DEBUG com.appiancorp.ps.msgraphmail.MSGraphMailPollerSmartService - Connecting to MS Graph authentication provider
    2021-08-09 18:35:18,146 [Appian Work Item - 493 - execution02 : UnattendedJavaActivityRequest] ERROR com.appiancorp.ps.msgraphmail.MSGraphMailPollerSmartService - Unexpected error polling for mail
    java.util.concurrent.ExecutionException: java.lang.NullPointerException
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908)
    at com.appiancorp.ps.msgraphmail.MSGraphConnector.<init>(MSGraphConnector.java:75)
    at com.appiancorp.ps.msgraphmail.MSGraphMailPollerSmartService.run(MSGraphMailPollerSmartService.java:171)
    at com.appiancorp.process.runtime.framework.DefaultActivityExecutor$1.lambda$call$0(DefaultActivityExecutor.java:131)
    at com.appiancorp.plugins.PluginUsageLogger.runWithPluginInformation(PluginUsageLogger.java:52)
    at com.appiancorp.process.runtime.framework.DefaultActivityExecutor$1.call(DefaultActivityExecutor.java:131)
    at com.appiancorp.process.runtime.framework.DefaultActivityExecutor$1.call(DefaultActivityExecutor.java:125)
    at com.appiancorp.common.ContextClassLoaderSwitcher.runInContext(ContextClassLoaderSwitcher.java:25)
    at com.appiancorp.process.runtime.framework.DefaultActivityExecutor.execute(DefaultActivityExecutor.java:125)
    at com.appiancorp.process.engine.UnattendedJavaActivityRequest.execute(UnattendedJavaActivityRequest.java:88)
    at com.appiancorp.process.engine.UnattendedJavaActivityRequestResponseCreator.getJavaActivityResultResponse(UnattendedJavaActivityRequestResponseCreator.java:21)
    at com.appiancorp.process.engine.UnattendedJavaActivityRequest.getJavaActivityResultResponse(UnattendedJavaActivityRequest.java:67)
    at com.appiancorp.process.engine.UnattendedJavaActivityRequest.execute0(UnattendedJavaActivityRequest.java:55)
    at com.appiancorp.process.engine.ContinuationRequest.executeOuter(ContinuationRequest.java:73)
    at com.appiancorp.process.engine.ContinuationRequest.execute(ContinuationRequest.java:102)
    at com.appiancorp.process.workpoller.UnattendedRequestHandlerBean.onMessage(UnattendedRequestHandlerBean.java:36)
    at com.appiancorp.process.workpoller.WorkItem.run(WorkItem.java:93)
    at org.springframework.jca.work.SimpleTaskWorkManager$DelegatingWorkAdapter.run(SimpleTaskWorkManager.java:239)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
    Caused by: java.lang.NullPointerException
    at com.microsoft.aad.msal4j.AuthenticationResultSupplier.logException(AuthenticationResultSupplier.java:139)
    at com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:88)
    at com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:17)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
    at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1596)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)

    Has someone got this same error, that could help to troubleshoot?

  • v2.1.5 Release Notes
    • Updated the contentType param to allow for the retrieval of both plain text and html
  • How do we get secret, tenant and application ID?

    Suppose I want this mail xxxxx@abc.com to read through this plugin then do I need to register in Azure with same email id?


    My point of asking is, what's the connection between email (Passed in smart service to read) and Azure registration?

    Thanks in advance

  • The only reason can be that the plugin has no access to the Exchange folder name within the Inbox. When it cannot find it, it will move the items to the Deleted Items instead.

    Please validate again the naming is identical. You might be able to find more info in the application log.

    If you require more debugging info from the mailpoller, add the line 

    log4j.logger.com.appiancorp.ps.msgraphmail=DEBUG

    to your deployment/web.war/WEB-INF/resources/log4j.properties

    This will provide all debug info in the application log. Make sure to remove it again once you have found the issue.

  • We are utilizing this plugin across our Dev, Test and Prod environments. We have configuration set to move processed emails into a "Processed" folder.  This works as expected in our Dev and Test environments but in our Prod environment it does not move processed items into the "Processed" folder but moves them to "Deleted Items" folder instead.  All other processing of the emails appears to behave normally. We verified the configuration, naming and security on the "Processed" folder and find no differences.

    What could be possible reasons that the emails would be moved to "Deleted Items" instead of the "Processed" folder specified in the configuration? Thanks.

  • I would then suggest to do postprocessing immediately after you have pulled the mails from the mailbox, i.e. in the same process.

  • The difficulty we're running into with implementing post-processing from the staging table is that we have several different apps polling completely different mailboxes, but the messages all end up in the same staging table in the db without a way for any post-processor to look at the table and identify the messages that are relevant to it. The source mailbox could actually be any address contained in the To, CC, or BCC fields, but to process a row in the staging table correctly, we need to know which mailbox the message was actually polled from.

    Maybe a possible alternative would be if the mail poller could simply write the source mailbox as another column in the db staging table, since that would allow post-processing to easily identify the messages that are relevant for its purposes and ignore the others?

    Thanks again.

  • This is not planned. The idea is that the mail poller will deliver the mails into a staging table, from where you process them for your own needs. If you want to distribute it across multiple tables, you have to design for this yourself in the process after running the mailpoller (e.g. using a stored proc). The Mailpoller should not be run in parallel, so you should create a central process for the collection of mails and if required, distribute it to different tables after processing some specific mailbox.

    All attachments that are recognized by MSGraph as oDataType fileAttachment will be saved as an attachment.

  • Is there any possibility of making optional input parameters for the database tables or Data Store Entity that the plugin will write to, similar to how we can input the specific folder to upload the attachments to? We want to use this for a number of separate apps in our environment, and having it always write emails to the same table means we'll have to do some pretty complicated row-level security to make sure users of each app can only see the emails fetched by that app. 

    It also seems like it's downloading all the inline files, even embedded images from email signatures, instead of just the attachments - a single email with one .pdf attachment ends up creating about 14 files, almost all of which are .png's. Not sure if this is intended behavior. Is there maybe an option we could switch off so we only get the actual attached files?

    Thanks so much!

  • This is not on the current backlog; the solution is built around the concept of extracting emails from the default Inbox. If you have rules on your server moving messages to different folders, make sure they leave the mails in the inbox that should be parsed by the mailpoller