Keeping track of Emails with EWS and K2

I haven’t posted anything in a while as I have been working on another project, which I am hoping to unveil sometime very soon. In the meantime though  I wanted to talk about K2 and Exchange. Now we all know that K2 can talk to exchange and send emails and receive replies back in the form of SmartActions out of the box.

But what if we wanted to keep track of the emails sent from a K2 app then this gets a bit tricky. We could save the message in a database using  a SmartObject Event and then use the email Event to send the email. Which is an ok approach, but I think something could be done better, where we don’t need to have this two step/event approach.

So lets have a think about about what i want the assembly to do?

  1. Send an email
  2. View the mailbox
  3. View an email

We could modify the existing email event to do what I am suggesting below, but that would be a pain as we would need to do it every time we use the email event and would also require the person building the workflow to be able to write code.  With the approach  I am going to go through, it  will allow anyone to be able to build a workflow where it would track what emails are being sent without having to write code and more importantly every app will be able to see it’s own emails it has sent out.

We are going to create a Email Endpoint Assembly that will allow a workflow to send an email and reference a primary key , SN, Process Instance Id or  application type (see framework) and view it’s mailbox by same type of information.

Getting Started

We will need the following

  1. Visual Studio 2015+
  2. Microsoft exchange web service (EWS URL)
  3. Exchange version
  4. UserAccount specifically setup just to be used for K2 mailbox (I normally create a service account, that just has a mailbox)
  5. User Account Email Address
  6. Microsoft.Exchange.Webservices.dll

To do this i need use the assembly Microsoft.Exchange.Webservices.dll which you can get from here .

Once we have the above we can start building the new email endpoint assembly.

EWS Code

To setup the connection to exchange server,  it is important to identify which version of exchange we are talking too.

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);

When we have created an instance of the exchange service, we then give the instance the exchange web service url.

service.Url = new Uri(“Web service”);

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.Credentials = new WebCredentials("Username", "Password");

service.Url = new Uri("Web service");
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "Email Address");

We have now got a connection to exchange server via it’s web service and we can do a number of different things such as

  1. Send Email
  2. View mailbox contents , such as the inbox or sent items
  3. View an email
  4. We can also do things such as create meeting requests

We will look at the basic code for sending an email

Sending an Email

To send an email we need to create an instance of the EmailMessage object and pass in the Exchange Service Object.

EmailMessage email = new EmailMessage(service);

Once we have done that we can access the properties and methods of EmailMessage object.

So we can give are email a subject email.Subject = “Subject”;

We can also give the email body and decide whether we want to send a plain text or a HTML message.

email.Body = new MessageBody(BodyType.HTML, Body);

EmailMessage email = new EmailMessage(service);
email.Subject = "Subject";
email.Body = new MessageBody(BodyType.HTML, Body);

To add recipients (To, Cc, Bcc) we just need to add the following code

  • email.ToRecipients.Add(“address”);
  • email.CcRecipients.Add(“address”);
  • email.BccRecipients.Add(“address”);

If you have more than one email address for ‘To’ or ‘Cc’ or the ‘Bcc’ then we can simply loop through the correct address method parameter. Like in the example below.

 if (To.Contains(";"))
 {
 String[] to = To.Split(';');
 foreach (var address in to)
 {
 email.ToRecipients.Add(address);
 }
 }
 else
 {
 email.ToRecipients.Add(To);
 }

To send the email we simply use .Send(); method

 email.SendAndSaveCopy();

Now we can send a basic email. So let us have a look how we can now extend this email so it can contain some additional properties that relate to the workflow it is being sent from.

The EmailMessage object allows us to add properties called extend properties and they are really simple to create. The only thing you need to remember is that the GUID used to identify the property must be the same every time we an email is sent and needs to be the same for when when we retrieve the mailbox.

So in this example i am going to bind the process instance id to the email message. We will then be able to search the sent items mailbox and retrieve all the messages that relates to that process instance id.

Creating extend properties.

This is the most important part , extend properties is what allows the ability to be able to group emails by the process Instance I’d, business key etc.. 

Create a Guid called ‘ProcessInstanceId’ and assign it a GUID.

Guid ProcessInstanceId_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc")

We then have to define the extend property by giving the property a name in this case the property is called ‘ProcessInstanceId’ and we define the data type of the property as a ‘String’.

 ExtendedPropertyDefinition ProcessInstanceId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessInstanceId_PropertySetId, "ProcessInstanceId", MapiPropertyType.String);

 

