Sending Emails With Report Attachments via API in Business Central
In many integrations, external systems need to trigger Business Central (BC) to email documents—such as sales order confirmations, invoices, or custom reports—directly to customers.
With the BC API page shown below, you can expose an endpoint that receives a Sales Order No. and Customer No., validates both, and then triggers a custom codeunit (SendCustomerEmails) that sends all required reports as email attachments.
This approach allows external applications (ERP integrations, e-commerce systems, automation tools) to call BC and initiate document delivery without user interaction.
Steps to Achieve the goal
- Accepts two fields: (Document No. , Bill-to Customer No.)
- Validates that: The sales order exists, The bill-to customer exists, Both values match a valid Sales Order in BC.
- Call ( SendEmail.SendAllReports(Rec_SHG);)
- where your custom codeunit handles: Generating reports, Attaching PDFs ,Sending emails, Logging activity This creates a simple but powerful integration point.
- Postman pass below body and endpoint
- url : POST /v2.0/api/VJ/APIGroup/v2.0/SendAllReportFromCustom
- body json {“No”: “SO-100152″,”BilltoCustomerNo”: “40000”}
page 50131 “Custom Sales Order API”
{
ApplicationArea = All;
APIGroup = ‘APIGroup’;
APIPublisher = ‘VJ’;
APIVersion = ‘v2.0’;
Caption = ‘SendAllReportFromCustom’;
DelayedInsert = true;
EntityName = ‘SendAllReportFromCustom’;
EntitySetName = ‘SendAllReportFromCustom’;
PageType = API;
SourceTable = “Sales Header”;
Permissions = tabledata “Sales Header” = rimd;
ODataKeyFields = “No.”;
layout
{
area(Content)
{
repeater(General)
{
field(“No”; DocumentNOL)
{
ApplicationArea = All;
trigger OnValidate()
var
Rec_SO: Record “Sales Header”;
Rec_SO1: Record “Sales Header”;
begin
if DocumentNOL = ” then
Error(‘”No.” cannot be empty.’);
Clear(Rec_SO);
Rec_SO.Reset();
Rec_SO.SetRange(“Document Type”, Rec_SO1.”Document Type”::Order);
Rec_SO.SetRange(“No.”, DocumentNOL);
if not Rec_SO.FindFirst() then
Error(‘Sales order does not exist in BC’);
end;
}
field(“BilltoCustomerNo”; BillToCustomerNo)
{
ApplicationArea = All;
trigger OnValidate()
var
Rec_Customer: Record Customer;
Rec_SHG: Record “Sales Header”;
begin
Clear(Rec_Customer);
Rec_Customer.Reset();
Rec_Customer.SetRange(“No.”, BillToCustomerNo);
if not Rec_Customer.FindFirst() then
Error(‘The customer does not exist in BC’)
else begin
if (DocumentNOL <> ”) and (BillToCustomerNo <> ”) then begin
Clear(Rec_SHG);
Rec_SHG.Reset();
Rec_SHG.SetRange(“Document Type”, Rec_SHG.”Document Type”::Order);
Rec_SHG.SetRange(“Bill-to Customer No.”, BillToCustomerNo);
Rec_SHG.SetRange(“No.”, DocumentNOL);
if Rec_SHG.FindFirst() then
SendEmail.SendAllReports(Rec_SHG)
else
Error(
‘No sales order found for the given bill-to customer number %1 and order number %2.’,
BillToCustomerNo, DocumentNOL);
end;
end;
end;
}
}
}
}
var
DocumentNOL: Code[30];
BillToCustomerNo: Code[30];
SendEmail: Codeunit SendCustomerEmails;
}
Codeunit to send email and attach the pdf
codeunit 50016 SendCustomerEmails
{
Permissions = tabledata “Sales Header” = rimd, tabledata “Sales Invoice Header” = rimd;
procedure SendAllReports(var Rec_SH: Record “Sales Header”): Boolean
var
TempBlob: Codeunit “Temp Blob”;
outStream: OutStream;
inStreamVar: InStream;
EmailCU: Codeunit Email;
EmailMsg: Codeunit “Email Message”;
Rec_Customer: Record Customer;
Ref: RecordRef;
begin
Rec_Customer.Reset();
Rec_Customer.SetRange(“No.”, Rec_SH.”Bill-to Customer No.”);
if not Rec_Customer.FindFirst() then
Error(‘Customer not found: %1’, Rec_SH.”Bill-to Customer No.”);
if Rec_Customer.”E-Mail” = ” then
Error(‘No email address found for customer %1’, Rec_Customer.”No.”);
// Create the email message (English only)
EmailMsg.Create(
Rec_Customer.”E-Mail”,
StrSubstNo(‘Your order confirmation – %1’, Rec_SH.”No.”),
StrSubstNo(‘Dear %1, <br><br>Thank you for your order. Attached you will find your order confirmation and related documents.<br><br>Best regards,’, Rec_Customer.”Name”),
true);
// Prepare a record reference for report generation
Ref.Get(Rec_SH.RecordId);
Ref.SetRecFilter();
// Generate first report (e.g. Order Confirmation)
TempBlob.CreateOutStream(outStream);
Report.SaveAs(50100, ”, ReportFormat::Pdf, outStream, Ref);
TempBlob.CreateInStream(inStreamVar);
EmailMsg.AddAttachment(‘OrderConfirmation_’ + Rec_SH.”No.” + ‘.pdf’, ‘application/pdf’, inStreamVar);
// Generate second report (e.g. Invoice or any other report you want)
TempBlob.CreateOutStream(outStream);
Report.SaveAs(1306, ”, ReportFormat::Pdf, outStream, Ref);
TempBlob.CreateInStream(inStreamVar);
EmailMsg.AddAttachment(‘Invoice_’ + Rec_SH.”No.” + ‘.pdf’, ‘application/pdf’, inStreamVar);
// Send the email
EmailCU.Send(EmailMsg);
Message(‘Email with PDF report(s) sent for document No %1’, Rec_SH.”No.”);
exit(true);
end;
}
To conclude, this API lets external systems initiate automatic emailing of sales order reports from Business Central. With just two inputs, you can trigger any complex reporting logic encapsulated inside your custom codeunit.
I Hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudFronts.com.
