Hi folks,

I’ve been posed with the following task: When the user posts a purchase invoice we would need to get other files attached to the purchase order and send them as attachments alongside with the invoice report itself, in a single email.

After digging the print management framework I found the class that actually sends the email.

The method toEmail() from the SrsReportRunPrinter class sends the email, but inside this method, right before sending the email, it calls the  onToEmail() method from the SRSPrintDestinationSettingsDelegates class, which in return will call the toEmail() delegate and when this delegate returns false it terminates the sending process without errors.

Check the line 11 of the following method:

private void toEmail()
{
    guid printId = newGuid();
    SSRSReportRuntimeEventSource::EventWriteRenderReportToEmailDetailTaskStart(
        "Printing report to email started.",
         reportContract.parmReportExecutionInfo().parmReportRunId(),
         printId);

    try
    {
        if(!delegatesHelper.onToEmail(this, reportContract, reportParamArray))
        {
            SSRSReportRuntimeEventSource::EventWriteRenderReportToEmailDetailTaskStop(
            "Printing report to email ended.",
             reportContract.parmReportExecutionInfo().parmReportRunId(),
             printId);
            return;
        }

        if(!printSettings)
        {
            throw error(strfmt("@SYS318601", 'printSettings'));
        }

        SrsReportEMailDataContract emailContract = printSettings.parmEMailContract();

        if(emailContract)
        {
            SRSReportFileFormat fileFormat = emailContract.parmAttachmentFileFormat();
            SRSImageFileFormat imageFormat = emailContract.parmAttachmentImageFileFormat();
            str attachmentFileName;
            System.Byte[] reportBytes;

            attachmentFileName = this.getAttachmentName(fileFormat, imageFormat);

            reportBytes = this.renderReportToFile(attachmentFileName, fileFormat);

            if (!delegatesHelper.onToSendEmail(reportBytes, this, reportContract, reportParamArray))
            {
                return;
            }

            if (reportBytes && reportBytes.Length > 0)
            {
                if (this.parmReportRunMailer().emailReportWithRetry(emailContract, reportBytes, attachmentFileName))
                {
                    // The report has been successfully sent as attachment to email.
                    str message = delegatesHelper.onToEmailSucceed(this, reportContract);
                    if(message == '')
                    {
                        message = "@SYS344685";
                    }
                    info(message);
                }
                else
                {
                    str message  = delegatesHelper.onToEmailFailed(this, reportContract);
                    if(message)
                    {
                        info(message);
                    }
                }
            }
        }
    }
    finally
    {
        SSRSReportRuntimeEventSource::EventWriteRenderReportToEmailDetailTaskStop(
        "Printing report to email ended.",
         reportContract.parmReportExecutionInfo().parmReportRunId(),
         printId);
    }
}

So, to solve the issue we can subscribe to this delegate and write our own logic to send the email. This way we would be able to add all additional attachments before sending it.

[SubscribesTo(classStr(SRSPrintDestinationSettingsDelegates), delegateStr(SRSPrintDestinationSettingsDelegates, toEmail))]
public static void SRSPrintDestinationSettingsDelegates_toEmail(SrsReportRunPrinter printer, SrsReportDataContract dataContract, Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] paramArray, EventHandlerResult result)
{
    // Add a new parameter in SystemParameters to enable/disable the multiple attachments feature
    if(SystemParameters::find().EnablePrintMgmtMultipleAttachments)
    {
        // Call a static method that will perform the send email logic
        MyMailerClass::sendEmail(...)
       
        // Set result to false
        result.result(false);
    }
}

The custom method that will add the attachments and send the email could be based on the method emailReport() from the SrsReportRunMailer class, as you can see in the following piece of code, this is the out-of-the-box method to add attachments and send emails:

public boolean emailReport(SrsReportEMailDataContract emailContract, System.Byte[] reportBytes, str fileName)
{
    SRSReportFileFormat fileFormat;
    boolean result = false;

    // Check args and validate contract
    if(!emailContract)
    {
        throw error(strfmt("@SYS318601", 'emailContract'));
    }

    if(reportBytes.Length == 0)
    {
        throw error(strfmt("@SYS318601", 'reportBytes'));
    }

    if(!fileName)
    {
        throw error(strfmt("@SYS318601", 'fileName'));
    }

    emailContract.validate();

    // Using mailer to send out report non interactively.
    if(mailer == null)
    {
        this.initMailer();
    }

    if (mailer)
    {
        // Construct mailer message builder and pass all the values from the contract.
        var messageBuilder = new SysMailerMessageBuilder();
        messageBuilder.setFrom(fromAddress)
                      .addTo(emailContract.parmTo())
                      .addCc(emailContract.parmCc())
                      .setSubject(emailContract.parmSubject())
                      .setBody(emailContract.parmBody())
                      .addAttachment(new System.IO.MemoryStream(reportBytes), fileName);
        result = mailer.sendNonInteractive(messageBuilder.getMessage());
    }

    return result;
}

To leverage some of the out-of-the-box code, the new mailer class should extend the SrsReportRunMailer.


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

four − three =