Now that we have defined the property , we can now populate the email with the process instance id. In code example below I am checking to see if the ‘ProcessInstanceId’ is greater than 0 or is not null and if true it will assign the property the value of the ‘ProcessInstanceId’ and if it is false it will assign the property a 0.

email.SetExtendedProperty(ProcessInstanceId_ExtendedPropertyDefinition, (ProcessInstanceId > 0 | ProcessInstanceId != null ? ProcessInstanceId : 0));

 

Now every time we send an email, it will now contain the process instance id.  In the complete code example of the ‘Send Emall’ method below I have also added some additional properties to contain the following

  1. Primary Key of the main business data
  2. ProcessTypeId (framework see here)
  3. Foilo of the process instance
  4. MessageId, so we can identify each email
public static string SendEmail(string Subject,string Body, string To, string Cc,string Bcc,int importance, string sn,string Folio, int? ProcessInstanceId, string ProcessTypeId, string BusinessKey)
 {
 string result = string.Empty;
 ExchangeService service = ConnectToExchange();
 try
 {
 if (To != null || To.Length != 0)
 {
 EmailMessage email = new EmailMessage(service);
 email.Subject = Subject;
 email.Body = new MessageBody(BodyType.HTML, Body);

Guid SN_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition SN_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(SN_PropertySetId, "SN", MapiPropertyType.String);
 email.SetExtendedProperty(SN_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(sn) ? sn : "0_0"));

Guid Folio_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
ExtendedPropertyDefinition Folio_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(Folio_PropertySetId, "Folio", MapiPropertyType.String);
 email.SetExtendedProperty(Folio_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(Folio) ? Folio : "Email Message"));

Guid ProcessInstanceId_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition ProcessInstanceId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessInstanceId_PropertySetId, "ProcessInstanceId", MapiPropertyType.String);
 email.SetExtendedProperty(ProcessInstanceId_ExtendedPropertyDefinition, (ProcessInstanceId > 0 | ProcessInstanceId != null ? ProcessInstanceId : 0));

Guid BusinessKey_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition BusinessKey_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(BusinessKey_PropertySetId, "BusinessKey", MapiPropertyType.String);
 email.SetExtendedProperty(BusinessKey_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(BusinessKey) ? BusinessKey : "0"));

Guid ProcessTypeId_PropertySetId = Guid.Parse("d6520129-3c59-4191-b9d7-4f5160329e4f");ExtendedPropertyDefinition ProcessTypeId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessTypeId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);
 email.SetExtendedProperty(ProcessTypeId_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(ProcessTypeId) ? ProcessTypeId : "00000000-0000-0000-0000-000000000000"));

Guid MessageId_PropertySetId = Guid.Parse("6e997d14-d9b3-4516-8d14-0a10b0aa74aa");
 string MessageId = Guid.NewGuid().ToString();
 ExtendedPropertyDefinition MessageId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(MessageId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);
 email.SetExtendedProperty(MessageId_ExtendedPropertyDefinition, MessageId);



if (To.Contains(";"))
 {
 String[] to = To.Split(';');
 foreach (var address in to)
 {
 email.ToRecipients.Add(address);
 }
 }
 else
 {
 email.ToRecipients.Add(To);
 }



if (!string.IsNullOrEmpty(Cc))
 {
 if (Cc.Contains(";"))
 {
 String[] to = Cc.Split(';');
 foreach( var address in to)
 {
 email.CcRecipients.Add(address);
 }
 }
 else
 {
 email.CcRecipients.Add(Cc);

}
 }

if (!string.IsNullOrEmpty(Bcc))
 {
 if (Bcc.Contains(";"))
 {
 String[] to = Bcc.Split(';');
 foreach (var address in to)
 {
 email.BccRecipients.Add(address);
 }
 }
 else
 {
 email.BccRecipients.Add(Cc);

}
 }

if (importance > 0)
 {
 email.Importance = (importance == 1 ? Microsoft.Exchange.WebServices.Data.Importance.Normal : Importance.High);
 }

email.SendAndSaveCopy();

result = email.Id.ToString();
 }
 }
 catch(Exception ex)
 {
 result = "Error: " + ex.Message.ToString(); 
 }
 finally
 {

}
 return result;
 }

Retrieving an Exchange Mailbox

Now that we can send emails with K2 related data we now need to be able to retrieve those emails. So we can then view them in a SmartForm.

The first thing we need

