Making email management as painless as possible

In a previous post I showed how a check-in style leads to newly cataloged emails kicking-off a workflow.  The check-in style resulted in a new label in gmail that I tied to a filter.  Items surfaced via the filter got attached to my gmail label, which in-turn created a record that initiated a workflow.  It's a one-time setup that works well for handling my online form submission.

I get other emails though.  Emails related to projects, for instance.  Some projects may last for 2 days, whilst others may last for 2 months. When I'm on the road I don't want to have to stop and setup a new check-in style for a new project.  In fact, I don't really want to have to setup a new check-in style at all.  Why am I adding/removing check-in styles?  Surely there's got to be a better way.

What I want to have happen

What I want to have happen

 

I want my check-in styles to be managed automatically.  Specifically I want:

  1. A check-in style to exist if there are any incomplete workflows where I'm assigned to an activity and the initiating record is a container.
  2. A check-in style to be removed if the workflow referenced above is completed.

 

 

Time to break out visual studio and write some code! 

If you're not a techie you can scroll to the very end to see the results.


First things first, I create a new class library project.  I referenced the .Net SDK and imported the log4net library via the NuGet package manager.  That gives me a solution that looks like this.

2017-10-08_22-52-20.png

I specify that my Addin implements the Trim Event Processor AddIn interface, which requires that I create a method named ProcessEvent.  In that method I test that the event I react to is one of the relevant events from an activity.  If it is, I call the ManageCheckInStyle method I create next.  Otherwise I exit out of my addin.  

namespace CMRamble.EventProcessor.WorkflowCheckInStyles
{
    public class Addin : TrimEventProcessorAddIn
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Addin));
        public override void ProcessEvent(Database db, TrimEvent evt)
        {
            XmlConfigurator.Configure();
            switch (evt.EventType)
            {
                case Events.ActivityAssigned:
                case Events.ActivityReassigned:
                case Events.ActivityCompleted:
                case Events.ActivityUndone:
                case Events.ActivityCurrent:
                case Events.ActivitySkipped:
                case Events.ActivityNeedsAuthorization:
                    ManageCheckInStyle(db, evt);
                    break;
                default:
                    break;
            }
        }
 
    }
}

Now I create the skeleton of my ManageCheckInStyle method, like shown below.

private void ManageCheckInStyle(Database db, TrimEvent evt)
{
    try
    {
        Activity activity = new Activity(db, evt.ObjectUri);
        if ( activity != null && activity.AssignedTo != null )
        {
            log.Debug($"Activity Uri {evt.ObjectUri}");
            Workflow workflow = activity.Workflow;
            if ( workflow != null && (workflow.Initiator != null && workflow.Initiator.RecordType.UsualBehaviour == RecordBehaviour.Folder) )
            {
                if ( workflow.IsComplete )
                {
                    log.Debug($"Workflow Uri {workflow.Uri} Is Completed");
                }
                else
                {
                    log.Debug($"Workflow Uri {workflow.Uri} not completed");
                }
            }
        }
    }
    catch ( TrimException ex )
    {
        log.Error($"Exception: {ex.Message}", ex);
    }
    finally
    {
    }
}

Then I implemented each of the requirements I laid-out at the top of the post (something is assigned, and workflow is completed).  First I code the logic for when something is assigned to me.

// ensure that there is a check-in style for this container
TrimMainObjectSearch styleSearch = new TrimMainObjectSearch(db, BaseObjectTypes.CheckinStyle)
{
    SearchString = $"owner:{activity.AssignedTo.Uri} container:{workflow.Initiator.Number}"
};
if ( styleSearch.Count == 0 )
{
    log.Debug($"Creating new check-in style");
    CheckinStyle style = new CheckinStyle(workflow.Initiator);
    style.RecordType = new RecordType(db, "Document");
    style.Name = workflow.Initiator.Title;
    style.StyleOwner = activity.AssignedTo;
    style.MoveToDeletedItems = false;
    style.Save();
} else
{
    log.Info("Check-in style already exists");
}

Last,  I create the logic for when the workflow is completed.

// when no other assigned activities for this container 
TrimMainObjectSearch activitySearch = new TrimMainObjectSearch(db, BaseObjectTypes.Activity)
{
    SearchString = $"workflow:[initiator:{workflow.Initiator.Number}] assignee:{activity.AssignedTo.Uri} not done"
};
if (activitySearch.Count == 0 )
{   // there are no other assigned activities
    TrimMainObjectSearch styleSearch = new TrimMainObjectSearch(db, BaseObjectTypes.CheckinStyle)
    {
        SearchString = $"owner:{activity.AssignedTo.Uri} container:{workflow.Initiator.Number}"
    };
    foreach (CheckinStyle style in styleSearch)
    {
        style.Delete();
    }
}

