Getting emails from the Exchange server and closing tasks by emails

The script below does the following:

  • gets all the incoming mail from a specific mailbox (Exchange server, MAPI/RPC protocol);
  • identifies the task by the email subject (adding a task ID to an email subject is described below);
  • closes the task by a specific transition (the transition is searched by name).

Declare the following namespaces:

using System;
using System.IO;
using System.Linq;
using Aspose.Email;
using Aspose.Email.Exchange;
using Aspose.Email.Mail;
using Aspose.Email.Outlook;
using EleWise.ELMA.API;
using EleWise.ELMA.Files;
using EleWise.ELMA.Model.Managers;
using EleWise.ELMA.Model.Services;
using EleWise.ELMA.Runtime.Managers;
using EleWise.ELMA.Services;
using EleWise.ELMA.Tasks.Models;
using EleWise.ELMA.Workflow.BPMN.Diagrams.Elements;
using EleWise.ELMA.Workflow.Models;
using EleWise.ELMA.Workflow.Services;

The script uses a context variable:

context.Initiator - User type.

Script text:

string resubject = "RE: ";// will be added to the subject when replying
string remessage = "";// reply email text
             
//email setup
string sendFrom = "example@example.com";
string mailboxURI = "https://mail.example.com/EWS/exchange.asmx";
string username = "User";
string password = "password";
string domain = "exapmle";
             
//Create IEWSClient
IEWSClient client = EWSClient.GetEWSClient (mailboxURI, username, password, domain);
ExchangeMailboxInfo mailboxInfo = client.GetMailboxInfo ();
             
