Lazy Approval with SharePoint – approve task via email part 3

 

Part 1: https://realworldsharepoint.wordpress.com/2012/06/27/lazy-approval-with-sharepoint-part-1-approve-task-via-email/

Part 2: https://realworldsharepoint.wordpress.com/2012/06/28/lazy-approval-with-sharepoint-approve-task-via-email-part-2/

Building Visual Studio workflows can be a little intimidating at first, but the workflow we will be making in this post is very simple.  The purpose of this workflow is to take the emails as they come into the “Workflow Response” library we setup in step 1 and process them.  This means that the workflow will auto-start on item creation, look at the contents of the mail, get the subject like, parse the 4 variables out, and take action as needed.

Step 1:  Create a Visual Studio Sharepoint 2010 sequential workflow, and call it “ApproveViaEmailWF” or something appropriate.

Step 2:  Add a single “Code” action in the workflow immediately after workflow_activated.  In this example, i also put two LogtoHistory actions around the execute code activity, so i can see what happened on the workflow history page for this workflow item.  Basically, the first one says “Begin workflow”, and the second says “End workflow”.

Now let’s take a look at the code that parses the email:

Double-click the code activity, and you will see the execute code activity method.  You need to include system.io in your code as well:

( this isn’t the cleanest code in the world, but it works.  update as you see fit. )

________________________________________________________________

Imports System.ComponentModel

Imports System.ComponentModel.Design

Imports System.Drawing

Imports System.Workflow.ComponentModel.Compiler

Imports System.Workflow.ComponentModel.Serialization

Imports System.Workflow.ComponentModel

Imports System.Workflow.ComponentModel.Design

Imports System.Workflow.Runtime

Imports System.Workflow.Activities

Imports System.Workflow.Activities.Rules

Imports Microsoft.SharePoint.Workflow

Imports Microsoft.SharePoint.WorkflowActions

Imports System.Net.Mail

Imports System.IO

Public Class Workflow1

Inherits SequentialWorkflowActivity

Public workflowProperties As New SPWorkflowActivationProperties

Public HistoryDescription1 As System.String = Nothing

Public Counter1 As Integer

Public Sub New()

MyBase.New()

InitializeComponent()

End Sub

Private Sub onWorkflowActivated1_Invoked(sender As System.Object, e As System.Workflow.Activities.ExternalDataEventArgs)

HistoryDescription1 = “STARTING WORKFLOW v2.  Pause for 5 minutes for workflow tasks to be unlocked.”

End Sub

Private Sub codeActivity1_ExecuteCode(sender As System.Object, e As System.EventArgs)

Dim obj As Object

Dim sSite As String = “”

Dim sList As String = “”

Dim file As SPFile = workflowProperties.Item.File

obj = workflowProperties.Item

Dim areader As StringReader = New System.IO.StringReader(file.ToString)

Dim breader As StreamReader = New StreamReader(Me.workflowProperties.Item.File.OpenBinaryStream)

Dim str As String = breader.ReadToEnd

Dim tempstr As String = “”

Dim listid As String = “”

Dim taskid As String = “”

Dim sEmailBody As String = “”

Dim pos As Integer = 0

Dim aitem As SPListItem

Try

    Dim msgObj As New System.Net.Mail.MailMessage

Catch ex As Microsoft.SharePoint.SPException

End Try

   Dim testString As String = str

pos = InStr(str, vbCrLf & vbCrLf)

Try

sEmailBody = Mid(str, pos, 100)

Catch ex As Microsoft.SharePoint.SPException

End Try

pos = InStr(str, “Subject: “)

If pos = 0 Then Exit Sub

tempstr = Mid(str, pos + 9, 120)

   Dim firstdash = InStr(tempstr, “+”)

   Dim UserAction = Left(tempstr, firstdash – 1)

tempstr = Right(tempstr, Len(tempstr) – firstdash)

firstdash = InStr(tempstr, “+”)

    Dim thisTask = Mid(tempstr, 3, firstdash – 3)

tempstr = Right(tempstr, Len(tempstr) – firstdash)

firstdash = InStr(tempstr, “+”)

sSite = GetSite(tempstr)

sList = GetList(tempstr)

   Dim gList As New Guid(sList)

sList = Replace(sList, ” “, “%20”)

    Dim site As New SPSite(sSite)

    Using web As SPWeb = site.OpenWeb()

      Try

        Dim alist As SPList = web.Lists(gList)

aitem = alist.GetItemById(CInt(thisTask))

    If UserAction = “APPROVE” Then

        Dim ht As New Hashtable()

ht(“Completed”) = “TRUE”

ht(“PercentComplete”) = 1

ht(“Status”) = “Completed”

ht(SPBuiltInFieldId.WorkflowOutcome) = “Approved”

ht(“Outcome”) = “Approved”

ht(“TaskStatus”) = “Approved”

ht(SPBuiltInFieldId.Description) = “Approved by email.  User comment: “ & sEmailBody

web.AllowUnsafeUpdates = True

        SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

ElseIf UserAction = “REJECT” Then

        Dim ht As New Hashtable()

ht(“Completed”) = “TRUE”