That's it.  I hit compile and I have a valid add-in.  I go and register it in the Enterprise Studio, like shown below.

2017-10-08_23-01-02.png

To test I go find a project folder and attach a workflow (assigning it to myself).  I then flip on over to my email and see the title of that project folder is now a label in my email (or a folder if using Outlook).

2017-10-08_23-15-40.png

If I complete the workflow the check-in style is automatically removed.  Sweet!  Now I can focus on my real work, and not the constant maintenance of my linkage between email & content manager.

Making the EmailLink Admin Console Easier to Use

As I manage my EmailLink instance, I can see a list of users being managed.  That's all well and good, but I really want to see this location within Content Manager.  This should be a link!  Same thing for all the other features.  I wish I could navigate directly to the objects.

No link to the location!

No link to the location!

By changing one line of code I can fix this up....

First I launched Notepad++ and then opened the "EmailLink\pages\users.cshtml" file.  I located the line where it outputs the table and wrapped the column within an anchor tag.

2017-10-03_14-15-29.png

I found this code on line 43:

 
<td>@userProfile.PrimarySmtpAddress</td>

I changed it to this:

 
<td><a target="_new" href="http://wg1/HPEContentManager?uri=@userProfile.Uri&t=location&lang=ln_englishus&mbd=true">@userProfile.PrimarySmtpAddress</a></td>

Then I saved the file and reloaded my EmailLInk admin console.  The column turned into a link that, when clicked, launched a new window directly to the location.

2017-10-03_14-20-31.png

So then I repeated the process for the requisite CheckIn Style template file, so that I get the exact same behavior when looking at the check-in styles themselves.

2017-10-03_14-24-45.png

Wouldn't it be cool if I could click "Duplicate for New User" as an administrator?  :)

2017-10-03_14-29-20.png

Kicking off a workflow from an online form submission

I should be drinking the kool-aid, right?  Meaning, I should be using the features of the product suite to my advantage.  I started to go down the route of trying to figure out how to effectively track when someone "Requests More Information" from my website.  I surely don't want to use 4 different products to manage that process.  Why can't I take the form submission from squarespace and have it kick-off a workflow within Content Manager?  

Once my email link server was configured it took all of about 5 minutes to get this setup.


Here's the workflow I want to kick-off....

 
2017-10-03_13-07-35.png
 

First I went into squarespace and created a submission form.  It sends me an email with the contents of the form.  That email looks like the image below.

2017-10-03_11-56-48.png

Next I went into Content Manager and created myself a new check-in style.  I'm doing this via the webclient, but the process is the same for the thick client.  

 
Web-client

Web-client

 
 

I then gave the check-in style a name and chose my "Request for Information" record type.  

 
2017-10-03_12-03-20.png
 
 

Then I gave it a default workflow template for my process

 
2017-10-03_12-05-04.png
 
 

I then clicked into the processing section and checked the first two check boxes: Automatically create server-side email capture folders and Keep email in the mail system.  By keeping it in there I'm hoping my conversations can be automatically related and captured down the road.

2017-10-03_12-56-40.png

Now after I click save, it shows me my new check-in style

 
2017-10-03_12-07-16.png
 

If I go back to my gmail inbox I can now see this folder available

 
2017-10-03_12-08-57.png
 

Next I create a new filter for my inbox, so that all incoming form submissions are automatically labeled into this folder.

 
2017-10-03_11-34-12.png
 

I know the sender and receiver of the messages I care about, so I define those on the filter like shown below.

 
2017-10-03_12-11-58.png
 

In the other options dialog I indicate the new label name and then click save

 
2017-10-03_11-37-03.png
 

Now I go visit my website and complete the form...

2017-10-03_12-28-15.png

Now if I check my workflows worklist, I can see my workflow has been kicked-off & assigned automatically!

 
2017-10-03_13-09-39.png
 

The things we can accomplish with the newest versions are pretty cool.  I can see lots of useful ways to leverage these features.  Keep in mind that once the form data is within Content Manager, I can apply scripts, code, and add-ons to do anything necessary (like harvest the form data, initiate an integration, etc).

The integration with gmail is secure.  It works.  And it's free (if you have both G Suite and Content Manager).  You just need to configure it.  :)