string rootUri = client.GetMailboxInfo ().RootUri;
//Get the list of all folders
ExchangeFolderInfoCollection folderInfoCollection = client.ListSubFolders (rootUri);
//Go through folders
foreach (ExchangeFolderInfo folderInfo in folderInfoCollection) 
{
        //Create a filter to receive only unread emails
        string resubject = "RE: ";// will be added to the subject when replying
        string remessage = "";// reply email text

 

//email setup
string sendFrom = "example@example.com";
string mailboxURI = "https://mail.example.com/EWS/exchange.asmx";
string username = "User";
string password = "password";
string domain = "exapmle";
             
//Create IEWSClient
IEWSClient client = EWSClient.GetEWSClient (mailboxURI, username, password, domain);
ExchangeMailboxInfo mailboxInfo = client.GetMailboxInfo ();
             
string rootUri = client.GetMailboxInfo ().RootUri;
//Get the list of all folders
ExchangeFolderInfoCollection folderInfoCollection = client.ListSubFolders (rootUri);
//Go through folders
foreach (ExchangeFolderInfo folderInfo in folderInfoCollection) 
{
    //Create a filter for getting only unread emails
    MailQuery query = new MailQuery ("’IsRead’ = ’False’");
    ExchangeMessageInfoCollection msgInfoColl = client.ListMessages (folderInfo.Uri, query); // get all the unread emails from the folder
                 
    //Go through all emails
    foreach (ExchangeMessageInfo mail in msgInfoColl) 
    {
        long num = 0;
 
        if (!mail.IsRead)//if an email is unread, process it
        {
            client.SetReadFlag (mail.UniqueUri, true); //mark the email as unread                        
            resubject = resubject + mail.Subject.ToString (); //generate the reply email subject                        
            var message = client.FetchMessage (mail.UniqueUri); //get email by uri
            remessage = message.Body; //get the reply email text                        
            string subject = mail.Subject.ToString (); //get the incoming email subject
                         
            string taskstat = ""; //a message for the recipient will be written here
                         
            //get the task ID
            if (subject.Contains ("#")) //the subject contains # + number
            {
                int number;
                var countv = subject.Split (’#’).Count () - 1;
                string splitvar = subject.Split (’#’) [countv]; //get the characters after #
                bool result = Int32.TryParse (splitvar, out number); //attempt parsing a string into a number
                             
                if (result)//if ID is obtained
                {
                    num = Convert.ToInt32 (splitvar);
                }
                else// if ID is not obtained
                {
                     num = 0;
                }
            }
            else//the subject does not contain # + number
            {
                num = 0;
            }
                         
            if (num > 0)//if ID is obtained
            {
                var task = EntityManager<TaskBase>.Instance.LoadOrNull (num); //get a task by ID
                             
                if (task != null) //if the task is obtained by ID
                {
                    var workfl = task.WorkflowBookmark.Instance; //get the process instance
                                 
                    //check the task status
                    if (task.Status == TaskBaseStatus.Complete) {
                        taskstat = "Failed to deliver your reply: The task is already completed. Contact the addressee in another way.";
                     }
                    if (workfl != null)//if the process is not found
                     {
                        //check the process status
                        if (workfl.Status != WorkflowInstanceStatus.Running) 
                        {
                            taskstat = "Failed to deliver your reply: The task is completed. Contact the addressee in another way.";
                        }
                        if ((workfl.Status == WorkflowInstanceStatus.Running) && (task.Status!= TaskBaseStatus.Complete))//"the process is started, the task is active"
                        {
                            //write the email text to the process instance context, EmailResponse context variable of the String type
                            var EmailResponse = (string)workfl.Context.GetType ().GetProperty ("EmailResponse").GetValue (workfl.Context, null);
                            EmailResponse += (string.IsNullOrEmpty (EmailResponse) ? "" : "\r\n") + remessage;
                            workfl.Context.GetType ().GetProperty ("EmailResponse").SetValue (workfl.Context, EmailResponse, null);
                                         
                            //get the email attachments
                            if (message.Attachments.Count > 0) {
                            for (int att = 0; att < message.Attachments.Count; att++) 
                                {
                                    //create an ELMA attachment
                                    var newAtt = InterfaceActivator.Create<EleWise.ELMA.Common.Models.Attachment> ();
                                    //create a file from stream
                                    newAtt.File = CreateBinaryFile (message.Attachments [att].ContentStream, "Attachment №" + att.ToString ());
                                    //and fill in the standard attachment properties
                                    newAtt.CreationAuthor = context.Initiator;
                                    newAtt.CreationDate = DateTime.Now;
                                    newAtt.Save ();
                                                                                                 
                                    //Add an attachment to the context of the EmailAttachments process instance (Attachment, list)
                                    dynamic procContext = workfl.Context;
                                    var itemType = procContext.EmailAttachments.GetType ().GetInterface (typeof(Iesi.Collections.Generic.ISet<>).FullName).GetGenericArguments () [0];
                                    var item = InterfaceActivator.Create (itemType);
                                    procContext.EmailAttachments.Add (newAtt);
                                }
                            }
                                         
                            //Get the process diagram element, by which the task was generated
                            var element = (BPMNFlowElement)task.WorkflowBookmark.Instance.Process.Diagram.Elements.Single (e => e.Uid == task.WorkflowBookmark.ElementUid);
                            //Find an outgoing transition by name. Since it may be one of two tasks, find a match by one of the transitions.
                            var connector = element.OutputConnectors.FirstOrDefault (c => (c.Name == "Email is loaded" || c.Name == "Done"));
                            if (connector != null)//if a transition is found
                            {
                                //Generate data for the task executor
                                var executeData = new WorkflowTaskExecuteData (task, connector.Uid);
                                //Execute the task
                                Locator.GetServiceNotNull<IWorkflowRuntimeService> ().Execute (executeData);
                                taskstat = "You reply was uploaded to the system. The task is completed.";
                            }
                        }
                    }
                }
                else
                {
                    taskstat = "Failed to deliver your reply to the recipient: The task is not found, " + "the email subject may have been changed. Contact the recipient in another way.";
                }
            }
            else
            {
                taskstat = "Failed to deliver your reply to the recipient: The task is not found, " + "the email subject may have been changed. Contact the recipient in another way.";
            }
                         
            // generate the text of the reply email 
            remessage = taskstat + "\r\n\r\n-----Original Message-----\r\n" + "\r\nОт: " + message.From 
            + "\r\nDate: " + message.Date + "\r\nTo: " + message.To + "\r\nSubject: " + message.Subject + "\r\n" + remessage;
                         
            // send the reply email
            var msg = new Aspose.Email.Mail.MailMessage ();
            msg.From = sendFrom;
            msg.To = message.From.Address.ToString ();
            msg.Subject = resubject;
            msg.Body = remessage; 
            client.Send (msg);
        }
    }
}

To create a stream file, this method is used:

private BinaryFile CreateBinaryFile (Stream stream, string fileName)
{
    var temp = BinaryFile.CreateContentFilePath (fileName);
    using (var fs = new FileStream (temp, FileMode.CreateNew, FileAccess.Write)) {
        stream.Seek (0, SeekOrigin.Begin);
        stream.CopyTo (fs);
    }
    var mimeMappingService = Locator.GetServiceNotNull<IMimeMappingService> ();
    var contractTemplate = new BinaryFile {
        ContentType = mimeMappingService.GetTypeByExtension (Path.GetExtension (fileName)),
        Name = Path.GetFileName (fileName),
        ContentFilePath = temp,
        CreateDate = DateTime.Now,
    };
    DataAccessManager.FileManager.SaveFile (contractTemplate);
    return contractTemplate;
}

To add the task ID to the email subject, edit the notification template file. You can find the file in ELMA3-[Edition]\UserConfig\Notifications\ Workflow.Task. Add {SR(’ #’)}{$New.Id} to this line: 

<Subject>
{if {$RecipientSet}=’ExecutorReplaced’}(@{$New.Executor}){end if}({SR(’New task’)}) ’{$New.Subject}’ {SR(’in the process’)} {$New.WorkflowBookmark.Instance.Name} ({$New.WorkflowBookmark.Instance.Process.Name}){SR(’ #’)}{$New.Id}
</Subject>