ht(“PercentComplete”) = 0

ht(“Status”) = “Completed”

ht(“Outcome”) = “Rejected”

ht(“TaskStatus”) = “Rejected”

ht(SPBuiltInFieldId.Description) = “Rejected by email.  User comment: “ & sEmailBody

ht(“FormData”) = SPWorkflowStatus.Completed

web.AllowUnsafeUpdates =True

        SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

End If

HistoryDescription1 = “END WORKFLOW.  id=” & thisTask & “: list=” & gList.ToString & “: site=” & sSite & “: action=” & UserAction

    Catch ex As Microsoft.SharePoint.SPException

HistoryDescription1 = ex.Message

       Dim ht As New Hashtable()

ht(“Completed”) = “FALSE”

ht(“PercentComplete”) = 0

ht(“Status”) = “Error”

ht(“Outcome”) = “Error”

ht(“TaskStatus”) = “Error”

ht(SPBuiltInFieldId.Description) = “Error: “ & ex.Message

ht(“FormData”) = SPWorkflowStatus.ErrorOccurred

SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

    End Try

End Using

End Sub

Private Function GetSite(fullString As String) As String

    Dim pos As Integer = InStr(fullString, “SITE”)

    Dim dsh As Integer = InStr(pos, fullString, “+”)

    Dim s As String = Mid(fullString, pos + 4, dsh – 5)

    Return s

End Function

Private Function GetList(fullString As String) As String

    Dim pos As Integer = InStr(fullString, “+LIST”)

    Dim tmp As String = Mid(fullString, pos + 5, 36)

Return tmp

End Function

End Class

_________________________________________________________________________

THAT’S ABOUT IT!   In this code, I didn’t show some of my code, but there are functions to get the taskid, list, site, and action out of the email message.  Also, i am not showing a else clause that handles the REJECTION, but it is pretty much the same code, but sets the percent complete to 0, and the outcome and task status to “Rejected”.  I also do not show how i am setting the log to history, but this is easy…I dynamically set a field called HistoryDescription1 and the log actions simply show what i set it to. The line of code that updates the task is:

SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

Since this isn’t a post about how to develop in Sharepoint, I wont be covering how to setup a development environment, how to test, how to deploy a solution to the production server, or any of that jazz…perhaps that is for a different post.

If this compiles, then you are ready to test it.  Start an approval process on a fake document you put in that “shared documents” library.  Once you receive the email, click the link in it to ACCEPT and send the message.  It should make its way to the “workflow response” library.   From there, you can copy the eml file to your testing environment and work with it.

If all goes right, when you have deployed this to your production server, you should be able to attch the workflow to the “workflow response” library, and have it launch on new item creation.   when the email drops in the library, the workflow runs, updates the task, and exits.  If there was an error, the log will show the error message.  If it completes, then the log shows ‘END GETEMAILCONTENTS’.

 

Advertisements

