Dynamic Attachment for Custom Workflow Email

Ajran Hossain | Jan 8, 2025 min read

How to Add a Dynamic Attachment Generated from a Custom Report for a Custom Workflow Email

Recently, I received a request from a client to develop a Comparison Sheet Module for Quotations with an approval workflow. To achieve this, I followed the official guide for workflow events and responses in Business Central.

While implementing the approval workflow, I encountered a challenge: the need to dynamically attach a document to the email notification sent for approval. After much exploration, I couldn’t find an easier solution, so I decided to tackle this problem by subscribing an event. While this might not be the best solution, it worked for my use case. Here’s how I did it.


Step 1: Subscribe the OnBeforeSend Event

To dynamically attach a file to the email, I subscribed to the OnBeforeSend event of the Email Item table. This event allows me to intercept the email before it’s sent and add the necessary attachment.

[EventSubscriber(ObjectType::Table, Database::"Email Item", OnBeforeSend, '', false, false)]
local procedure OnBeforeSend(var EmailItem: Record "Email Item"; var HideMailDialog: Boolean; var MailManagement: Codeunit "Mail Management"; EmailScenario: Enum "Email Scenario"; var Result: Boolean; var IsHandled: Boolean)

Step 2: Identify the Relevant Record

Using the GetSourceDocuments method, I retrieved all related records for the email. This method provides the source tables, source IDs, and relation types as lists.

EmailItem.GetSourceDocuments(SourceTableList, SourceIDList, SourceRelationTypeList);

// Check if the email is linked to a CS Quote Header
if not SourceTableList.Contains(Database::"CS Quote Header") then
    exit;

To ensure I was attaching the file only to emails related to the CS Quote Header, I checked whether this table was present in the source tables list.


Step 3: Retrieve the Relevant Record Data

Once I confirmed the email was related to a CS Quote Header, I identified the corresponding record using its SystemId.

CSTableIndex := SourceTableList.IndexOf(Database::"CS Quote Header");
SysGuidCS := SourceIDList.Get(CSTableIndex); // Table Index and Source ID are in the same index
CS.GetBySystemId(SysGuidCS);

This step ensures I am working with the exact CS Quote Header record linked to the email.


Step 4: Generate and Attach the PDF

The final step was to generate the PDF file from the CS Quotation Report and attach it to the email.

tempBlob.CreateOutStream(OutStr);
CSQR.SetTableView(CS);
FileName := 'CS Quotation -' + CS."CS No." + '.pdf';
PdfGenerated := CSQR.SaveAs('', format::Pdf, OutStr);

if PdfGenerated then begin
    tempBlob.CreateInStream(InStr);
    EmailItem.AddAttachment(Instr, FileName);
end;

By creating a temporary blob to store the PDF output, I generated the file and added it as an attachment to the Email Item record.


Complete Code

Here is the full implementation of the event subscriber:

[EventSubscriber(ObjectType::Table, Database::"Email Item", OnBeforeSend, '', false, false)]
local procedure OnBeforeSend(var EmailItem: Record "Email Item"; var HideMailDialog: Boolean; var MailManagement: Codeunit "Mail Management"; EmailScenario: Enum "Email Scenario"; var Result: Boolean; var IsHandled: Boolean)
var
    CS: Record "CS Quote Header";
    CSQR: Report "CS Quotation Report";
    tempBlob: Codeunit "Temp Blob";
    PdfGenerated: Boolean;
    SysGuidCS: Guid;
    Instr: InStream;
    CSTableIndex: Integer;
    SourceIDList: List of [Guid];
    SourceRelationTypeList: List of [Integer];
    SourceTableList: List of [Integer];
    OutStr: OutStream;
    format: ReportFormat;
    FileName: Text[250];
begin
    // Retrieve source documents linked to the email
    EmailItem.GetSourceDocuments(SourceTableList, SourceIDList, SourceRelationTypeList);

    // Check if the email is linked to a CS Quote Header
    if not SourceTableList.Contains(Database::"CS Quote Header") then
        exit;

    // Retrieve the CS Quote Header record
    CSTableIndex := SourceTableList.IndexOf(Database::"CS Quote Header");
    SysGuidCS := SourceIDList.Get(CSTableIndex); // Table Index and Source ID are in the same index
    CS.GetBySystemId(SysGuidCS);

    // Generate and attach the PDF
    tempBlob.CreateOutStream(OutStr);
    CSQR.SetTableView(CS);
    FileName := 'CS Quotation -' + CS."CS No." + '.pdf';
    PdfGenerated := CSQR.SaveAs('', format::Pdf, OutStr);

    if PdfGenerated then begin
        tempBlob.CreateInStream(InStr);
        EmailItem.AddAttachment(Instr, FileName);
    end;
end;

This solution worked perfectly for my use case. While there might be other approaches to achieve the same result, this method allowed me to dynamically generate and attach a PDF document to approval emails in a custom workflow. If you’re facing a similar challenge, I hope this helps!