We may get a requirement in D365FO , to Automate Email Functionality with Additional attachment.

I had a similar requirement to  send SSRS report Sales Invoice as PDF to the customer along with Product Safety sheet/Compliance Document in the same mail as attachment.

1.  I have a created a batch job , which will read all the customer Invoice and send that invoice as PDF to the customer as PDF.

Below code is useful , 

class MylabelsSalesInvoiceSendMailBatch
{
SysEmailItemId nextEmailItemId; //Global variable
SysEmailTable sysEmailTable;
SysEmailMessageTable sysEmailMessageTable;
SysEmailContents sysEmailContents;
SysOutgoingEmailTable outgoingEmailTable;
SysOutgoingEmailData outgoingEmailData;
Filename filename, FileExtension =".pdf";
int DataID = 1;
Email email= '';

public void updateCustInvoicejournal(RecId _recid )
{
CustInvoiceJour custInvoiceJour;

select forupdate custInvoiceJour where custInvoiceJour.RecId == _recid;
if(custInvoiceJour.RecId)
{
ttsbegin;
custInvoiceJour.MylabelsSentMail = NoYes::Yes;
custInvoiceJour.doUpdate();
ttscommit;

}

}

Public void SendMail()
{
SysEmailDistributor SysEmailDistributor = new SysEmailDistributor();
SysEmailDistributor.run();
}

// Attachment Loop Of Binary
public void StreamFile(DocuRef docuref,int _DataId)
{
container binData2;
Binary binaryData2;
DocuAction docuAction;

docuAction = docuRef.docuAction();
System.IO.Stream stream = docuAction.getStream(docuRef);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
stream.CopyTo(memoryStream);
stream = DocumentManagement::getAttachmentStream(docuRef);
binaryData2 = Binary::constructFromMemoryStream(memoryStream);

if(binaryData2)
{
binData2 = binaryData2.getContainer();

}

this.EamilAttachment("Alert","en-AU",email,binData2,docuref.Name,_DataId);

}

//Insert Email Header Table ++
public void EmailHeader( SysEmailId _emailId,
LanguageId _language,
SysEmailAddress _emailAddr
,container _binData,str _fileName, Str _SalesID )
{

select sysEmailTable
join sysEmailMessageTable
where sysEmailMessageTable.EmailId==sysEmailTable.EmailId
&& sysEmailMessageTable.EmailId== _emailId
&& sysEmailMessageTable.LanguageId==_language;

if(sysEmailTable.RecId>0)
{
nextEmailItemId = EventInbox::nextEventId();

filename =strFmt("Sales Invoice - %1",_SalesID);

outgoingEmailTable.clear();
outgoingEmailTable.Origin=sysEmailTable.Description;
outgoingEmailTable.EmailItemId = nextEmailItemId;
outgoingEmailTable.IsSystemEmail = NoYes::Yes;
outgoingEmailTable.Sender = sysEmailTable.SenderAddr;
outgoingEmailTable.SenderName = sysEmailTable.SenderName;
outgoingEmailTable.Recipient = _emailAddr;
outgoingEmailTable.Subject = "@Mylabels:MylabelsSalesInvoice";
outgoingEmailTable.Priority = eMailPriority::High;
outgoingEmailTable.WithRetries = NoYes::NO;
outgoingEmailTable.RetryNum = 0;
outgoingEmailTable.UserId = curUserId();
outgoingEmailTable.Status = SysEmailStatus::Unsent;
outgoingEmailTable.Message = strFmt("@Mylabels:MylabelsEmailBody",_SalesID) ;
outgoingEmailTable.LatestStatusChangeDateTime = DateTimeUtil::getSystemDateTime();
outgoingEmailTable.TemplateId= _emailId;
outgoingEmailTable.insert();

if(conLen(_binData)>0)
{
outgoingEmailData.clear();

outgoingEmailData.EmailItemId = nextEmailItemId;
outgoingEmailData.DataId = 1;
outgoingEmailData.EmailDataType = SysEmailDataType::Attachment;
outgoingEmailData.Data = _binData;
outgoingEmailData.FileName = filename;
outgoingEmailData.FileExtension =FileExtension;

outgoingEmailData.insert();

}

}
}

//Insert Email Header Table --

//Insert Email Attachments
public void EamilAttachment( SysEmailId _emailId,
LanguageId _language,
SysEmailAddress _emailAddr
,container _binData,str _fileName,Int _Dataid)
{
if(conLen(_binData)>0)
{
outgoingEmailData.clear();
outgoingEmailData.EmailItemId = nextEmailItemId;
outgoingEmailData.DataId = _Dataid;
outgoingEmailData.EmailDataType = SysEmailDataType::Attachment;
outgoingEmailData.Data = _binData;
outgoingEmailData.FileName = _filename;
outgoingEmailData.FileExtension =FileExtension;

outgoingEmailData.insert();
}

}

[SysEntryPointAttribute(false)]
public void processRecords()
{
CustInvoiceJour custinvjour;
int counter = 0;
date dT;
utcDateTime utcDT;
int timeOfday;
dT = today();//get today

timeOfday = str2Time("00:00");//prepare time
utcDT = datetimeutil::newDateTime(dT,timeOfday);


try
{
//Actual operation performed
while select custinvjour where
custinvjour.CreatedDateTime >= utcDT

{
Filename Attachmentname = "SalesInvoice.pdf";
SrsReportRunController controller = new SrsReportRunController();
SalesInvoiceContract contract = new SalesInvoiceContract();
SRSReportExecutionInfo executionInfo = new SRSReportExecutionInfo();
System.Byte[] reportBytes = new System.Byte[0]();
SRSReportRunService srsReportRunService = new SrsReportRunService();
SRSPrintDestinationSettings settings;
Array arrayFiles;
SRSProxy srsProxy;
Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] parameterValueArray;
Map reportParametersMap;
Args args;
SalesInvoiceContract salesInvoiceContract;
DocuRef docuref;
SalesLine salesline;
PdsMRCDocument pdsMRCDocument;
ItemIdSmall itemid = '';
CustTable custtable;

args = new Args();
args.record(custinvjour);
custtable = CustTable::find(custinvjour.OrderAccount);
email = custtable.email();
if (email!= '')
{
contract.parmRecordId(custinvjour.RecId);
// Provide details to controller and add contract
controller.parmArgs();
controller.parmReportName(ssrsReportStr(MylabelsSalesInvoice, Report));
controller.parmShowDialog(false);
controller.parmLoadFromSysLastValue(false);
controller.parmReportContract().parmRdpContract(contract);
// Provide printer settings
settings = controller.parmReportContract().parmPrintSettings();
settings.printMediumType(SRSPrintMediumType::File);
settings.fileName(Attachmentname);
settings.fileFormat(SRSReportFileFormat::PDF);

// Below is a part of code responsible for rendering the report
controller.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration());
controller.parmReportContract().parmReportExecutionInfo(executionInfo);

srsReportRunService.getReportDataContract(controller.parmreportcontract().parmReportName());
srsReportRunService.preRunReport(controller.parmreportcontract());
reportParametersMap = srsReportRunService.createParamMapFromContract(controller.parmReportContract());
parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap);

srsProxy = SRSProxy::constructWithConfiguration(controller.parmReportContract().parmReportServerConfig());
// Actual rendering to byte array
reportBytes = srsproxy.renderReportToByteArray(controller.parmreportcontract().parmreportpath(),
parameterValueArray,
settings.fileFormat(),
settings.deviceinfo());
//Report Binary Code
Binary binaryData;
container binData;
System.IO.MemoryStream mstream = new System.IO.MemoryStream(reportBytes);
binaryData = Binary::constructFromMemoryStream(mstream);
if(binaryData)
{
binData = binaryData.getContainer();

}

this.EmailHeader("Alert","en-AU",email,binData,"SalesOrderInvoice",custinvjour.SalesId);

while select salesline where
salesline.SalesId == custinvjour.SalesId
if (salesline.ItemId != itemid)
{
select * from pdsMRCDocument where pdsMRCDocument.ItemId == salesline.ItemId;

while select docuref
where docuref.RefRecId == pdsMRCDocument.RecId
&& docuref.RefTableId == tableName2Id('PdsMRCDocument')
{
itemid = salesline.ItemId;
DataID += 1 ;
this.StreamFile(docuref,DataID);
}
}

Info (strfmt("@Mylabels:MylabelsSuccessMessage",custinvjour.OrderAccount,custinvjour.SalesId));

}
else
{
Info (strfmt("@Mylabels:MylabelsBalnkEmailID",custinvjour.OrderAccount,custinvjour.SalesId));

}
counter += 1;
this.SendMail();
this.updateCustInvoicejournal( custinvjour.RecId);
Info(strFmt("@Mylabels:MylabelsEmailCount",custinvjour.SalesId));
}

}

catch (Exception::Deadlock)
{
retry;
}



}

}