D365 FO Sending Email with SSRS reports as attachment using X++
Public class EmailCustAccountStmnt
{
public void run(CustTable _custTable)
{
SysOperationQueryDataContractInfo sysOperationQueryDataContractInfo;
SrsReportRunController reportRunController;
CustTransListContract custTransListContract;
SRSReportExecutionInfo reportExecutionInfo;
SRSPrintDestinationSettings printDestinationSettings;
SRSReportRunService srsReportRunService;
SRSProxy srsProxy;
QueryBuildRange qbrCustAccount;
QueryBuildDataSource queryBuildDataSource;
Object dataContractInfoObject;
Map reportParametersMap;
Map mapCustAccount;
MapEnumerator mapEnumerator;
Array arrayFiles;
System.Byte[] reportBytes;
Filename fileName;
Args args;
System.IO.MemoryStream memoryStream;
System.IO.MemoryStream fileStream;
CustParameters custParameters;
Email toEmail;
Map templateTokens;
str emailSenderName;
str emailSenderAddr;
str emailSubject;
str emailBody;
Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] parameterValueArray;
#define.Subject("Subject")
#define.CustAccount("CustAccount")
#define.EmailDate("Date");
custParameters = CustParameters::find();
reportRunController = new SrsReportRunController();
custTransListContract = new CustTransListContract();
reportExecutionInfo = new SRSReportExecutionInfo();
srsReportRunService = new SrsReportRunService();
reportBytes = new System.Byte[0]();
args = new Args();
templateTokens = new Map(Types::String, Types::String);
var messageBuilder = new SysMailerMessageBuilder();
custTransListContract.parmNewPage(NoYes::Yes);
fileName = strFmt("CustomerAccountStatement_%1.pdf", _custTable.AccountNum);
reportRunController.parmArgs(args);
reportRunController.parmReportName(ssrsReportStr(CustTransList, Report));
reportRunController.parmShowDialog(false);
reportRunController.parmLoadFromSysLastValue(false);
reportRunController.parmReportContract().parmRdpContract(custTransListContract);
// Modify query
mapCustAccount = reportRunController.getDataContractInfoObjects();
mapEnumerator = mapCustAccount.getEnumerator();
while (mapEnumerator.moveNext())
{
dataContractInfoObject = mapEnumerator.currentValue();
if (dataContractInfoObject is SysOperationQueryDataContractInfo)
{
sysOperationQueryDataContractInfo = dataContractInfoObject;
queryBuildDataSource = SysQuery::findOrCreateDataSource(sysOperationQueryDataContractInfo.parmQuery()
, tableNum(CustTable));
qbrCustAccount = SysQuery::findOrCreateRange(queryBuildDataSource, fieldNum(CustTable, AccountNum));
qbrCustAccount.value(_custTable.AccountNum);
}
}
printDestinationSettings = reportRunController.parmReportContract().parmPrintSettings();
printDestinationSettings.printMediumType(SRSPrintMediumType::File);
printDestinationSettings.fileName(fileName);
printDestinationSettings.fileFormat(SRSReportFileFormat::PDF);
reportRunController.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration());
reportRunController.parmReportContract().parmReportExecutionInfo(reportExecutionInfo);
srsReportRunService.getReportDataContract(reportRunController.parmreportcontract().parmReportName());
srsReportRunService.preRunReport(reportRunController.parmreportcontract());
reportParametersMap = srsReportRunService.createParamMapFromContract(reportRunController.parmReportContract());
parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap);
srsProxy = SRSProxy::constructWithConfiguration(reportRunController.parmReportContract().parmReportServerConfig());
reportBytes = srsproxy.renderReportToByteArray(reportRunController.parmreportcontract().parmreportpath()
, parameterValueArray
, printDestinationSettings.fileFormat()
, printDestinationSettings.deviceinfo());
memoryStream = new System.IO.MemoryStream(reportBytes);
memoryStream.Position = 0;
fileStream = memoryStream;
toEmail = this.getCustEmail(_custTable.AccountNum);
if (custParameters.EmailId && toEmail)
{
templateTokens.insert(#CustAccount, _custTable.name());
templateTokens.insert(#EmailDate, date2StrXpp(systemDateGet()));
[emailSubject, emailBody, emailSenderAddr, emailSenderName] =
EmailCustAccountStmnt::getEmailTemplate(custParameters.EmailId, _custTable.languageId());
messageBuilder.addTo(this.getCustEmail(_custTable.AccountNum))
.setSubject(strFmt("Customer account statement for %1", _custTable.AccountNum))
.setBody(SysEmailMessage::stringExpand(emailBody, SysEmailTable::htmlEncodeParameters(templateTokens)))
.addCC("");
messageBuilder.setFrom(emailSenderAddr, emailSenderName);
messageBuilder.addAttachment(fileStream, fileName);
SysMailerFactory::sendNonInteractive(messageBuilder.getMessage());
info(strFmt("Email sent successfully to the customer account %1", _custTable.AccountNum));
}
else
{
info(strFmt("There is no email id mappiing for this customer %1 or check the Email template setup.", _custTable.AccountNum));
}
}
protected static container getEmailTemplate(SysEmailId _emailId, LanguageId _languageId)
{
var messageTable = SysEmailMessageTable::find(_emailId, _languageId);
var emailTable = SysEmailTable::find(_emailId);
if (!messageTable && emailTable)
{
// Try to find the email message using the default language from the email parameters
messageTable = SysEmailMessageTable::find(_emailId, emailTable.DefaultLanguage);
}
if (messageTable)
{
return [messageTable.Subject, messageTable.Mail, emailTable.SenderAddr, emailTable.SenderName];
}
else
{
warning("@SYS135886"); // Let the user know we didn't find a template
return ['', '', emailTable.SenderAddr, emailTable.SenderName];
}
}
public Email getCustEmail(CustAccount _custAccount)
{
CustTable custTable;
DirPartyLocation dirPartyLocation;
LogisticsLocation logisticsLocation;
LogisticsElectronicAddress logisticsElectronicAddress;
custTable = CustTable::find(_custAccount);
select firstonly Location, Party from dirPartyLocation
where dirPartyLocation.Party == custTable.Party
join RecId from logisticsLocation
where logisticsLocation.RecId == dirPartyLocation.Location
join Locator from logisticsElectronicAddress
where logisticsElectronicAddress.Location == logisticsLocation.RecId
&& logisticsElectronicAddress.Type == LogisticsElectronicAddressMethodType::Email
&& logisticsElectronicAddress.IsPrimary == NoYes::Yes;
return logisticsElectronicAddress.Locator;
}
Published on:
Learn moreRelated posts
New Approved Customer List mapping for Items in Dynamics 365 Finance and operations
Take control of your sales process with the latest feature in Microsoft Dynamics 365 Finance – the Approved Customer List! This powerful new f...
Part-9: Connect and Query Dynamics 365 Finance and operations data with Copilot studio
In this video, we kick off an exciting new series focused on extending Copilot Studio capabilities by connecting it to real enterprise data! �...
How to Create Deep Links to D365 F&O Records with Dataverse Virtual Tables
It is a common requirement for SaaS platform that exposes form over data to be able to share a secure link (a.k.a. Deep Link) to access a give...
Simplifying License Management for Dynamics 365 Finance and Operations: Improved User License Validation
Starting April 30th, Dynamics 365 administrators will gain access to new license usage reporting tools, centralizing user license management. ...
D365FO Integration: Import Sales Orders from an External Web Application
Learn how to implement robust and efficient process to import complex documents into Dynamics 365 Finance and Operations from external Web ser...
Practical Hints for Technical Management of D365FO Go-Live
In this post, I share practical insights from my experience managing the technical side of Go-Live for D365FO projects, focusing on key activi...
D365FO Integration: Event-Based Exports to External Web Services
How to implement robust, efficient integrations between Dynamics 365 Finance and Operations and external Web Services. This post covers design...