Fill Document Dispatch Placeholders with a Custom Codeunit
Use a custom codeunit to build the complete text value of a Document Dispatch placeholder. The codeunit receives the current document and can return a combination of invoice number, customer name, and your own calculations. Document Dispatch then inserts this text for the assigned placeholder in the email template.
Assign it in the dispatch profile through Output Type Setup → Email Placeholders → Data Mapping Code. The selected CORE data mapping contains a line of type CODEUNIT that calls your codeunit. Select the appropriate mapping for each required placeholder, such as %1 or %2, to define its content yourself. The following example shows the complete setup for a posted sales invoice.
Current document → CORE data mapping (CODEUNIT) → custom codeunit → returned text → placeholder in the email template.
Prerequisites
- A custom AL extension with a dependency on CORE by Simova and its symbols.
- Permission to set up CORE data mappings, execute your codeunit, and read the records it uses.
- For the email example: Document Dispatch with an email template and a dispatch profile for Sales Invoice Header (table 112).
1. Implement the Codeunit
Add the following codeunit to your extension. Adapt the object ID and name to your extension and publish it before selecting it in the mapping.
codeunit 50100 "My Placeholder Mapping"
{
TableNo = "SIM_CORE Temp Table";
trigger OnRun()
var
SalesInvoiceHeader: Record "Sales Invoice Header";
SourceRecordRef: RecordRef;
DocumentTextLbl: Label '%1 | %2', Locked = true;
UnsupportedFunctionErr: Label 'Unsupported function: %1.', Comment = '%1 = Function name';
MissingRecordErr: Label 'The source record could not be found.';
WrongTableErr: Label 'This function requires a posted sales invoice.';
begin
Rec."Function List" := 'DOCUMENTTEXT';
Clear(Rec."Dyn Mapping Return Value");
if Rec.Param = '' then
exit;
if Rec.Param <> 'DOCUMENTTEXT' then
Error(UnsupportedFunctionErr, Rec.Param);
if not SourceRecordRef.Get(Rec.RecID) then
Error(MissingRecordErr);
if SourceRecordRef.Number <> Database::"Sales Invoice Header" then
Error(WrongTableErr);
SourceRecordRef.SetTable(SalesInvoiceHeader);
SourceRecordRef.Close();
Rec."Dyn Mapping Return Value" := CopyStr(
StrSubstNo(DocumentTextLbl,
SalesInvoiceHeader."No.",
SalesInvoiceHeader."Bill-to Name"),
1, MaxStrLen(Rec."Dyn Mapping Return Value"));
end;
}
For a posted invoice with number INV-1001 and bill-to name Contoso, the result is INV-1001 | Contoso. The separator and text composition are defined by your codeunit.
CORE runs the codeunit through its OnRun trigger with a SIM_CORE Temp Table buffer:
| Field | Use |
|---|---|
RecID |
ID of the current source record, for example the posted sales invoice. |
Param |
Value of Execute Codeunit Param, here DOCUMENTTEXT (maximum 50 characters). |
Company |
Current company name, limited to 30 characters. The example reads in the current company. |
Function List |
Comma-separated function names for the parameter lookup. With an empty parameter, the example only fills this list. |
Dyn Mapping Return Value |
Text returned to the placeholder, maximum 250 characters. |
Write the result into Rec."Dyn Mapping Return Value". This text output does not require a return record or a value in the Return Value BLOB. The example uses CopyStr to truncate longer results to the field length. If you support other source tables, adapt the record handling and validation accordingly.
2. Set Up the CORE Data Mapping
- Search for CORE - Data Mappings and choose New.
- Enter Code
DOC-TEXTand a meaningful Description. - Set Starting Table on the card to Sales Invoice Header (112).
- Add exactly one mapping line and select Type
CODEUNITfirst. - Fill the line as follows. The field names below follow the English client.
| Field on the mapping line | Value |
|---|---|
| Type | CODEUNIT |
| Starting Table | Sales Invoice Header (112) |
| Execute Codeunit | 50100 (or your own object ID) |
| Execute Codeunit Param | DOCUMENTTEXT |
Enter DOCUMENTTEXT directly or select it through the parameter lookup. The lookup runs the codeunit with an empty parameter and reads Function List, which is why the example handles this call without reading a source record.
Leave Source Table, Source Field, Starting Field, and Field Filter empty for this example. Do not add RETURN, RETURNFIELD, or CODEUNITRECORD lines: this mapping returns its text directly through the codeunit. Use the same starting table on the line as on the card so that Test Data Mapping can offer records from the correct table.
3. Assign the Mapping to a Placeholder
- Open the Document Dispatch dispatch profile for posted sales invoices and its Output Type Setup.
- Choose Email Placeholders and select or create a placeholder, for example
%1. - Select
DOC-TEXTin Data Mapping Code. Leave Field empty and Fill with BC Salutation disabled for this placeholder. - Use
%1in the assigned email template, for exampleDocument: %1.
When the placeholder is resolved, CORE passes the current record to the codeunit and uses its returned text. The example template text becomes Document: INV-1001 | Contoso.
4. Check the Result
- On the mapping card, choose Test Data Mapping and select a posted sales invoice. Compare the displayed text with its number and bill-to name.
- Prepare an email through the configured Document Dispatch profile and check the resolved placeholder in the email body before sending.
- Repeat with another invoice to verify that the value comes from the current document.
If the value is empty, check the selected mapping code, Type, codeunit ID, parameter, and the assignment to Dyn Mapping Return Value. If no record selection appears during the mapping test, check Starting Table on the mapping line. If an error occurs, also check the source table and the permissions to execute the codeunit and read the source record. Shorten the result if it exceeds 250 characters; the email subject has an additional overall length limit.