Clone any Record Dynamics 365

Hello Everyone,

I was working on a requirement where i have to clone records on multiple custom entities.if the entity having very less fields, you can achieve it easily but what about those entities where attributes are more than 100 per entity. So, i am going to tell you how you can achieve it easily by writing a very small code.

Lets start!

Step-1: Add a button “Clone” using the ribbon workbench on your entity where you want to perform the cloning. Just drag and drop where you want to add.

Now create a command and add an java script action.

Add java script library and function name(code added below). Add a “Crm Parameter= PrimaryControl”.

After that add the command to the button. Publish the solution from ribbon workbench.

Step-2: Now create a global Action process inside your dynamics solution.and create a input parameter of “Entity” type .

we are going to set it through our java script code as below. So while setting the entity type parameter inside the action, we need to specify two properties , 1) GUID of the record , 2) Logical name in key value pair.

Note: Value you can get easily but how you can make “key” dynamic so that it could run on any custom entity. for that you need to pass the key dynamically as shown in below code(check InvokeAction function parameter).

function callAction(primaryControl) {
    debugger;
    var formContext=primaryControl;
    var formtype = formContext.ui.getFormType();
    if(formtype!=1){
    debugger;
    Xrm.Utility.confirmDialog("Do You want Clone this Record?", 
    function () {
     var recordId = formContext.data.entity.getId().replace("{", "").replace("}", "");
     var logicalName = formContext.data.entity.getEntityName();
    InvokeAction(recordId,logicalName);
    },
    function () {});
    
    } 
   }
   function InvokeAction(recordId,logicalName) {
    debugger;
    var parameters = {};
var target = {};
target[logicalName+"id"]=recordId;      //making it dynamics so can be worked on multiple entity
target["@odata.type"] = "Microsoft.Dynamics.CRM."+logicalName;
parameters.Target = target;

var ign_CloneRecordRequest = {
    Target: parameters.Target,

    getMetadata: function() {
        return {
            boundParameter: null,
            parameterTypes: {
                "Target": {
                    "typeName": "mscrm.crmbaseentity",
                    "structuralProperty": 5
                }
            },
            operationType: 0,
            operationName: "ign_CloneRecord"            //specify your action name
        };
    }
};

Xrm.WebApi.online.execute(ign_CloneRecordRequest).then(
    function success(result) {
        if (result.ok) {
            //Success - No Return Data - Do Something
        }
    },
    function(error) {
        Xrm.Utility.alertDialog(error.message);
    }
);
    
   }
   

Step-3:After that you need to create a plugin which will create a clone/copy of the record.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

namespace cloneRecord
{
    public class cloneRecord : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
            tracing.Trace(context.InputParameters.Contains("Target").ToString());
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                if(context.Depth>1)
                {
                    return;
                }
                //Getting the Entity record from the Action
                Entity en = (Entity)context.InputParameters["Target"];
                //Retrieving the same entity record with all the attributes
                Entity entity= service.Retrieve(en.LogicalName, en.Id, new ColumnSet(true));
                //Set the EntityState to null, so that a new cloned record can be created
                entity.EntityState = null;
                //remove the PrimaryId of the record otherwise will show you error
                entity.Attributes.Remove(entity.LogicalName+"id") ;

                if(entity.Contains("new_name") && (string)entity.Attributes["new_name"]!=string.Empty)
                {
                    //differentiating the new record which will create from the exisiting with New prefix.
                    entity.Attributes["name"] = "New " + entity.Attributes["name"].ToString();
                }

                //set a unique id to the cloned record
                entity.Id = Guid.NewGuid();

                //Create the new cloned record
                service.Create(entity);
            }
            }
    }
}

Now register your plugin and use the global action as message inside your plugin step.

Now navigate to custom entity in dynamics model driven app. As you can see here my clone button just click on it.

Now go back to the Entity list record and you will found copied/cloned record as below image. If you want to do cloning of record more than one entity, just follow only the Step-1 as shown above, it will work for any entity.

That’s it.

Hope this will help you. If you having any issues please feel free to ask me . Shoot your question in comment box.

Get Logged In User Security Roles in Dynamics 365 v9.1

Hello , Hope Everyone doing very well. i want to share something which a created for you guys. i was working on a requirement where i need to get logged in user security role.Most of you will already know but i discover a new method,a very short code without using any web API . This will help you to save your time to writ a big code.

function getCurrentUserSecurityRoles(executionContext)
{
	//Returns information about the current user settings.
    var userRoles=Xrm.Utility.getGlobalContext().userSettings;	
	//it will give you count of security a user is having
    if(Object.keys(userRoles.roles._collection).length>0)				
    {
		//userRoles.roles._collection will give you the index of the Current user security role , it contains roleid , and name of the security role
        for ( var rolidcollection in userRoles.roles._collection)		
        {
			//Once you get the index of the security role from where you can retrive id, name of the Security Role
           var currentUserRoles= Xrm.Utility.getGlobalContext().userSettings.roles._collection[rolidcollection].name;    
           console.log(currentUserRoles);
        }
    }
}

If you have any question feel free to ask :).

Switch BPF using Power Automate

Switch BPF using Power Automate

1.Requirement:

Sometimes you need to switch a BPF based on some option set value. e.g. if I have an option set field named “Active BPF” in which I have one or more values. Based upon those values, going to switch BPF instance. Below are the trigger points.

  1. On creation of the case entity record.
  2. On update of an option set field on case entity form.

To achieve this functionality without using single line of code going to use Power Automate CDS Current Environment Connector. There is no solution available for achieving this functionality using Power Automate previously until I developed one. I am sharing my knowledge by which you can achieve the functionality using Power Automate.

3. Prerequisite:

  1. Dynamics 365 Customer Engagement Subscription.
  2. Power Automate Subscription.
  3. CDS Current Environment Subscription.

4.Resolution:

  1. Login to Power Apps with Dynamics 365 Organisation account URL-https://make.powerapps.com/.
  • Left pane you will found list of operation you can perform. Now click on Flows. Click on “+New” button and select Automated-from blank Flow.
  • Then give a proper name and select from the list of the trigger points available-Common Data Service Current Environment.

Trigger: – Create and Update of the Case Entity.

  • In filter attribute you can specify attribute as a part of trigger. e.g. Change of that attribute flow will run.
  • When a user clicks on create “+New” a new case entity record. Default BPF set to the record.

If there are 4 BPF active for case entity than based on their order, default BPF set (Top Order).

  • For setting a new BPF instance you need to delete or make it inactive. In this scenario I am deleting the default BPF instance and setting a new one.

Here Immigration BPF is default BPF. For Setting a new BPF (PWD Business Process Flow), need to delete existing or default BPF Instance.

  • Now let get back to the Flow. Now after the triggering point check the BPF option set value is null or not.

If it is not null,

check the value of the option set, suppose it is PWD BPF value 364840000, then delete the existing or default BPF (Immigration Business Process). For deleting the existing flow instance, need to perform several steps.

  • Get the process using List record CDS current environment action and add filter criteria (name eq ‘Immigration Business Process).
  • List records give you the collection of the record for get the all the data from the collection further we need to iterate the list of records using apply for each control. We need to get the instance of the Immigration Business Process Entity. Again, use the list record CDS Current Environment for getting the immigration business process flow entity instance record using filter query.

In the filter query “_bpf_incidentid_value” is an attribute in Immigration Business Process Entity, reference to the case record and processed/workflowid is Immigration Business Process Flow GUID. Set both values in filter attribute, now you have the record in response. Again, add apply for each control and add delete action of common data service current environment. Specify the entity name and item id is immigration business process entity instance record id.

After deletion of the default or existing process half of the task completed now we need to create the instance of the other business process – PWD Business Process.

  1. Here I am checking the “Active BPF” option set value in Case entity form using switch case condition.

Specify your Option set value.

Check the option set value is Posted Worker-36484000. If it matches than we need to follow some steps to create an instance of the flow and set it to case.

  1. List record process using CDS current environment Action and add filter query name eq ‘PWD Business Process’.
  1. Add apply for each and now we need the process stages of the PWD Business Process. Because while creating new PWD Business Process instance record we need to specify the active stage. In this scenario I am retrieving first Process Stage using filter query. In filter query I am filtering it based on process id which is PWD Business Process Guid and stage name is Case Validation (First stage in PWD BPF).

So now I have process stage. Next, create PWD Business Process Instance.

  1. Add a Apply for each condition it will give me the process stage entity record which I retrieved in previously. Inside it add an action “Create a Record” using CDS Current Environment. Specify the parameter as below.

1.Specify the Name – PWD Business Process

2.Active Stage (Process Stages)-/processstages(processstageid)

Processstages – Plural name of the entity and parameter will be entity guid which I am retrieving from the previous list record Process stages.

3.Incident (Cases) – /incidents(incidentid)

Incidents – Plural name of the case entity and parameter will be entity guid which I am retrieving from the trigger record.

4.Process (Processes)-/workflows(workflowid) pass the PWD BPF Guid.

5.Status Reason- Make status reason active.

It will create an instance of the PWD Business Process and set it to active. After that you need to update the case entity record.

  1. Select the new Action from the Common Data Service Current Environment- Update a Record. Give the entity name and the item id(from the trigger event), update the process id field by passing the PWD Business Process Instance Guid which created in previous step.

After that just terminate the flow.

Follow all the steps and you will be able to switch the BPF using Power Automate Common Data Service Current Environment Connector.

Sending Email to Customer With SSRS PDF Attachment Using JavaScript Dynamics 365 CRM(Online)

Hello everyone ,

I got a task to send an email to the customer(contact), in which I have to send a quote to the customer as a pdf attachment. But every quoted line contains lots of images as note attachment those also should come in pdf and after creating the Report, attach to an email and then sent to the customer. All I have to do dynamic on click of a button. So I am sharing my learning how I did it.

I am creating a blog on how to send an email attachment to the customer. Hope it will you guys.

Part 1:

Creating Email activity with attachment(SSRS pdf report). Also adding the user Signature with the email.

var base64 = null;

function form_onsave(executionContext) {
    debugger;
    var formContext = executionContext.getFormContext();
    if (formContext.getAttribute("ccc_senttocustomer") !== null && formContext.getAttribute("ccc_senttocustomer") !== undefined) {
        var senttocustomer = formContext.getAttribute("ccc_senttocustomer").getValue();
        if (senttocustomer === true) {
            createAttachment();
        }
    }
}
function getReportingSession() {
    var reportName = "Estimate.rdl"; //set this to the report you are trying to download
    //var reportGuid = "170faa66-19ad-e811-a96f-000d3af43d1a"; //set this to the guid of the report you are trying to download 
    var reportGuid = "75cdd688-8bbd-e811-a971-000d3af42a5a"; //set this to the guid of the report you are trying to download 
    var rptPathString = ""; //set this to the CRMF_Filtered parameter            
    var selectedIds = Xrm.Page.data.entity.getId();
    var pth = Xrm.Page.context.getClientUrl() + "/CRMReports/rsviewer/reportviewer.aspx";
    var retrieveEntityReq = new XMLHttpRequest();

    var strParameterXML = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='quote'><all-attributes /><filter type='and'><condition attribute='quoteid' operator='eq' value='" + selectedIds + "' /> </filter></entity></fetch>";

    retrieveEntityReq.open("POST", pth, false);

    retrieveEntityReq.setRequestHeader("Accept", "*/*");

    retrieveEntityReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

    retrieveEntityReq.send("id=%7B" + reportGuid + "%7D&uniquename=" + Xrm.Page.context.getOrgUniqueName() + "&iscustomreport=true&reportnameonsrs=&reportName=" + reportName + "&isScheduledReport=false&p:CRM_quote=" + strParameterXML);
    var x = retrieveEntityReq.responseText.lastIndexOf("ReportSession=");
    var y = retrieveEntityReq.responseText.lastIndexOf("ControlID=");
    // alert("x" + x + "y" + y);
    var ret = new Array();

    ret[0] = retrieveEntityReq.responseText.substr(x + 14, 24);
    ret[1] = retrieveEntityReq.responseText.substr(x + 10, 32);
    return ret;
}