public static List<EmailBox> GetMailBox(string MailBoxType,int PageSize)
 {
 ItemView view = new ItemView(PageSize);
 List<EmailBox> list = new List<EmailBox>();

Guid SN_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition SN_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(SN_PropertySetId, "SN", MapiPropertyType.String);

Guid Folio_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition Folio_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(Folio_PropertySetId, "Folio", MapiPropertyType.String);

Guid ProcessInstanceId_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition ProcessInstanceId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessInstanceId_PropertySetId, "ProcessInstanceId", MapiPropertyType.String);

Guid BusinessKey_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition BusinessKey_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(BusinessKey_PropertySetId, "BusinessKey", MapiPropertyType.String);

Guid ProcessTypeId_PropertySetId = Guid.Parse("d6520129-3c59-4191-b9d7-4f5160329e4f");
 ExtendedPropertyDefinition ProcessTypeId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessTypeId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);

Guid MessageId_PropertySetId = Guid.Parse("6e997d14-d9b3-4516-8d14-0a10b0aa74aa");
 ExtendedPropertyDefinition MessageId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(MessageId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);

ExchangeService service = ConnectToExchange();
 view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, SN_ExtendedPropertyDefinition, Folio_ExtendedPropertyDefinition, ProcessInstanceId_ExtendedPropertyDefinition, BusinessKey_ExtendedPropertyDefinition, ProcessTypeId_ExtendedPropertyDefinition, MessageId_ExtendedPropertyDefinition);

FindItemsResults<Item> findResults = service.FindItems((MailBoxType == "Sent" ? WellKnownFolderName.SentItems : WellKnownFolderName.Inbox), view);
 foreach(Item email in findResults.Items)
 {
 Item mail = Item.Bind(service, email.Id);
 list.Add(new EmailBox
 {
 MailBoxType = MailBoxType,
 Subject = mail.Subject,
 Body = mail.Body,
 Importance = mail.Importance.ToString(),
 Id = mail.Id.ToString(),
 Categories = mail.Categories.ToString(),
 DateTimeCreated = mail.DateTimeCreated,
 DateTimeReceived = mail.DateTimeReceived,
 DateTimeSent = mail.DateTimeSent,
 Cc = mail.DisplayCc,
 To = mail.DisplayTo,
 SN = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[0].Value.ToString():string.Empty),
 Folio = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[1].Value.ToString(): string.Empty),
 ProcessInstanceId = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[2].Value.ToString(): string.Empty),
 BusinessKey = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[3].Value.ToString(): string.Empty),
 ProcessTypeId = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[4].Value.ToString(): string.Empty),
 MessageId = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[5].Value.ToString(): string.Empty)

});

}
 return list;

}

d

de

Retrieve an Email

Now that we can retrieve a list of emails from a mailbox we now need to be able to retrieve a single email.

We can do this.ww

public static EmailBox GetEmail(string Id)
 {
 EmailBox email = new EmailBox();
 ExchangeService service = ConnectToExchange();

try
 {
 Item mail = Item.Bind(service, (ItemId)Id);
 {
 email.Subject = mail.Subject;
 email.Body = mail.Body;
 email.Importance = mail.Importance.ToString();
 email.Id = mail.Id.ToString();
 email.Categories = mail.Categories.ToString() ;
 email.DateTimeCreated = mail.DateTimeCreated;
 email.DateTimeReceived = mail.DateTimeReceived;
 email.DateTimeSent = mail.DateTimeSent;
 email.Cc = mail.DisplayCc;
 email.To = mail.DisplayTo;
 email.SN = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[0].Value.ToString(): string.Empty);
 email.Folio = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[1].Value.ToString(): string.Empty);
 email.ProcessInstanceId = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[2].Value.ToString(): string.Empty);
 email.BusinessKey = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[3].Value.ToString(): string.Empty);
 email.ProcessTypeId = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[4].Value.ToString(): string.Empty);
 email.MessageId = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[5].Value.ToString(): string.Empty);
}
}
 catch(Exception ex)
 { }
 finally
 {

}
 return email;
 }

 

Now that we have these methods to send an email, retrieve a mailbox and to retrieve an email. We can now register the library as an endpoint assembly. 

We could extend this to be able to add attachments and we could also look at the calendar meeting requests and doing the same with those and extend their properties 

We can then build a SmartObject around it and then we can use it within are workflows and Smartforms. To make it even easier for people to use the new email SmartObject, we could wrap a SmartWizard around the methods.

The full solution can be downloaded from here 

 

Slack and Simple K2 Integration

One of the big messaging apps for team collaboration is Slack and  is perfect platform to demo how to integrate K2 into it. This will be the first article on how we go about doing this.  Slack is free to use and so is great to demo with and it has an ever growing list of third party integration plugins to play with.