23 thoughts on “Lazy Approval with SharePoint – approve task via email part 3

  1. […] 3:  https://realworldsharepoint.wordpress.com/2012/06/28/lazy-approval-with-sharepoint-approve-task-via-e… Share this:TwitterFacebookLike this:LikeBe the first to like this. This entry was posted in […]

  2. […] Post navigation ← Previous Next → […]

  3. Russell October 22, 2012 at 10:01 am Reply

    Hi George, I am using your article to create an email approval mechanism, however I am not a coder and am struggling at the last step regarding the code. Are you able to post me a full working version of the code, as the above does not seem to work for me? Thanks.

    • george hardy 4 October 23, 2012 at 4:43 pm Reply

      review the revised code sample for the complete solution. enjoy!

      • Russell October 24, 2012 at 4:21 pm

        Thanks that works great!

      • george hardy 4 October 24, 2012 at 4:56 pm

        awesome! im glad my solution helped someone out there. this is used SO MUCH in my company, none of the managers or executives even use normal approvals anymore. they love this!

        The next step is to figure out how to allow them to type a comment in the body of the email message and use that comment as a task comment for the approval….the problem with that is that email can be plain text, html, rtf, and depending on the mail client used, changes the headers slightly, so this is kinda hard to do.

        I know there are some components that do mail processing and give you a “mail message” object that you can load from a file stream. this way, i could just set the comment to “mail.body” or something. unfortunately, the built-in system.net.mail.mailmessage object does not allow you to create a mail message by sending a streamreader to it (bummer!)….so on to a third party product i guess.

        glad this was helpful!

        george

      • Nick March 20, 2014 at 2:32 am

        I too am about to venture in to the lazy approval process. Similat to Russell my coding skills are limited. Is the code that is posted in part 3 above the ‘revised code sample’ that you mentioned? Or was it an attachement that has been removed. Also, can VS express (basic, C++ or C#?) be used to accomplish the approval? Great descriptions, I cannot thank you enough.

      • george hardy 4 March 21, 2014 at 4:33 pm

        the revised code is in step 3. im not sure, but i don’t think you can do sharepoint workflows in vs express. one way to find out is to create a new project, change it to a 64 bit project, and .net 3.5. then, when you add a new item, you should have a group for Sharepoint 2007/Sharepoint 2010. if you don’t see these groups, then you wont be able to do it. At a minimum, you should be working with VS 2010 pro. now, if you do manage to get pro version of visual studio you will want to do this in c#. even though i provide the code in VB.net, you can easily convert code using one of several online code conversion utilities out there.

        i should also note that this was my first workflow in visual studio. since then, i have discovered that using an event receiver would be a better choice for this, since you can look at the email body much easier. this is useful if you want to set the user’s task comments to what is in the body of the email. one of these days, i will post how to do this (if i can find time).

        -geo

  4. Kalai April 17, 2013 at 10:31 am Reply

    Hi Russel,

    Nice post !!

    You can use ‘SPEmailEventReceiver’ instead of the workflow to update the task. with this, you can even read the mail body and use it as task completion comments.

    • george hardy 4 April 17, 2013 at 4:17 pm Reply

      I was unaware of the email receiver. I plan on doing a new project to implement this. Lazy approval 2.0 on the way!

      Thanks!

  5. HDHT April 23, 2013 at 10:02 pm Reply

    I am starter on sharepoint 2013 and workflow. Recently I built a very simple assign task using sharepoint 2013 designer, and wanted to have Approve & Rejected link action direct from email content, exactly the same as your “Lazy Approval” method. However, I try to insert your code in the workflow, but I could not find where to put them to execute. Can you please give me some advice? Thanks Gorge

    • george hardy 4 April 24, 2013 at 8:01 pm Reply

      in the CodeActivity1 member in the workflow diagram is where you will insert this code.
      by the way, the code i listed is several different functions in the workflow.
      hope this helps.

  6. Rohit July 8, 2013 at 5:54 am Reply

    Hi George,
    I am using your article to create an email approval mechanism, however i am facing some issue in your code activity code, please provide me the full code on my mail ID.

    Thanks in advance.

    Your artice is soo good.

    Regards
    Rohit

    • george hardy 4 July 8, 2013 at 3:55 pm Reply

      can you provide specifics on what isn’t working?

      • Rohit July 9, 2013 at 9:17 am

        Hi George,

        Thanks for replying me, i have created workflow in visual studio 2010 using C# code and i am unable to understand how we are sending mail through code and also where we are passing list and site name, it will be very helpful to me if you provide me the whole solution.

        George really i need your help.

        My personal email id is:-sharmarohit625@gmail.com

        Thanks & Regards
        Rohit Sharma

      • george hardy 4 July 9, 2013 at 2:28 pm

        well, I kind of did give the whole solution.   I don’t send mail from code.   I let sharepoint designer workflows do most of the work.   in sdesigner, when you create a task item, one of the aspects of this is a notification by email to do the task….all from sdesigner.  the only thing code does is wait for an email to come in and process it.   make sure and read pt 1 and 2 of this article.   hope this helps.

        ________________________________

      • george hardy 4 August 27, 2013 at 8:49 pm

        sorry for the late response, as I don’t really monitor this site too much. how far have you gotten? in vs2012 sequential workflows, you will be using the create task item. there is also a send email taskyou will use to send out the notification. I have not done tasks or emails from a vs workflow yet. that is something I will be learning soon.

        it seems that if you are doing an approval to mimic the sp designer workflow, you will be better off with a state machine workflow, since you are doing things like waiting on a task to be approved or not. you might be able to do this with a while loop in the sequential workflow, but wont be as elegant.

        good luck!

  7. Rohit July 11, 2013 at 3:20 am Reply

    George,

    I am not using Sp Designer, will it possible to create this whole mechanism in visual studio 2010 sequential workflow. please providee the guide line

    Thnak you soo much!

  8. SomeOneUnKnown April 7, 2015 at 5:53 pm Reply

    Hi,

    The code looks like is outdated as on .NET 4.5. I tried using it but it keeps saying “System.Workflow.Activities.*” is obsolete and to use “System.Activities.*”. Are you going to post an updated code? Thanks.

    • george hardy 4 January 12, 2016 at 12:20 am Reply

      i haven’t been on this blog too much, but i will be re-doing this soon. it will be done in vs2015 using an email event receiver. stay tuned! cheers.

  9. Tom January 11, 2016 at 11:42 pm Reply

    did you ever create an update to this workflow? (the version 2.0 you spoke about?)

    • george hardy 4 January 12, 2016 at 12:18 am Reply

      no, i haven’t. this has been working well enough that i just haven’t gotten around to it. however, i am moving my company over to sharepoint 2013 in the next few months, so this seems like a good time to rewrite the thing. this time, as stated before, will use an email event receiver and i will likely be writing this one in vs2015. i’ll see if i can get to this in a few weeks. cheers

  10. cjsigler March 1, 2016 at 10:19 pm Reply

    I am now receiving emails in SharePoint when a user clicks APPROVE in the body of an email. I downloaded and installed VS 2010 on my SharePoint 2010 server. Created a Sequential Workflow. Opened codeActivity1 and copied your code over what was there. I am getting an error that “A namespace cannot directly contain member such as fields or methods.” I wish there was more detail on the code. I don’t understand how to connect it to my email doc library or the library that houses my documents that will get their status updated.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: