OneByte: Adding body and subject text placeholders in Microsoft Dynamics 365 email reports | OnActuate
 In A-ERP, A-How To

Productivity is easier to increase when Microsoft Dynamics 365 Finance & Operations (D365 F&O) comes with the ability to send reports via email and schedule in recurring batches. Print Destination settings give you the flexibility to configure the dynamic value for remail reports, including Subject, To, CC, and the attachment file format. Still, there are limitations such as the lack of functionality to include email body and subject text placeholders. 

However, there is a workaround that resolves this issue. Follow these steps to add email body and subject text placeholders. 

1. Open the print destination form for email. 

 

a. Create an extension of SRSPrintDestinationSettingsForm. Add form string control for body. 

 

b. Create an extension class of SRSPrintDestinationSettingsForm to populate mail body on init.

[ExtensionOf(formStr(SRSPrintDestinationSettingsForm))] 

final class SRSPrintDestinationSettingsForm_Extension 

    public void init() 

    { 

        next init(); 

        SRSPrintDestinationSettings printSettingsLocal = this._printDestinationSettings; 

        FormStringControl mailBodyControl = this.design().controlName(formControlStr(SRSPrintDestinationSettingsForm,MailBody)); 

        mailBodyControl.text(printSettingsLocal.EmailBody()); 

    }  

c. Create an SRSPrintDestinationSettings FormEventHandler class to subscribe formCloseOk delegate. 

class SRSPrintDestinationSettingsFormEventHandler 

    [SubscribesTo(classStr(SRSPrintDestinationSettingsDelegates), delegateStr(SRSPrintDestinationSettingsDelegates, formCloseOk))] 

    public static void SRSPrintDestinationSettingsDelegates_formCloseOk(FormRun settingsForm, SRSPrintDestinationSettings settings) 

    { 

        FormDesign design = settingsForm.design(); 

        FormStringControl mailBodyControl = design.controlName(formControlStr(SRSPrintDestinationSettingsForm,MailBody)); 

        str bodyemail = mailBodyControl.text(); 

        settings.emailBody(bodyemail); 

    } 

d. Create an extension class of SRSReportRunPrinter_extension to populate mail body with placeholders.

Note: In this class, we are using Report DP Class and Report Name from Print Management Settings as examples.

I have added two reports hereone is Coupon which is a custom report and the other is Payment Advice which is a standard report. Add multiple if you have cases for multiple reports. 

[ExtensionOf(classStr(SrsReportRunPrinter))] 

public final class SRSReportRunPrinter_extension 

    public void printReport() 

    { 

        if (reportContract.parmRdpName() == “CouponProformaDP”) //Find DP Class of Report and add name Here 

        { 

            CouponProformaContract coupnProformaContract = reportContract.parmRdpContract() as CouponProformaContract; 

            printSettings.reportTitle(“Coupon Proforma Report”); //As Seen in Screenshot 

            printSettings.voucherRecId(coupnProformaContract.parmCouponProformaRecId()); 

        } 

if (reportContract.parmRdpName() == “BankPaymAdviceVendDP”) //Find DP Class of Report and add name Here 

        { 

            BankPaymAdviceContract bankPaymAdviceContract = reportContract.parmRdpContract() as BankPaymAdviceContract; 

            printSettings.reportTitle(“Payment Advice”); //As Seen in Screenshot 

            printSettings.voucherRecId(bankPaymAdviceContract.parmLedgerJournalTransRecId()); 

        } 

        next printReport(); 

    } 

 

 

e. Create an extension of the SRSPrintDestinationSettings class to augment additional functions.

i. Create a new Data member attribute for Email Body, Report Title and RecId (To get placeholder values)

ii. Using Chain of command, extend the functionality of the parmEMailContract function to set the Body and Subject with placeholders in email contract class.

/// </summary> 

[ExtensionOf(classstr(SRSPrintDestinationSettings))] 

public final class SRSPrintDestinationSettings_Extension 

    internal    str     reportTitle; 

    public      str     emailBody; 

    internal    RecId   voucherRecId; 

 

    #define.CurrentVersion(1) 

    #localmacro.CurrentList 

        emailBody 

    #endmacro 

 

    //Type of report 

    [DataMemberAttribute] 

    public str reportTitle(str _reportTitle = reportTitle) //To get Report Title from Print destinations form 

    { 

        reportTitle = _reportTitle; 

        return reportTitle; 

    } 

 

    [DataMemberAttribute] 

    public RecId voucherRecId(RecId _voucherRecId = voucherRecId) 

    { 

        voucherRecId = _voucherRecId; 

        return voucherRecId; 

    } 

 

    [DataMemberAttribute] 

    public str emailBody(str _value = emailBody) 

    { 

        emailBody = _value; 

        return emailBody; 

    } 

 