So before we start with the demo,what would we expect a K2 slack plugin to behave? I believe it behave in the following way.

  1. Send notifications of tasks that we have to actiontask
  2. Be notified of when task has been completed and what the action was or the workflow has moved to a certain stage or when there is a workflow escalation.
  3. To be able to action a task from inside Slackhomepage_example_hiretron
  4. To be ask Slack what are my outstanding tasks or what is the status of a certain workflow

So lets starts with points 1 and 2 and deal with simple notifications.

 

Building a Simple messaging app for Slack

Lets start with a simple example, where we can K2 notification messages to Slack, whether its a public message , message to a particular group or a message to an individual person.

First of all we need to sign up for Slack and create a team, which you can down from here . Now we have a slack team, we just need to here  to get access to API for Slack.

api_slack

We are starting simple, so click on “Incoming webhooks” and then click on the link ‘ incoming webhook integration

introwebhooks

Building the web hook url

  1. Choose the channel you want to send the messages to, don’t we will be able to override this later on.

introwebhooks12. Click on the green button ‘Add incoming Webhook integration’

3. You can how see your web hook url, copy that.

introwebhooks24. Further down you can also customize the actual message. I have opted for a K2 look.

introwebhooks35. Click on ‘Save’, we have now created are web hook for incoming messaging.

Slack endpoint assembly

Now we have the web hook, we can how write some code, so K2 can use it. We are going to use a endpoint assembly for this. So we are going to create a class that will take the endpoint and allow us to pass in a message, a optional username and optional group.

private static void PostMessage(Payload payload)
 {
 Encoding _encoding = new UTF8Encoding();
 Uri endpoint = new Uri("web hook here");

string payloadJson = JsonConvert.SerializeObject(payload);
 
 using (System.Net.WebClient client = new System.Net.WebClient())
 {
 System.Collections.Specialized.NameValueCollection data = 
new System.Collections.Specialized.NameValueCollection();
 data["payload"] = payloadJson;

var response = client.UploadValues(endpoint, "POST", data);

//The response text is usually "ok"
 string responseText = _encoding.GetString(response);
 }
 }

Simple code for posting a payload of information to the web hook url

public static void PostMessage(string text, string username = null, string channel = null)
 {
 Payload payload = new Payload()
 {
 Channel = channel,
 Username = username,
 Text = text
 };

PostMessage(payload);
 }

The actual public static method, we will be creating a SmartObject from and then using inside a workflow.

We can then build the solution and take the dll  and now tell K2 about it using the ‘Endpoint Assembly broker’. If you don’t know how to do that view my previous post on creating an Endpoint Assembly.

K2Service

Now just build a SmartObject that uses the service instance you just created.

Slack SMO

We can test it in the SmartObject tester

smotester

When it executes we get this response in Slack

smoslack

No that the SmartObject has been created, we can now use this method inside a workflow

Workflow

I am just going to use a simple workflow for this, that has one task and two actions.

test-workflow

We just going to use a SmartObject event to call the Slack notification SmartObject to send a message to the destination user when a task is generated and then a message to the originator when the task is approved or rejected.

SlackSMOEVENT1

SlackSMOEVENT2.PNG

SlackSMOEVENT4

We do something similar for the approve and reject activities, except we put in the originator name and the message is that the task has been approved or rejected depending on the activity.

When we run the workflow the destination user gets this message in Slack

task

With a link to the task, when they action the task the originator will get this message

task1

Next time we will expand on this by making the notifications more advanced and by allowing the user to ask questions about K2.

The source code for this example can be downloaded from here

Next Challenge

It’s that time of the year again where we start to move from those cold winter nights and frosty mornings.  To longer warmer days as we move towards Spring.

For me I am looking for that next  challenge. If your company uses K2 and you need some help whether it be solution design, development of K2 based applications. Or if your organisation is looking to create a centre of excellence within your organisation or you have team members that need to be trained in developing with K2 Blackpearl and Smarforms. Then please get in touch with me  as I am a  K2 Master and I specialise in K2 development and evangelism.

My rates are competive within the K2 market and I am willing to work anywhere in the UK/Europe/World. If you need more than one person then I can also provide your organisation with a K2 development team with each member having in depth knowledge and experience working in the K2 platform

Below is my experience and if you need someone like me in your organisation please email me at simon.allport@cloudfish.solutions or ping me on LinkedIn

With over 17 years experience working on Microsoft based solutions, I have managed and designed solutions for a number of large enterprise clients including the Channel 4,NHS, MOD and NATO.  I am a regular contributor at industry events and have presented at a number of SharePoint conferences.

