Send email from template via Javascript

Today we are going to send an email using an email template. I will use Typescript and assume that you have prior experience with this. In the client scripting SDK there is a method called Xrm.Utility.invokeProcessAction, but there are some bugs related to that method, (or I havent figured out how to call this correctly), which make it impossible to use for some actions. Instead we will use the Xrm.WebAPi.online.execute API to call the SendEmailFromTemplate action.

Find the correct parameters to use

First we need to find the correct parameters to use in the call. This can be found in the metadata-document, which is found on the url https://your_instance_name.api.crmX.dynamics.com/api/data/v9.1/$metadata or in the interface by clicking on the cog -> Advanced Settings -> Customizations -> Developer Resources, then copy the Service Root Url and append $metadata to the end. Before opening the metadata document I would advice you to installed some JSON extension to Chrome to get the data formatted. I like to use JSONView. When we open the metadata document we search for SendEmailFromTemplate to find something like this

<Action Name="SendEmailFromTemplate">
<Parameter Name="TemplateId" Type="Edm.Guid" Nullable="false"/>
<Parameter Name="Regarding" Type="mscrm.crmbaseentity" Nullable="false"/>
<Parameter Name="Target" Type="mscrm.crmbaseentity" Nullable="false"/>
<ReturnType Type="mscrm.email" Nullable="false"/>
</Action>

This tells us to call the action of name SendEmailParameter, we must supply it with three arguments, and expect a return type of mscrm.email. Non of the parameters are nullable, meaning that we can not omit any of them. The next step is to learn how to actually call the action.

Call the action from code

Start by opening Visual Studio code and create a new file called EmailService.ts. Open the terminal and write tsc –init to create an initial tsconfig.json file. We the start by defining our EmailService class and and empty method called sendEmailFromTemplate which takes to parameters, the template id and the form context object. How you aquire these to values is up to you, but I called this method from a button in the Ribbon. We are now left with the following code

class EmailService {
    public static sendEmailFromTemplate(templateId: string, formContext: any): void {
    }
}

Next up we will define some helper methods which will make it easier for us to call the actions. These methods are resuable to if you want to, you can extract them out to a utility class. In this example we keep all the code in our EmailService class.

// Wires the call to WebAPI. The docs for this can be fount
// in the link in the post.
private static callAction(actionName: string,
    ...params: Array<
        {
            key: string, // Parameter name
            value: any, // The value
            structuralProperty: number,
            typeName: string, // Type name
            isBoundParameter?: boolean // false if global action
        }>): PromiseLike<any> {
    const request: any = {};
    const metadata: any = { operationName: actionName, operationType: 0 };
    const parameterTypes: any = {};
    for (const param of params) {
        const key: string = param.key;
        request[param.key] = param.value;
        let parameterType: any = {};
        parameterType = {
            structuralProperty: param.structuralProperty,
            typeName: param.typeName
        };
        parameterTypes[key] = parameterType;
        if (param.isBoundParameter) {
            metadata.boundParameter = param.key;
        }
    }
    metadata.parameterTypes = parameterTypes;
    request.getMetadata = () => metadata;
    // Make the actual call to WebAPI
    return Xrm.WebApi.online.execute(request);
}
    // Removes the {} from the string. 
    //Cant use brackets in the calls to WebAPI
    private static removeCurlyBrackets(value: string): string {
        return value.replace(/{|}/gi, "");
    }

Our email that we are sending are from the owner of the Account record to the account.

private static createEmail(formContext: any): any {
    const owner = formContext.getAttribute("ownerid").getValue()![0];
    const accountId = formContext.data.entity.getEntityReference();
    const email: any = { "@odata.type": "Mirosoft.Dynamics.CRM.email" };
    email["regardingobjectid_account_email@odata.bind"] = 
        "/" + accountId.entityType + "s/" + accountId.id;
    const sender: any = {};
    sender["partyid_systemuser@odata.bind"] = 
        "/" + owner.entityType + "s(" + this.removeCurlyBrackets(owner.id) + ")";
    sender["participationtypemask"] = 1; // From
    const receiver: any = {};
    receiver["partyid_account@odata.bind"] = 
        "/" + accountId.entityType + "s(" + this.removeCurlyBrackets(accountId.id) + ")";
    receiver["participationtypemask"] = 2; // To
    email["email_activity_parties"] = [sender, receiver];
    return email;
}

Wrapping all the pieces together we are left with this content in the sendEmailFromTemplate method in our EmailService class.

const email = this.createEmail(formContext);
this.callAction("SendEmailFromTemplate",
    {
        key: "TemplateId",
        value: { guid: templateId },
        structuralProperty: 1,
        typeName: "Edm.Guid"
    },
    {
        key: "Target",
        value: email,
        structuralProperty: 5,
        typeName: "email"
    },
    {
        key: "Regarding",
        value: { entityType: "account", id: formContext.data.entity.getId() },
        structuralProperty: 5,
        typeName: "Edm.Guid"
    }
).then(console.log, (error: {
    code: string, message: string, innerror: { message: string, type: string, stacktrace: string }
}) => {
    const details = error?.innerror?.message + "\n" + error?.innerror?.stacktrace;
    Xrm.Navigation.openErrorDialog({
        details: details,
        message: error.message,
        errorCode: parseInt(error.code, undefined)
    });
});

If we write tsc in the terminal to compile the code to javascript and uploading it into our environment we can then call it like this

EmailService.sendEmailFromTemplate("our-template-guid-goes-here", formContext_goes_here);

I hope you learning something from this!.

Leave a comment