top of page

Let's catch the E-Mail Attachments

Have you ever tried to get the attachments of an E-Mail which have been sent inside of Business Central?

The Main Question is: Do you want to store all Sales Quotes which have been sent to your customers/partners? Your employees are sending many mails with different versions of Quotes and a centralized storage would be nice?

Our goal is to download or even upload the body of our mail and all attachments to Sharepoint Online by using our Beyond Cloud Connector (which can be extended by any developer).

Let's step back and understand the implementation:

I am using Business Central v21 and Codeunit "Mail Management" is full of Mailing procedures to make the "Big Thing" run.

For our scenario there is an Event, which is very helpful:

OnSendViaEmailModuleOnAfterEmailSend(Message, TempEmailItem, MailSent, Cancelled, HideEmailSendingError);

Message is declared as Codeunit "Email Message" and holds the Body of your Mail and all Attachments.

GetBody() returns a String, so we need to use an InStream to download or upload it later:

if Message.GetBody() <> '' then begin
  Attachment.CreateOutStream(OutStr, TextEncoding::UTF8); 
  Attachment.CreateInStream(BodyInStream, TextEncoding::UTF8);
  UploadToBeyondCloudConnectorOrDownload(BodyInStream, 'Mail.html', CloudStorageSalesHeader, SalesHeader);

Let's iterate also through all Attachments:

if Message.Attachments_First() then
    UploadToBeyondCloudConnectorOrDownload(AttachmentStream, Message.Attachments_GetName(), CloudStorageSalesHeader, SalesHeader);
  until Message.Attachments_Next() = 0;

TempEmailItem is declared as Record "Email Item"and is aware of some background information. Like the the Source Tables, System IDs and Documents:

TempEmailItem.GetSourceDocuments(SourceTableIDs, SourceIDs, SourceRelationTypes);

We need to check if this Mail has been sent from our Sales Quote, right?

By returning a List, we need to get the first entry:

if SourceTableIDs.Get(1) <> Database::"Sales Header" then

if SourceRelationTypes.Get(1) <> Enum::"Sales Document Type"::Quote.AsInteger() then

Also if we can still get that Sales Header:

if not SalesHeader.GetBySystemId(SourceIDs.Get(1)) then

And then let's download or upload our InStream:

local procedure UploadToBeyondCloudConnectorOrDownload

The User should answer that question by using a StrMenu:

local procedure UploadToBeyondCloudConnectorOrDownload(var AttachmentInStream: InStream; Filename: Text; CloudStorageSalesHeader: Record "BYD Cloud Storage"; SalesHeader: Record "Sales Header")

case selected of
    OK := DownloadFromStream(AttachmentInStream, 'Download', '', '', NewFileName);
      CloudStorageMgt.PerformChunkedFileUpload(AttachmentInStream, CloudStorageSalesHeader, SalesHeader.RecordId(), SalesHeader.TableCaption(), CloudStorageMgt.GetPrimaryKeyText(SalesHeader.RecordId()), NewFileName, FileManagement.GetFileNameMimeType(NewFileName));

And let's add a timestamp to all attachments which will work as a "Version":

FileManagement: Codeunit "File Management";
TypeHelper: Codeunit "Type Helper";

TodayFormatted := TypeHelper.GetFormattedCurrentDateTimeInUserTimeZone(DateTimeFormatLbl);
NewFileName := StrSubstNo(FileNameLbl, FileManagement.GetFileNameWithoutExtension(FileName), TodayFormatted, FileManagement.GetExtension(FileName));

Let's give it a try and see how it works:

Happy coding :)!

21 views0 comments

Recent Posts

See All


bottom of page