Working as part of a team, I am highly motivated to produce software that is functional and looks good.  I am security cleared for the Ministry of Defense.

Technologies that I have experience with

C# Crystal Reports
SharePoint 2007,2010,2013 HTML \ XML \CSS
K2 Blackpearl

K2 Appit

JavaScript

WPF Access 97/2000
N-Tier Architecture Object Oriented / Data Modelling
Silver Light ASP \ ASP.net
AJAX IIS \ DNS Administration
SQL Server 00, 05, 08, 12, Azure Office 365
Unit testing VB .net  & VBScript
Entity Framework Linq
SAP

Oracle

Salesforce & Dynamics CRM

Web Services (REST, WCF, Asmx, Azure Data)

Skills:

  • Project Management
  • Solution Design
  • System Analysis
  • Development
  • Technical deep dive talks
  • Leading Training Sessions
  • Presenting at Key Events
  • Researching new technology
  • Proof of concepts
  • Specification Writing
  • Evangelism

Other Qualifications

  • Certified Scrum Master
  • K2 Master
  • K2 Black pearl Core
  • K2 Smart forms builder
  • K2 Connect
  • K2 Extensions
  • K2 SharePoint
  • MCP in .NET Framework 3.5, ASP.NET Application Development
  • .Net Enterprise Solutions
  • Microsoft Curriculum Certificate (SQL Server)

cert

k2_master_badgems_cert_professional_logo_blk_rgb

References and full CV

Available on Request

K2 Management Portal: Using the K2 Scheduler

In the latest update of K2, there is now a management portal and one of the key new features of this is the ability to schedule workflows. Which up to now was only available if you had K2 for SharePoint , Appit or if you could decipher the K2 Scheduler API. Your only other option was to write a windows service that would call your scheduled workflow.

 

How to access the K2 Management portal

The K2 management portal can be accessed from here http://[k2servername]/Management

home

The management portal replaces the management console found in the K2 Work space, but doesn’t replace the work space completely.

The K2 Scheduler lives under ‘Workflow Server’ heading in the menu on the left. Expanding ‘Workflow Server’ you have a number of different options. The one we are after is ‘Schedules’ which is the fourth one down.

home1

Schedules

Clicking on Schedules shows a list of currently scheduled workflows and the ability to ‘Add’, ‘Edit’ and ‘Delete’  scheduled workflows from the scheduler

 

Creating a new scheduled workflow

To create a new scheduled workflow follow the following steps

  1. Click on ‘Schedules’
  2. Click on ‘New’
    scheduler
  3.  A form will pop up, for you to fill in
  4. Enter a name of what the scheduled workflow will be called
  5. Enter a description
  6. Enabled is checked by default
  7. Next enter the name of the workflow you want to schedule, either by entering it’s full name or by clicking on the search button to search for it
  8. Once you have found the desired workflow, it’s process data fields will load up and up have the option to populate them with values
  9. The folio can also use the date and time as default or can be edited with a value
    scheduler1
  10. Now if we scroll down the form, we can now tell the scheduler when it should run
  11. Under pattern, we can choose what the scheduling pattern should be

 

Pattern
Description
Once K2 will schedule the workflow to run just once on a certain day and time

once

Daily K2 will schedule the workflow to run every weekday or intervals of days. It also has a start date and time and can be configured to end after a number of occurrences or by a end date and time

daily

Weekly K2 will schedule the workflow to run at least once a week on a certain day. It also has a start date and time and can be configured to end after a number of occurrences or by a end date and time

scheduler3

Monthly K2 will schedule a workflow to run at least once a month, in monthly intervals. It has the ability to schedule a workflow to start on the last or first day of the month or first / last day of the week. It also has a start date and time and can be configured to end after a number of occurrences or by a end date and time

monthly

Yearly K2 will schedule the workflow to run at least once on a particular month. It has the ability to schedule a workflow to start on the last or first day of the month or first / last day of the week. It also has a start date and time and can be configured to end after a number of occurrences or by a end date and time

yearly

Interval With intervals, you can tell K2 to schedule a workflow to start by minutes, hours, days,months and years.It also has a start date and time and can be configured to end after a number of occurrences or by a end date and time

interval

12. Click on ‘Ok’, the scheduled workflow is now scheduled to start at it’s selected interval.

scheduler4

13. From here you can see when it last ran, whether it has been successful or failed and also the ability to enable and disable the scheduled workflow

scheduler5

With K2 releasing the Scheduler in the management portal, this means we can now build some interesting workflows that relies on scheduling of workflows to perform autonomous daily tasks. Such as sending out daily emails to a subscription list.