/// </summary> 

    public SrsReportEMailDataContract parmEMailContract(SrsReportEMailDataContract _emailContract) 

 

    { 

        SrsReportEmailDataContract  contract; 

        CustQuotationJour           custQuotationJour; 

        contract = next parmEMailContract(_emailContract); 

 

        if(reportTitle == “Coupon Proforma Report”) 

        { 

            emailSubject =     contract.parmSubject(); 

            select firstonly custQuotationJour  where custQuotationJour.RecId == voucherRecId; //RecId is used to get Related Report placeholder values 

 

            emailSubject =  strReplace(emailSubject,”%CustomerName%”,CustTable::find(custquotationjour.InvoiceAccount).name()); 

 

            contract.parmSubject(emailSubject); // Update values 

 

            emailBOdy = strReplace(emailBOdy,”%CustomerName%”,CustTable::find(custquotationjour.InvoiceAccount).name()); 

            emailBOdy = strReplace(emailBOdy,”%LegalEntityName%”,CompanyInfo::findRecId(CompanyInfo::current()).Name); 

 

            contract.parmBody(emailBody); // Update values 

 

        } 

 

        if (reportTitle == “Payment Advice”) 

        { 

 

            emailSubject =     contract.parmSubject(); 

            select firstonly ledgerJournalTrans  where ledgerJournalTrans.RecId == voucherRecId; //RecId is used to get Related Report placeholder values 

 

            emailSubject =  strReplace(emailSubject,”%VendorAccount%”,ledgerJournalTrans.accountDisplay()); 

 

            contract.parmSubject(emailSubject); 

 

            emailBody = contract.parmBody(this.emailBody()); 

 

            emailBody = strReplace(emailBody,”%VendorName%”,ledgerJournalTrans.LedgerDimensionName); 

 

            emailBody = strReplace(emailBody,”%LegalEntityName%”,CompanyInfo::findRecId(CompanyInfo::current()).Name); 

            contract.parmBody(emailBody); 

         }    

        return contract; 

}

 

f. In above created SRSPrintDestination Settings, extend the pack and unpack function.

Extend the Augmented class macro to include mail body and define logic for pack and unpack using the below implementation. Use the pack-unpack pattern to save and/or store the state of an object, and then later re-instantiate the same email parameters on the next run. 

public container pack() 

    { 

        container packedClass = next pack(); 

        return SysPackExtensions::appendExtension(packedClass, classStr(SRSPrintDestinationSettings_Extension), this.demoPack()); 

    } 

 

    private container demoPack() 

    { 

        return [#CurrentVersion, #CurrentList]; 

    } 

 

    public boolean unpack(container _packedClass) 

    { 

        boolean result = next unpack(_packedClass); 

 

        if (result) 

        { 

            container packedExtension = SysPackExtensions::findExtension(_packedClass, classStr(SRSPrintDestinationSettings_Extension)); 

 

            result = this.demoUnpack(packedExtension); 

        } 

 

        return result; 

    } 

 

    private boolean demoUnpack(container _packedClass) 

    { 

        boolean success = false; 

        Integer version = RunBase::getVersion(_packedClass); 

 

        switch (version) 

        { 

            case #CurrentVersion: 

                [version, #currentList] = _packedClass; 

                success = true; 

                break; 

 

            default: 

                success = false; 

                break; 

        } 

 

        return success; 

    } 

2. Send report email including the body and subject with placeholders.

Now we can include the email body and subject in print destination settings. 

 Subject = For %CustomerName% 

 Body    = Good Afternoon, <b>%CustomerName%</b> <Br> Please find Attached Document <Br> Thanks and Regards, <Br> <b>%LegalEntityName%</b><Br> 

(For Formatting Use Appropriate HTML Tags, I have used Line break and bold here, Use Exact placeholder as defined in ParmEmailContract Method for Subject And Body) 

 

 

The report emailed now includes the body and subject with placeholdervalues as well and can be further configured for dynamics messages using print management settings based on conditions. 

Coupon Proforma example: 

 

Payment Advice example: 

 

With these placeholders, you’ll be able to save time when emailing reports and spend more time focusing on your business needs. 

About the expert  

Sachin Mittal, Technical Associate, OnActuate

Sachin is a Microsoft Dynamics certified Technical Associate. He has worked extensively on customization and development of new functionalities and SSRS Reports in Dynamics 365 F&O projects. He also has knowledge of LCS, and DevOps projects and Power Platform including Power Canvas Apps, and integration with D365F&O. Sachin holds multiple certifications including an MB-500: Microsoft Dynamics 365: Finance and Operations Apps Developer and AZ-900: Microsoft Azure Fundamentals certification.

The “OneByte” blog series are technical how-to articles by OnActuate’s expert consultants covering Microsoft Business Applications (Microsoft Dynamics, Power Platform) and related technologies. Have a topic you’d like to learn more about? Email us at info@onactuate.com! 

Our website uses cookies to personalize and enhance your experience and improve the delivery of information to you. By clicking "Accept", you agree to our use of cookies. Click “Learn more” to read our Privacy Policy