function createEntity(ent, entName, upd) {
    var jsonEntity = JSON.stringify(ent);
    var createEntityReq = new XMLHttpRequest();
    var ODataPath = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc";
    createEntityReq.open("POST", ODataPath + "/" + entName + "Set" + upd, false);
    createEntityReq.setRequestHeader("Accept", "application/json");
    createEntityReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    createEntityReq.send(jsonEntity);
    var newEntity = JSON.parse(createEntityReq.responseText).d;

    return newEntity;
}

function createAttachment() {
    var params = getReportingSession();

    if (msieversion() >= 1) {
        encodePdf_IEOnly(params);
    } else {
        encodePdf(params);
    }
}

var StringMaker = function () {
    this.parts = [];
    this.length = 0;
    this.append = function (s) {
        this.parts.push(s);
        this.length += s.length;
    }
    this.prepend = function (s) {
        this.parts.unshift(s);
        this.length += s.length;
    }
    this.toString = function () {
        return this.parts.join('');
    }
}

var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function encode64(input) {
    var output = new StringMaker();
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    while (i < input.length) {
        chr1 = input[i++];
        chr2 = input[i++];
        chr3 = input[i++];

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output.append(keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4));
    }

    return output.toString();
}

function encodePdf_IEOnly(params) {
    var bdy = new Array();
    var retrieveEntityReq = new XMLHttpRequest();

    var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
    retrieveEntityReq.open("GET", pth, false);
    retrieveEntityReq.setRequestHeader("Accept", "*/*");

    retrieveEntityReq.send();
    bdy = new VBArray(retrieveEntityReq.responseBody).toArray(); // minimum IE9 required

    createNotesAttachment(encode64(bdy));
}

function encodePdf(params) {
    var xhr = new XMLHttpRequest();
    var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
    xhr.open('GET', pth, true);
    xhr.responseType = 'arraybuffer';

    xhr.onload = function (e) {
        if (this.status == 200) {
            var uInt8Array = new Uint8Array(this.response);
            base64 = encode64(uInt8Array);
            CreateEmail(base64);
            createNotesAttachment(base64);
        }
    };
    xhr.send();
}

function msieversion() {

    var ua = window.navigator.userAgent;
    var msie = ua.indexOf("MSIE ");

    if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))      // If Internet Explorer, return version number
        return parseInt(ua.substring(msie + 5, ua.indexOf(".", msie)));
    else                 // If another browser, return 0
        return 0;
}

function createNotesAttachment(base64data) {

    var propertyName;
    var propertyAddress;
    var propertyCity;
    var estimateNumber;
    if (Xrm.Page.getAttribute("name") !== null && Xrm.Page.getAttribute("name") !== undefined) {
        estimateNumber = Xrm.Page.getAttribute("name").getValue();
        //alert(estimateNumber);
    }
    if (Xrm.Page.getAttribute("ccc_propertyid") !== null && Xrm.Page.getAttribute("ccc_propertyid") !== undefined) {
        var propertyNameRef = Xrm.Page.getAttribute("ccc_propertyid");
        if (propertyNameRef != null && propertyNameRef != undefined) {
            propertyId = propertyNameRef.getValue()[0].id.slice(1, -1);
            propertyAddress = propertyNameRef.getValue()[0].name;
            var object = getPropertyAddress(propertyId);
            propertyName = object[1];
            propertyCity = object[2];
        }
    }

    var post = Object();
    post.DocumentBody = base64data;
    post.Subject = estimateNumber+propertyAddress;
    post.FileName = estimateNumber + "-" + propertyName + "-" + propertyAddress + "-" + propertyCity + ".pdf";
    post.MimeType = "application/pdf";
    post.ObjectId = Object();
    post.ObjectId.LogicalName = Xrm.Page.data.entity.getEntityName();
    post.ObjectId.Id = Xrm.Page.data.entity.getId();
    createEntity(post, "Annotation", "");
}

