Friday, September 10, 2021

Read Multiple Level Response in Business Cental AL Extension by Json Token, Json Object & Json Array

Dear Firends,

Use below sample code to read multiple array document respone in AL Extension

Sample AL Input File 



{
   "orders":[
      {
         "DocumentNo":"SO004349",
         "Status":"Partially Shipped",
         "lines":[
            {
               "LineNo":20000,
               "QtyToShip":1,
               "Status":"Finalised"
            }
         ]
      },
      {
         "DocumentNo":"SO004424",
         "Status":"Partially Shipped",
         "lines":[
            {
               "LineNo":10000,
               "QtyToShip":5,
               "Status":"Finalised"
            },
            {
               "LineNo":20000,
               "QtyToShip":5,
               "Status":"Finalised"
            }
         ]
      },
      {
         "DocumentNo":"SO004423",
         "Status":"Partially Shipped",
         "lines":[
            {
               "LineNo":10000,
               "QtyToShip":4,
               "Status":"Finalised"
            }
         ]
      }
   ]
}

AL Extensoin Code to Read Above File:

procedure UpdateSOShipmentStatus_gFnc(JsonText: Text)Boolean
    var
        SalesHeader_lRec: Record "Sales Header";
        SalesLine_lRec: Record "Sales Line";
        WarehouseShipLine_lRec: Record "Warehouse Shipment Line";
        Jtoken: JsonToken;
        JObject: JsonObject;
        jsonval: JsonValue;
        Jarray: JsonArray;
        i: Integer;
        j: Integer;
        TotalCount: Integer;
        OrderCount: Integer;
        Location_lRec: Record Location;
        ReqWareShip_lBln: Boolean;
        AnylineFound_lBln: Boolean;
    begin
        if not JObject.ReadFrom(JsonTextthen
            Error('Invalid response, expected a JSON object');

        JObject.Get('orders', Jtoken);

        if not Jarray.ReadFrom(Format(Jtoken)) then
            Error('Array not Reading Properly');

        TotalCount := 0;
        OrderCount := 0;
        TotalCount := Jarray.Count();
        for i := 0 to Jarray.Count() 1 do begin
            Jarray.Get(i, Jtoken);
            JObject := Jtoken.AsObject();

            Jtoken.AsObject.Get('DocumentNo', Jtoken);
            IF SalesHeader_lRec.GET(SalesHeader_lRec."Document Type"::Order, Jtoken.AsValue().AsCode()) then begin
                OrderCount += 1;

                Jarray.Get(i, Jtoken);
                if Jtoken.AsObject.Get('Status', Jtokenthen
                    SalesHeader_lRec."Shipment Status" := Jtoken.AsValue().AsText();

                JObject.Get('lines', Jtoken);
                for j := 0 to Jtoken.AsArray().Count() 1 do begin
                    JObject.Get('lines', Jtoken);
                    if Jtoken.AsArray().Get(j, Jtokenthen
                        Jtoken.AsObject.Get('LineNo', Jtoken);

                    if SalesLine_lRec.Get(SalesLine_lRec."Document Type"::Order, SalesHeader_lRec."No.", Jtoken.AsValue().AsInteger()) then begin
                        JObject.Get('lines', Jtoken);
                        if Jtoken.AsArray().Get(j, Jtokenthen
                            if Jtoken.AsObject.Get('QtyToShip', Jtokenthen begin
                                ReqWareShip_lBln := false;
                                IF Location_lRec.GET(SalesLine_lRec."Location Code"Then begin
                                    IF Location_lRec."Require Receive" Then begin
                                        ReqWareShip_lBln := true;
                                        WarehouseShipLine_lRec.RESET;
                                        WarehouseShipLine_lRec.Setrange("Source Type", 37);
                                        WarehouseShipLine_lRec.Setrange("Source Subtype", SalesLine_lRec."Document Type");
                                        WarehouseShipLine_lRec.Setrange("Source No.", SalesLine_lRec."Document No.");
                                        WarehouseShipLine_lRec.Setrange("Source Line No.", SalesLine_lRec."Line No.");
                                        IF WarehouseShipLine_lRec.FindFirst() Then begin
                                            IF WarehouseShipLine_lRec."Qty. Outstanding" <= Jtoken.AsValue().AsDecimal() THen
                                                WarehouseShipLine_lRec.Validate("Qty. to Ship", Jtoken.AsValue().AsDecimal())
                                            Else
                                                WarehouseShipLine_lRec.Validate("Qty. to Ship", WarehouseShipLine_lRec."Qty. Outstanding");

                                            WarehouseShipLine_lRec.Modify();
                                            AnylineFound_lBln := true;
                                        end;

                                    end;
                                end;
                                IF NOT ReqWareShip_lBln Then
                                    SalesLine_lRec.Validate("Qty. to Ship", Jtoken.AsValue().AsDecimal());
                            End;

                        JObject.Get('lines', Jtoken);
                        if Jtoken.AsArray().Get(j, Jtokenthen
                            if Jtoken.AsObject.Get('Status', Jtokenthen begin
                                SalesLine_lRec."Shipment Status" := Jtoken.AsValue().AsText();
                                SalesLine_lRec.Modify(true);
                                AnylineFound_lBln := true;

                                WarehouseShipLine_lRec.RESET;
                                WarehouseShipLine_lRec.Setrange("Source Type", 37);
                                WarehouseShipLine_lRec.Setrange("Source Subtype", SalesLine_lRec."Document Type");
                                WarehouseShipLine_lRec.Setrange("Source No.", SalesLine_lRec."Document No.");
                                WarehouseShipLine_lRec.Setrange("Source Line No.", SalesLine_lRec."Line No.");
                                IF WarehouseShipLine_lRec.FindFirst() Then begin
                                    WarehouseShipLine_lRec."Shipment Status" := SalesLine_lRec."Shipment Status";
                                    WarehouseShipLine_lRec.Modify();
                                    AnylineFound_lBln := true;
                                End;


                            end;
                    end;
                    SalesHeader_lRec.Modify(true);
                    AnylineFound_lBln := true;
                end;
            end;
        end;
        exit(AnylineFound_lBln);
    End;


Saturday, August 21, 2021

System.IO.IOException - The file exists --- Dyamics NAV

Hello Experts,

I have face many time below error and it is very hard to find solution first time.

Now i have solution for below issue so though to share with you. 

Error details in event log:

==============================================================

Server instance: DynamisNAV90

Tenant ID: <ii>default</ii>

<ii>Session type: Background

Session ID: 18694

User:

Type: System.IO.IOException

Message:

  <ii>The file exists.

  </ii>

StackTrace:

     at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

     at System.IO.Path.InternalGetTempFileName(Boolean checkHost)

     at Microsoft.Dynamics.Nav.Runtime.NavReport.GetSaveAsRenderer(String fileName, ReportFormat format, String& tempFilePath)

     at Microsoft.Dynamics.Nav.Runtime.NavReport.SaveAs(DataError errorLevel, Int32 reportId, String fileName, NavRecord record, ReportFormat format)

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.SaveReportAsHTML_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.SaveReportAsHTML(Int32 reportID, NavVariant recordVariant, NavCode layoutCode)

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.GetEmailBody_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.GetEmailBody(ByRef`1 serverEmailBodyFilePath, Int32 reportUsage, NavVariant recordVariant, NavCode custNo, ByRef`1 custEmailAddress, NavCode docNo_iRec)

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.OnInvoke(Int32 memberId, Object[] args)

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.SendEmailToCustDirectly_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.SendEmailToCustDirectly(Int32 reportUsage, NavVariant recordVariant, NavCode docNo, NavText docName, Boolean showDialog, NavCode custNo)

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.SendEmailInBackground_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.SendEmailInBackground(INavRecordHandle jobQueueEntry)

     at Microsoft.Dynamics.Nav.BusinessApplication.Record77.OnInvoke(Int32 memberId, Object[] args)

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit260.OnRun_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit260.OnRun(INavRecordHandle εrec)

     at Microsoft.Dynamics.Nav.Runtime.NavCodeunit.DoRun(DataError errorLevel, NavRecord record)

     at Microsoft.Dynamics.Nav.Runtime.NavCodeunit.RunCodeunit(DataError errorLevel, Int32 objectId, NavRecord record)

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit449.OnRun_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit449.OnRun(INavRecordHandle εrec)

     at Microsoft.Dynamics.Nav.Runtime.NavCodeunit.DoRun(DataError errorLevel, NavRecord record)

     at Microsoft.Dynamics.Nav.Runtime.NavCodeunit.RunCodeunit(DataError errorLevel, Int32 objectId, NavRecord record)

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit448.HandleRequest_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit448.HandleRequest(INavRecordHandle jobQueueEntry)

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit448.OnRun_Scope.OnRun()

     at Filter.InvokeWithFilter(NavMethodScope )

     at Microsoft.Dynamics.Nav.Runtime.NavMethodScope.Run()

     at Microsoft.Dynamics.Nav.BusinessApplication.Codeunit448.OnRun(INavRecordHandle εrec)

     at Microsoft.Dynamics.Nav.Runtime.NavCodeunit.DoRun(DataError errorLevel, NavRecord record)

     at Microsoft.Dynamics.Nav.Runtime.NavCodeunit.RunCodeunit(DataError errorLevel, Int32 objectId, NavRecord record)

     at Microsoft.Dynamics.Nav.Runtime.NavTaskScheduler.TaskRunInfo.RunCodeunit(Int32 codeunitId, NavRecordRef recordRef)

     at Microsoft.Dynamics.Nav.Runtime.NavTaskScheduler.TaskRunInfo.InternalRun()

Source: mscorlib

HResult: -2147024816

</ii>

=============================================================

This error will come at time of system use the TEMP folder for saving any intermedicate result file.

Like - While Generate word layout report, QR Code Generate, Create Zip File, etc. case

Use will face the error on screen like below.


===========================================

Solution:

Delete files from TEMP folder for below users account:

1) Delete temp file in User Machine

2) Delete temp file from NAV Service Acccount User in NAV Application Server.

You can open the TEMP Folder in user machine by click on RUN and type %temp%


Select All and make sure you delete all .tmp files


Done....

Restart NAV in User Machine and try to do the process.
It will solve the issue.

I hope it will help someone in future.
Thank you for reading

Keep Sharing...Keep Growing....

Thursday, August 19, 2021

Optimize the SQL Database Table Performation by Rebuild Query - Dynamics NAV SQL Optimization

 Hello Experts,

Run the below query on SQL DB for optimization

Take the full backup of database before run this query

================================================

DECLARE @sql VARCHAR(MAX), @i INT, @init INT, @table VARCHAR(50), @indextype VARCHAR(50), @indexname VARCHAR(500), @fillfactor INT

--DROP TABLE ##t



IF OBJECT_ID('tempdb..##t') IS NOT NULL

      DROP TABLE ##t

 


SELECT

ROW_NUMBER() OVER(ORDER BY i.fill_factor DESC) as ID

, DB_NAME() AS Database_Name

, sc.name AS Schema_Name

, o.name AS Table_Name

, o.type_desc

, i.name AS Index_Name

, i.type_desc AS Index_Type

, i.fill_factor

, 0 AS [Status]

, CAST('' AS VARCHAR(1000)) AS ErrorMEssage

INTO ##t

FROM sys.indexes i

INNER JOIN sys.objects o ON i.object_id = o.object_id

INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id

WHERE i.name IS NOT NULL

AND o.type = 'U'

ORDER BY i.fill_factor DESC, o.name


SELECT @i = MAX(ID), @init = 1 FROM ##t 


WHILE @i >= @init

BEGIN

SELECT @table = Table_Name, @indexname = Index_Name, @indextype = Index_Type, @fillfactor = fill_factor FROM ##t WHERE ID = @init


IF @indextype = 'CLUSTERED' AND @fillfactor NOT IN (0,100)

SET @sql = 'ALTER INDEX ['+@indexname+'] ON [dbo].['+@table+'] REBUILD PARTITION = ALL WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100)'

ELSE IF @indextype = 'NONCLUSTERED' AND @fillfactor NOT IN (0)

SET @sql = 'ALTER INDEX ['+@indexname+'] ON [dbo].['+@table+'] REBUILD PARTITION = ALL WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)'


BEGIN TRY

PRINT 'Starting index rebuild of number ' + CAST(@init AS VARCHAR(10)) + ' out of ' + CAST(@i AS VARCHAR(10)) + ' Table Name = ' + @table

PRINT @sql

EXEC (@sql)

UPDATE ##t SET [Status] = 1 WHERE ID = @init

END TRY

BEGIN CATCH

UPDATE ##t SET ErrorMEssage = ERROR_MESSAGE() WHERE ID = @init

END CATCH


SET @init += 1

END

=====================================================

This query will take some time depend on size of database



I hope it will help someone.

Keep Sharing...Keep Growing...


====================================================

Perform following Steps to Reduce Table Lock: (Dynamics NAV)

  1. Run above query to rebuild table index (run in night time – we can setup this query to run at every weekend)
  2. Increase the table lock time waiting period (default it is 10 second – we can changes to 30 second) From Database à Alter à Advance à Timeout Duration
  3. Check our custom code – if it is running in long loop for some standard  calculation than commit in code to release table lock
  4. Verify that there is no CONFIRM command used in- between long running code- it is cause the major issue in table lock
  5. We need to identify the Table Name – for that user getting table lock issue (We can run SQL Query  EXEC sp_who2  identify the running sql command and check the query executing cause the table lock)
  6. Re-transfer the full SQL Database to fresh DB – It will reduce database size to 40% and increase performance (this is optional steps we can do if relay require)
  7. Check our long executive code and add command SetCurrentKey to optimize it

Wednesday, August 11, 2021

Download Multiple PDF Files as Compress Zip File in Business Central SaaS Version

Hello Expert,

The goal of this pattern is to enable the users to download multiple files as a zip file instead of downloading one by one.  On the Web Client this is preferred way of delivering multiple files since it is one of the web patterns and we cannot use File Management code unit to place files silently on the machine.

To Enable download of multiple files of report at result single zip archive file we can following sample code.

report 65001 "Download Zip File Sample"
{
    UsageCategory = Administration;
    ApplicationArea = All;
    ProcessingOnly = true;
    Caption = 'Download Zip File';

    trigger OnPreReport()
    begin
        //Init Zip Archive
        Clear(DataCompression);
        DataCompression.CreateZipArchive();

        //Create  PDF File 1 and add in Archive >>
        SIH_lRec.RESET;
        SIH_lRec.SetCurrentKey("Sell-to Customer No.");
        SIH_lRec.SetFilter("No.", '103086');

        Clear(ReportRunTempBlob);
        Clear(Rpt_Out);
        Clear(Rpt_Instr);
        ReportRunTempBlob.CreateOutStream(Rpt_Out);
        SIH_RecRef.GetTable(SIH_lRec);
        REPORT.SaveAs(1306''REPORTFORMAT::Pdf, Rpt_Out, SIH_RecRef);
        ReportRunTempBlob.CREATEINSTREAM(Rpt_Instr);
        DataCompression.AddEntry(Rpt_Instr, 'test 1.pdf');


        //Create  PDF File 2 and add in Archive >>
        SIH_lRec.RESET;
        SIH_lRec.SetCurrentKey("Sell-to Customer No.");
        SIH_lRec.SetFilter("No.", '103087');

        Clear(ReportRunTempBlob);
        Clear(Rpt_Out);
        Clear(Rpt_Instr);
        ReportRunTempBlob.CreateOutStream(Rpt_Out);
        SIH_RecRef.GetTable(SIH_lRec);
        REPORT.SaveAs(1306''REPORTFORMAT::Pdf, Rpt_Out, SIH_RecRef);
        ReportRunTempBlob.CREATEINSTREAM(Rpt_Instr);
        DataCompression.AddEntry(Rpt_Instr, 'test 2.pdf');

        //Create  PDF File 3 and add in Archive >>
        SIH_lRec.RESET;
        SIH_lRec.SetCurrentKey("Sell-to Customer No.");
        SIH_lRec.SetFilter("No.", '103088');

        Clear(ReportRunTempBlob);
        Clear(Rpt_Out);
        Clear(Rpt_Instr);
        ReportRunTempBlob.CreateOutStream(Rpt_Out);
        SIH_RecRef.GetTable(SIH_lRec);
        REPORT.SaveAs(1306''REPORTFORMAT::Pdf, Rpt_Out, SIH_RecRef);
        ReportRunTempBlob.CREATEINSTREAM(Rpt_Instr);
        DataCompression.AddEntry(Rpt_Instr, 'test 3.pdf');

        //Save Zip Archive and Convert in InStream Data
        ZipTempBlob.CreateOutStream(ZipFileOutStream);
        DataCompression.SaveZipArchive(ZipFileOutStream);
        ZipTempBlob.CreateInStream(ZipFileInStream);

        DataCompression.CloseZipArchive();

        ZipFileName := 'Test.Zip';
        DOWNLOADFROMSTREAM(ZipFileInStream, '''''', ZipFileName);
    end;

 var
        DataCompression: Codeunit "Data Compression";
        ReportRunTempBlob: Codeunit "Temp Blob";

        Rpt_Out: OutStream;
        Rpt_Instr: InStream;
        SIH_lRec: Record "Sales Invoice Header";
        SIH_RecRef: RecordRef;
        ZipTempBlob: Codeunit "Temp Blob";
        ZipFileOutStream: OutStream;
        ZipFileInStream: InStream;
        ZipFileName: Text;
}

The above code create 3 pdf files of invoice and at the result we get the single zip file.









I hope it will help someone in future.

Thank you reading this blog.

Keep Sharing....Keep Growing...

Bulk Export Item Pictures in Business Central SaaS version as Zip File

Hello Experts,

Use the below sample code to bulk export items pictures at a tims from item master.

Make sure you have imported the picture in your Item list or for testing purpose just import the pictures for some items and then check

you can use the below code as it is for your test environment.


    Procedure DownloadItemImage()
    var
        MyItem: Record Item;
        TenantMedia: Record "Tenant Media";
        datacompresion: Codeunit 425;
        blobStorage: Codeunit "Temp Blob";
        PicInStream: InStream;
        ZipInStream: InStream;
        ZipOutStream: OutStream;
        ZipFileName: Text;
        ItemCnt: Integer;
        Index: Integer;
        PicCount: Integer;
    begin
        ZipFileName := 'Picture.zip';
        datacompresion.CreateZipArchive();
        MyItem.Reset();
        MyItem.FindSet();
        repeat
            if MyItem.Picture.Count > 0 then begin
                ItemCnt := ItemCnt + 1;
                for Index := 1 to MyItem.Picture.Count do begin
                    PicCount := PicCount + 1;
                    if TenantMedia.Get(MyItem.Picture.Item(Index)) then begin
                        TenantMedia.calcfields(Content);
                        if TenantMedia.Content.HasValue then begin
                            TenantMedia.Content.CreateInStream(PicInstream);
                            datacompresion.AddEntry(PicInStream, MyItem."No." + '.png');
                        end;
                    end;
                end;
            end;
        until MyItem.Next() 0;
        Message('Items processed ' + Format(ItemCnt' Pictures processed ' + Format(PicCount));
        blobStorage.CreateOutStream(ZipOutStream);
        datacompresion.SaveZipArchive(ZipOutStream);
        datacompresion.CloseZipArchive();
        blobStorage.CreateInStream(ZipInStream);
        DownloadFromStream(ZipInStream, 'Download zip file''''', ZipFileName);
    end;

This code simple create the steam of image media and add in zip archive

at last we download the full image file zip at once using DownloadFromSteam command



I hope it will help someone in future.

Thank you reading this blog.

Keep Sharing....Keep Growing...

Tuesday, August 4, 2020

Business Central --> Sent Email with Attachment of Report (using report selection of RDLC , Word , Customer Layout anything)

Hello Friends,

You can create customized email sending functionality in business central and attach standard document report from report selection with RDLC, Word and any custom layout

See the following example of sending Posted Sales Invoice email to client.

    procedure EmailSalesInvoice_gFnc(SalesInvoiceHeader_iRec: 
Record "Sales Invoice Header")Boolean
    var

        Customer: Record Customer;
        CompanyInfo: Record "Company Information";
        EmailInStream: InStream;
        EmailOutStream: OutStream;
        tempBlob: Codeunit "Temp Blob";
        receipent: List of [Text];
        ShipmentNo: Code[20];
        SalesShipmentHeader: Record "Sales Shipment Header";
    begin
        Clear(Customer);
        Customer.Get(SalesInvoiceHeader_iRec."Sell-to Customer No.");
        if Customer."E-Mail" = '' then
            exit;

        Clear(CompanyInfo);
        CompanyInfo.Get();

        SMTPMailSetup.Get();
        SMTPMailSetup.TestField("User ID");

        Clear(receipent);
        receipent.Add(Customer."E-Mail");

        Clear(SMTPMail);
        SMTPMail.CreateMessage(CompanyInfo.Name, SMTPMailSetup."User ID", receipent,
 'Sales Invoice - ' + SalesInvoiceHeader_iRec."No.", '', true);

        SMTPMail.AppendBody('<html>');
        SMTPMail.AppendBody('<head>');
        SMTPMail.AppendBody('<meta charset="utf-8">');
        SMTPMail.AppendBody('<title>A simple, clean, and responsive HTML
 invoice template</title>');

        SMTPMail.AppendBody('<style>');
        SMTPMail.AppendBody('.invoice-box {');
        SMTPMail.AppendBody('max-width: 800px;');
        SMTPMail.AppendBody('margin: auto;');
        SMTPMail.AppendBody('padding: 30px;');
        SMTPMail.AppendBody('border: 1px solid #eee;');
        SMTPMail.AppendBody('box-shadow: 0 0 10px rgba(0, 0, 0, .15);');
        SMTPMail.AppendBody('font-size: 16px;');
        SMTPMail.AppendBody('line-height: 24px;');
        SMTPMail.AppendBody('font-family: ''Helvetica Neue''''Helvetica'',
 Helvetica, Arial, sans-serif;');
        SMTPMail.AppendBody('color: #555;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table {');
        SMTPMail.AppendBody('width: 100%;');
        SMTPMail.AppendBody('line-height: inherit;');
        SMTPMail.AppendBody('text-align: left;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table td {');
        SMTPMail.AppendBody('padding: 5px;');
        SMTPMail.AppendBody('vertical-align: top;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr td:nth-child(2) {');
        SMTPMail.AppendBody('text-align: right;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.top table td {');
        SMTPMail.AppendBody('padding-bottom: 20px;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.top table td.title {');
        SMTPMail.AppendBody('font-size: 45px;');
        SMTPMail.AppendBody('line-height: 45px;');
        SMTPMail.AppendBody('color: #333;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.information table td {');
        SMTPMail.AppendBody('padding-bottom: 40px;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.heading td {');
        SMTPMail.AppendBody('background: #eee;');
        SMTPMail.AppendBody('border-bottom: 1px solid #ddd;');
        SMTPMail.AppendBody('font-weight: bold;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.details td {');
        SMTPMail.AppendBody('padding-bottom: 20px;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.item td{');
        SMTPMail.AppendBody('border-bottom: 1px solid #eee;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.item.last td {');
        SMTPMail.AppendBody('border-bottom: none;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.total td:nth-child(2) {');
        SMTPMail.AppendBody('border-top: 2px solid #eee;');
        SMTPMail.AppendBody('font-weight: bold;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('@media only screen and (max-width: 600px) {');
        SMTPMail.AppendBody('.invoice-box table tr.top table td {');
        SMTPMail.AppendBody('width: 100%;');
        SMTPMail.AppendBody('display: block;');
        SMTPMail.AppendBody('text-align: center;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.invoice-box table tr.information table td {');
        SMTPMail.AppendBody('width: 100%;');
        SMTPMail.AppendBody('display: block;');
        SMTPMail.AppendBody('text-align: center;');
        SMTPMail.AppendBody('}');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('/** RTL **/');
        SMTPMail.AppendBody('.rtl {');
        SMTPMail.AppendBody('direction: rtl;');
        SMTPMail.AppendBody('font-family: Tahoma, ''Helvetica Neue''''Helvetica'',
 Helvetica, Arial, sans-serif;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.rtl table {');
        SMTPMail.AppendBody('text-align: right;');
        SMTPMail.AppendBody('}');

        SMTPMail.AppendBody('.rtl table tr td:nth-child(2) {');
        SMTPMail.AppendBody('text-align: left;');
        SMTPMail.AppendBody('}');
        SMTPMail.AppendBody('</style>');
        SMTPMail.AppendBody('</head>');

        SMTPMail.AppendBody('<body>');
        SMTPMail.AppendBody('<div class="invoice-box">');
        SMTPMail.AppendBody('<table cellpadding="0" cellspacing="0">');
        SMTPMail.AppendBody('<tr class="top">');
        SMTPMail.AppendBody('<td colspan="2">');
        SMTPMail.AppendBody('<table>');
        SMTPMail.AppendBody('<tr>');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td class="title">');
        SMTPMail.AppendBody('<b><font size = "5">Sales Invoice</font></b><br>');
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');
        SMTPMail.AppendBody('</table>');
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="information">');
        SMTPMail.AppendBody('<td colspan="2">');
        SMTPMail.AppendBody('<table>');
        SMTPMail.AppendBody('<tr>');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody(CompanyInfo.Name + '<br>');
        SMTPMail.AppendBody(CompanyInfo.Address + '<br>');
        SMTPMail.AppendBody(CompanyInfo."Address 2" + '<br>');
        SMTPMail.AppendBody(CompanyInfo.City + '<br>');
        SMTPMail.AppendBody(CompanyInfo."Post Code" + '<br>');
        SMTPMail.AppendBody(CompanyInfo."Phone No." + '<br>');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody(CompanyInfo."Contact Person" + '<br>');
        SMTPMail.AppendBody(CompanyInfo."E-Mail" + '<br>');
        SMTPMail.AppendBody('Created Date:' + Format(CurrentDateTime()) '<br>');
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');
        SMTPMail.AppendBody('</table>');
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="heading">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('Account No.');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody(Customer."No.");
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="details">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('Name');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody(Customer.Name);
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="heading">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('Details:');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('');
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="item">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('Document No.');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody(SalesInvoiceHeader_iRec."No.");
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="item">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('Order Date');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody(format(SalesInvoiceHeader_iRec."Order Date"));
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="item last">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('<tr class="heading">');
        SMTPMail.AppendBody('<td>');
        SMTPMail.AppendBody('Total');
        SMTPMail.AppendBody('</td>');

        SMTPMail.AppendBody('<td>');
        SalesInvoiceHeader_iRec.CalcFields("Amount Including VAT");
        SMTPMail.AppendBody(format(SalesInvoiceHeader_iRec."Amount Including VAT"));
        SMTPMail.AppendBody('</td>');
        SMTPMail.AppendBody('</tr>');

        SMTPMail.AppendBody('</table>');
        SMTPMail.AppendBody('</div>');
        SMTPMail.AppendBody('</body>');
        SMTPMail.AppendBody('</html>');
        SMTPMail.AppendBody('<br><br>Kindly go through attached Document for more 
details.');
        SMTPMail.AppendBody('<br><br>Regards,<br><b>');
        SMTPMail.AppendBody(CompanyInfo."Contact Person" + '<br>');
        SMTPMail.AppendBody(CompanyInfo.Name + '<br>');
        SMTPMail.AppendBody(CompanyInfo.Address + '<br>');
        SMTPMail.AppendBody(CompanyInfo."Address 2" + '<br>');
        SMTPMail.AppendBody(CompanyInfo.City + ',');
        SMTPMail.AppendBody(CompanyInfo."Post Code" + '<br>');
        SMTPMail.AppendBody(CompanyInfo."Phone No." + '<br>');
        SMTPMail.AppendBody(CompanyInfo."E-Mail" + '<br></b>');


        PostedInvoice(SalesInvoiceHeader_iRec);
       


        if SMTPMail.Send() then begin
            exit(true);
        end;
    end;

    procedure PostedInvoice(var SalesInvHeader_iRec: Record "Sales Invoice Header")
    var
        TempBlob_lCdu: Codeunit "Temp Blob";
        Out: OutStream;
        Instr: InStream;
        RecRef: RecordRef;
        FileManagement_lCdu: Codeunit "File Management";
        ReportSelection_lRec: Record "Report Selections";
        ReportID: Integer;
        SalesInvHeader_lRec: Record "Sales Invoice Header";
        MyPath: Text;
        ReprotLayoutSelection_lRec: Record "Report Layout Selection";
        CustomReportLayout_lRec: Record "Custom Report Layout";
    begin
        SalesInvHeader_lRec.Reset;
        SalesInvHeader_lRec.SetFilter("No.", SalesInvHeader_iRec."No.");
        SalesInvHeader_lRec.FindFirst;

        ReportSelection_lRec.reset;
        ReportSelection_lRec.SETRANGE(Usage, ReportSelection_lRec.Usage::"S.Invoice");
        IF ReportSelection_lRec.FindFirst then begin
            ReportID := ReportSelection_lRec."Report ID";
        end;

        IF ReportID > 0 then begin
            ReprotLayoutSelection_lRec.Reset;
            ReprotLayoutSelection_lRec.SetRange("Report ID", ReportID);
            if ReprotLayoutSelection_lRec.FindFirst then begin
                case ReprotLayoutSelection_lRec.Type of
                    ReprotLayoutSelection_lRec.Type::"RDLC (built-in)":
                        begin
                            TempBlob_lCdu.CreateOutStream(Out);
                            RecRef.GetTable(SalesInvHeader_lRec);
                            REPORT.SaveAs(ReportID, ''REPORTFORMAT::Pdf, Out, RecRef);
                            TempBlob_lCdu.CREATEINSTREAM(Instr);
                            MyPath := STRSUBSTNO('%2_%1.pdf'
SalesInvHeader_lRec."No.", 'Posted Sales Invoice');
                            SMTPMail.AddAttachmentStream(Instr, MyPath);
                        end;
                    ReprotLayoutSelection_lRec.Type::"Word (built-in)":
                        begin
                            TempBlob_lCdu.CreateOutStream(Out);
                            RecRef.GetTable(SalesInvHeader_lRec);
                            REPORT.SaveAs(ReportID, ''REPORTFORMAT::Word, Out, 
RecRef);
                            TempBlob_lCdu.CREATEINSTREAM(Instr);
                            MyPath := STRSUBSTNO('%2_%1.docx'
SalesInvHeader_lRec."No.", 'Posted Sales Invoice');
                            SMTPMail.AddAttachmentStream(Instr, MyPath);
                        end;
                    ReprotLayoutSelection_lRec.Type::"Custom Layout":
                        begin
                            ReprotLayoutSelection_lRec.CalcFields("Report Layout Description");
                            CustomReportLayout_lRec.Reset();
                            CustomReportLayout_lRec.SetRange(Code,
 ReprotLayoutSelection_lRec."Custom Report Layout Code");
                            if CustomReportLayout_lRec.FindFirst then begin
                                case CustomReportLayout_lRec.Type OF
                                    CustomReportLayout_lRec.Type::RDLC:
                                        begin
                                            TempBlob_lCdu.CreateOutStream(Out);
                                            RecRef.GetTable(SalesInvHeader_lRec);
                                            REPORT.SaveAs(ReportID, ''
REPORTFORMAT::Pdf, Out, RecRef);
                                            TempBlob_lCdu.CREATEINSTREAM(Instr);
                                            MyPath := STRSUBSTNO('%2_%1.pdf',
 SalesInvHeader_lRec."No.", 'Posted Sales Invoice');
                                            SMTPMail.AddAttachmentStream(Instr, MyPath);
                                        end;
                                    CustomReportLayout_lRec.Type::Word:
                                        begin
                                            TempBlob_lCdu.CreateOutStream(Out);
                                            RecRef.GetTable(SalesInvHeader_lRec);
                                            REPORT.SaveAs(ReportID, ''REPORTFORMAT::Word, Out, RecRef);
                                            TempBlob_lCdu.CREATEINSTREAM(Instr);
                                            MyPath := STRSUBSTNO('%2_%1.docx',
 SalesInvHeader_lRec."No.", 'Posted Sales Invoice');
                                            SMTPMail.AddAttachmentStream(Instr, MyPath);
                                        end
                                end
                            END
                        end;
                end;
            END ELSE begin
                TempBlob_lCdu.CreateOutStream(Out);
                RecRef.GetTable(SalesInvHeader_lRec);
                REPORT.SaveAs(ReportID, ''REPORTFORMAT::Pdf, Out, RecRef);
                TempBlob_lCdu.CREATEINSTREAM(Instr);
                MyPath := STRSUBSTNO('%2_%1.pdf'
SalesInvHeader_lRec."No.", 'Posted Sales Invoice');
                SMTPMail.AddAttachmentStream(Instr, MyPath);
            end;

        end

    end;




Sample output of this email.




















I hope this help someone for email functionality development.

Please write the comment for any query

Keep Sharing....Keep growing.....