Thursday, June 9, 2011

SPD Workflow Tasks: email notification customization

[What you have]:

   You have a SharePoint Designed Workflow with action "Collect Data from a User"\"Assign a Form to a Group"\"Assign a To-do Item". The task list has email notification turned on.

[What you want]:

  You want change the default task email notification from the task list.
[What you want to know]:

WSS stores predefined alert templates under {sharepoint root\hive*}\TEMPLATE\XML
                * - If you use SharePoint on a daily basis, you are probably familiar with the SharePoint hive. In SharePoint 2010, the hive is called the SharePoint root.
    If you turn the notification on the Task list: Tasks -> Settings -> Advanced settings -> E-mail Notification; every time the task gets assigned -the email gets sent to the "Assigned to" person.
    The type of such notification is described in alerttemplates.xml:

 <AlertTemplate Type="List"  Name="SPAlertTemplateType.AssignedToNotification">
Here the piece where the text of the email is defined:
                        <Expr2><GetVar Name="RawValue#ContentTypeId" /></Expr2>
                        <Then><GetVar Name="RawValue#EmailBody"/></Then>

The meaning of this CAML piece is following:

   - "RawValue#" - I couldn't find any decent documentation about this value. But my experiment has shown that "RawValue" is the FieldCollection of the SPItem - "Task".

   - CAML gets the ContentTypeId of the task, check if  the content type id has a substring "0x010801"
Why "0x010801"? - There are predefined content types in SharePoint, all  custom content types are inherited from the basic one. The all basic content types are in the file {root folder\hive}\TEMPLATE\FEATURES\ctypes.xml. 
        The content type with ID 0x010801 is a workflow task.
   <ContentType ID="0x010801"
            <FieldRef ID="{58ddda52-c2a3-4650-9178-3bbc1f6e36da}" Name="Link" />
            <FieldRef ID="{16b6952f-3ce6-45e0-8f4e-42dac6e12441}" Name="OffsiteParticipant" />
            <FieldRef ID="{4a799ba5-f449-4796-b43e-aa5186c3c414}" Name="OffsiteParticipantReason" />
            <FieldRef ID="{18e1c6fa-ae37-4102-890a-cfb0974ef494}" Name="WorkflowOutcome" />
            <FieldRef ID="{e506d6ca-c2da-4164-b858-306f1c41c9ec}" Name="WorkflowName" />
            <FieldRef ID="{ae069f25-3ac2-4256-b9c3-15dbc15da0e0}" Name="GUID" />
            <FieldRef ID="{8d96aa48-9dff-46cf-8538-84c747ffa877}" Name="TaskType" />
            <FieldRef ID="{17ca3a22-fdfe-46eb-99b5-9646baed3f16}" Name="FormURN" />
            <FieldRef ID="{78eae64a-f5f2-49af-b416-3247b76f46a1}" Name="FormData" />
            <FieldRef ID="{8cbb9252-1035-4156-9c35-f54e9056c65a}" Name="EmailBody" />
            <FieldRef ID="{47f68c3b-8930-406f-bde2-4a8c669ee87c}" Name="HasCustomEmailBody" />
            <FieldRef ID="{cb2413f2-7de9-4afc-8587-1ca3f563f624}" Name="SendEmailNotification" />
            <FieldRef ID="{4d2444c2-0e97-476c-a2a3-e9e4a9c73009}" Name="PendingModTime" />
            <FieldRef ID="{35363960-d998-4aad-b7e8-058dfe2c669e}" Name="Completed" />
            <FieldRef ID="{1bfee788-69b7-4765-b109-d4d9c31d1ac1}" Name="WorkflowListId" />
            <FieldRef ID="{8e234c69-02b0-42d9-8046-d5f49bf0174f}" Name="WorkflowItemId" />
            <FieldRef ID="{1c5518e2-1e99-49fe-bfc6-1a8de3ba16e2}" Name="ExtendedProperties" />

That means the Alert "AssignedToNotification" checks if the task's content type is inherited from the workflow task. All instances of SPD WF tasks are childs of 0x010801. 
 - If the tasks has a derived workflow task content type, the email body is formed from the  field "EmailBody"  of the task list item.

 I have looked at the content of the field "EmailBody" and it looks like this:
    border-collapse:collapse; width:100%;
    font: 8pt Tahoma;

TD.header { background:#F8F8F9; border:1px solid #E8EAEC;              padding: 12pt 10px 20px 10px; font: 16pt Verdana}
TD.body { border-top:1px solid #E8EAEC; border-bottom:1px solid #E8EAEC; padding: 12pt 10px 24pt 10px; }
TD.footer { border-top:1px solid #E8EAEC; border-bottom:1px solid #9CA3AD; padding: 4pt 10px 4pt 10px; }
A { color:#003399; text-decoration:none; }
A:visited { color:#aa00aa; }.bodytext
    font: 8pt Tahoma;
    color: #000000;

  <BODY class=bodytext>
    <TABLE class=mail cellspacing=0 dir=ltr>
      <TR class=header>
        <TD class=header>Task assigned by SharePOint ETL User on 4/23/2010.<br></TD>
      <TR class=body>
        <TD class=body></TD>
      <TR class=footer><TD class=footer>To complete this task:<br><ol><li>Review <a href="http://webapp/sitecol/subsite1/subsite1_1/Lists/Discussion/DiscussionView.aspx?ID=380">Veronica M. Jackson</a>.</li><li>Perform the specific activities required for t
his task.</li><li><!--[if gte mso 12]>Use the <b>Edit this task</b> button to mark the task as completed. (If you cannot update this task, you might not have access to it. Click <a href="http://
D=379">here</a> to request access.)<![endif]--><![if !(gte mso 12)]><a href="
/webapp/sitecol/subsite1/subsite1_1//Lists/Tasks/DispForm.aspx?ID=379">Edit this task</a> to mark the task as completed.<![endif]></li></ol></TD></TR>


I don't know for sure what puts the value in the "EmailBody" field. But I have a feeling that is OWSSVR.dll

[What you want to do]:

As I can see, here is 2 solutions:

1. Create a copy of alerttemplate.xml and change the CAML query there  - replace <GetVar Name="RawValue#EmailBody"/> with what you want to see in the email, and run the stsadm command:
stsadm -o updatealerttemplates -url {sitecollection url} -f {custom alerttemplate} –lcid 1033
   Consideration:The alert template is applied on the whole site collection. That means that you will change the email notification body for the whole site collection.

2. If you want to change the email body only for particular SPD WF tasks - you want to implement custom event handler on the task list .
  public override void ItemAdding(SPItemEventProperties properties)
                var emailBody = properties.AfterProperties["EmailBody"];
                    properties.AfterProperties["EmailBody"] = getNewEmailBody(emailBody.ToString(),properties.AfterProperties["Title"].ToString());

[What you want to consider]:
For some scenarios - you can avoid the deep diving into alert templates changing - and make use of the SPD WF action: "Send an Email".