function CreateEmail(base64) {

    var recordURL;
    var propertyName;
    var propertyAddress;
    var propertyCity;
    var estimateNumber;
    var serverURL = Xrm.Page.context.getClientUrl();
    var email = {};
    var qid = Xrm.Page.data.entity.getId().replace(/[{}]/g, "");
    var OwnerLookup = Xrm.Page.getAttribute("ownerid").getValue();
    var OwnerGuid = OwnerLookup[0].id;
    OwnerGuid = OwnerGuid.replace(/[{}]/g, "");
    var ContactLookUp = Xrm.Page.getAttribute("ccc_contact").getValue();
    var ContactId = ContactLookUp[0].id.replace(/[{}]/g, "");
    var contactTypeName = ContactLookUp[0].typename;
    var contactName = ContactLookUp[0].name;
    var signature = getSignature(OwnerGuid);
    if (Xrm.Page.getAttribute("ccc_recordurl") !== null && Xrm.Page.getAttribute("ccc_recordurl") !== undefined) {
        recordURL = Xrm.Page.getAttribute("ccc_recordurl").getValue();
        //alert(estimateNumber);
    }
    if (Xrm.Page.getAttribute("name") !== null && Xrm.Page.getAttribute("name") !== undefined) {
        estimateNumber = Xrm.Page.getAttribute("name").getValue();
        //alert(estimateNumber);
    }
    if (Xrm.Page.getAttribute("ccc_propertyid") !== null && Xrm.Page.getAttribute("ccc_propertyid") !== undefined) {
        var propertyNameRef = Xrm.Page.getAttribute("ccc_propertyid");
        if (propertyNameRef != null && propertyNameRef != undefined) {
            propertyId = propertyNameRef.getValue()[0].id.slice(1, -1);
            propertyAddress = propertyNameRef.getValue()[0].name;
            var object = getPropertyAddress(propertyId);
            propertyName = object[1];
            propertyCity = object[2];
        }
    }

    if (signature == null || signature == undefined) {
        signature = "";
    }
    var string = "Hello " + contactName + " ,</br>Here is the estimate you requested for this location:</br>Estimate # " + estimateNumber + " </br>" + propertyName + "  " + propertyAddress + ",  " + propertyCity + "</br></br>A PDF copy is attached to this email, as well.</br>If you have any questions about this estimate, please reply back to this email or call me.Thank you for considering us!</br></br>" + signature;


    email["subject"] = estimateNumber +"-"+ propertyAddress;
    email["description"] = string;
    email["regardingobjectid_quote@odata.bind"] = "/quotes(" + qid + ")";
    //activityparty collection
    var activityparties = [];
    //from party
    var from = {};
    from["partyid_systemuser@odata.bind"] = "/systemusers(" + OwnerGuid + ")";
    from["participationtypemask"] = 1;
    //to party
    var to = {};
    to["partyid_contact@odata.bind"] = "/contacts(" + ContactId + ")";
    to["participationtypemask"] = 2;

    activityparties.push(to);
    activityparties.push(from);

    //set to and from to email
    email["email_activity_parties"] = activityparties;

    var req = new XMLHttpRequest();
    req.open("POST", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/emails", false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 204) {
                var uri = this.getResponseHeader("OData-EntityId");
                var regExp = /\(([^)]+)\)/;
                var matches = regExp.exec(uri);
                var newEntityId = matches[1];
                createEmailAttachment(newEntityId, base64);
            } else {
                Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send(JSON.stringify(email));
    ///////////////////
}
function createEmailAttachment(emailUri, base64) {
    var activityId = emailUri.replace(/[{}]/g, "");
    var propertyId;
    var propertyName;
    var propertyAddress;
    var propertyCity;
    var estimateNumber;
    if (Xrm.Page.getAttribute("name") !== null && Xrm.Page.getAttribute("name") !== undefined) {
        estimateNumber = Xrm.Page.getAttribute("name").getValue();
    }
    if (Xrm.Page.getAttribute("ccc_propertyid") !== null && Xrm.Page.getAttribute("ccc_propertyid") !== undefined) {
        var propertyNameRef = Xrm.Page.getAttribute("ccc_propertyid");
        if (propertyNameRef != null && propertyNameRef != undefined) {
            propertyId = propertyNameRef.getValue()[0].id.slice(1, -1);
            propertyAddress = propertyNameRef.getValue()[0].name;
            var object = getPropertyAddress(propertyId);
            propertyName = object[1];
            propertyCity = object[2];

        }
    }


    var activityType = "email"; //or any other entity type
    var entity = {};
    entity["objectid_activitypointer@odata.bind"] = "/activitypointers(" + activityId + ")";
    //entity.body = "ZGZnZA=="; //your file encoded with Base64
    entity.body = base64; //your file encoded with Base64
    entity.filename = estimateNumber + "-" + propertyName + "-" + propertyAddress + "-" + propertyCity + ".pdf";
    entity.subject = estimateNumber + "-" + propertyName;
    entity.objecttypecode = activityType;
    var req = new XMLHttpRequest();
    req.open("POST", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/activitymimeattachments", false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 204) {
                var uri = this.getResponseHeader("OData-EntityId");
                var regExp = /\(([^)]+)\)/;
                var matches = regExp.exec(uri);
                var newEntityId = matches[1];
                //alert("attachement created "+newEntityId);
            } else {
                Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send(JSON.stringify(entity));
}
function getPropertyAddress(pid) {
    debugger;
    var ccc_name;
    var ccc_property1;
    var ccc_propertycity;
    var req = new XMLHttpRequest();
    req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/ccc_properties(" + pid + ")?$select=ccc_name,ccc_property1,ccc_propertycity", false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 200) {
                var result = JSON.parse(this.response);
                ccc_name = result["ccc_name"];
                ccc_property1 = result["ccc_property1"];
                ccc_propertycity = result["ccc_propertycity"];
            } else {
                Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send();
    return [ccc_name, ccc_property1, ccc_propertycity];
}
function getSignature(OwnerGuid) {
    debugger;
    var sig;
    var req = new XMLHttpRequest();
    req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/emailsignatures?$select=presentationxml&$filter=_ownerid_value eq " + OwnerGuid, false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 200) {
                var results = JSON.parse(this.response);
                for (var i = 0; i < results.value.length; i++) {
                    var presentationxml = results.value[i]["presentationxml"];
                    oXml = CreateXmlDocument(presentationxml);
                    sig = oXml.lastChild.lastElementChild.textContent;
                }
            } else {
                Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send();
    return sig;
}
function CreateXmlDocument(signatureXmlStr) {
    // Function to create Xml formate of return email template data
    var parseXml;

    if (window.DOMParser) {
        parseXml = function (xmlStr) {
            return (new window.DOMParser()).parseFromString(xmlStr, "text/xml");
        };
    }
    else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
        parseXml = function (xmlStr) {
            var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = "false";
            xmlDoc.loadXML(xmlStr);

            return xmlDoc;
        };
    }
    else {
        parseXml = function () { return null; }
    }

    var xml = parseXml(signatureXmlStr);
    if (xml) {
        return xml;
    }
}

Part 2: Sending the email to customer using plugin.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk.Workflow;
using System.Activities;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
namespace ccc_SendEmail
{
    public class sendEmail : CodeActivity
    {
        [RequiredArgument]
        [Input("RegardingEmail")]
        [ReferenceTarget("email")]
        public InArgument<EntityReference> RegardingEmail { get; set; }

        protected override void Execute(CodeActivityContext executionContext)
        {
            //Create the tracing service

            ITracingService tracingService = executionContext.GetExtension<ITracingService>();

            //Create the context
            IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(null);
            EntityReference emailRefrence = RegardingEmail.Get<EntityReference>(executionContext);

            SendEmailRequest SendEmail = new SendEmailRequest();

            SendEmail.EmailId = emailRefrence.Id;

            SendEmail.TrackingToken = "";

            SendEmail.IssueSend = true;

            SendEmailResponse res = (SendEmailResponse)service.Execute(SendEmail);
            //throw new NotImplementedException();
        }
    }
}

If need any help please use comment section so I can help you more. Thank you.