Sending Email with attached Excel file in D365 FO and Ax 2012 using SysMailerMessageBuilder Framework X++
Moving on from Ax dynamics 2012 to D365, there are multiple frameworks that has been added on by Microsoft to use its basic functionality.In the case of email sending functionality in Dynamics Ax we probably prefer SMTP in 2012 that is to add on the code and bypassing its required parameter.While in D365 we could use SysMailerMessageBuilder framework to perform our work that is sending email to multiple recipient too.
recipients
*The file data will be from financial dimension view and it will be distributed into
three worksheets that is D1,D2 and D4_5 according to conditions
*Data of Data Entity of D4 & D5 will be inserted into same worksheet that is D4_5
public class IRC_FinancialDimExportService extends SysOperationServiceBase
{
public const str T1 = 'T1-D1';
public const str T3 = 'T3-D3';
public const str T5 = 'T5-D4';
public const str D4 = 'D04Location';
public const str D5 = 'D05Entity_Code';
// used for validating email
public const Str MatchEmailPattern =
@"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
+ @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
+ @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
+ @"([\w-]+\.)+[a-zA-Z]{2,4})$";
// setEmailParm is used when we want to send
// email to multiple recipients
public SysMailerMessageBuilder setEmailParm(IRC_FinancialDimExportContract _contract)
{
container con = str2con(_contract.parmEmails());
SysMailerMessageBuilder mailer = new SysMailerMessageBuilder();
UserInfo user = xUserInfo::find();
SysUserInfo sysUse = SysUserInfo::find(user.id);
str sender = sysUser.getSendAsEmail(user);
IRC_RecipientEmail recipient;
for(int i=1;i<=conLen(con);i++)
{
if(this.validateEmail(conPeek(con,i)) == true)
{
recipient = conPeek(con,i);
mailer.addTo(recipient);
}
else
{
Global::warning(strFmt("%1 , This email is incorrect",conPeek(con,i)));
}
}
mailer.setSubject("Financial Details");
mailer.setFrom(sender);
mailer.setBody("PFA");
return mailer;
}
//emailSender has been used to attach Excel file
//through stream
public void emailSender(IRC_FinancialDimExportContract _contract)
{
try
{
SysMailerMessageBuilder objMailer = new SysMailerMessageBuilder();
SysMailerSMTP smtp = new SysMailerSMTP();
container fileTitle = ['T1-D1','D01Project_Code','T3- D3','D03Program_Area','T5-D4','D04Location'];
str fileName;
objMailer = this.setEmailParm(_contract);
System.IO.MemoryStream memoryStream;
for(int iterator=1 ;iterator <=conLen(fileTitle) ;iterator++)
{
memoryStream = this.csvFileExporter(conPeek(fileTitle,iterator),conPeek(fileTitle,iterator+1));
memoryStream.Seek(0, System.IO.SeekOrigin::Begin);
fileName = conPeek(fileTitle,iterator)+'.csv';
//The below line used to attach excel file to email.
objMailer.addAttachment(memoryStream, fileName, "application/csv");
//For PDF we use objMailer.addAttachment(memoryStream, fileName, "application/pdf");
memoryStream.Flush();
iterator++;
}
try
{
smtp.sendNonInteractive(objMailer.getMessage());
Global::info("Email has been sent sucessfully");
}
catch(Exception::CLRError)
{
error(CLRInterop::getLastException().toString());
}
}
catch(Exception::CLRError)
{
error(CLRInterop::getLastException().toString());
}
}
//Used for validating email's structure
private boolean validateEmail(Email _email)
{
boolean ret = true;
Boolean VerifEmails;
System.Text.RegularExpressions.Match emailMatch;
if(_email != '')
{
new InteropPermission(InteropKind::ClrInterop).assert();
emailMatch = System.Text.RegularExpressions.Regex::Match(_email,MatchEmailPattern);
VerifEmails = emailMatch.get_Success();
ret = VerifEmails;
CodeAccessPermission::revertAssert();
}
return ret;
}
// The pupose of this function is to write into
//excel file and create it
public System.IO.MemoryStream csvFileExporter(Filename fName , Name _dimAttribute)
{
System.IO.MemoryStream memoryStreamer = new System.IO.MemoryStream();
commaStreamIo iO;
boolean isFirstRow = true;
Name tempDimAttribute;
str financialDesc,tempStr,fPrefix,code;
container conDim,conDimTemp;
iO = commaStreamIo::constructForWrite();
container header = ["Type","Code","Description"];
iO.writeExp(header);
if(_dimAttribute == D4)
{
tempDimAttribute = D5;
}
conDim = this.financialDimDetails(_dimAttribute);
for(int iterator=1 ;iterator <=conLen(conDim) ;iterator++)
{
tempStr = isFirstRow ? fName : '';
fPrefix = fName==T1?'': (fName == T3 && fName != T1) ? 'T3' : 'T5';
conDimTemp = conPeek(conDim,iterator);
code = con2Str(conPeek(conDimTemp,1));
if(strScan(code,'_',0,strLen(code)) == 0)
{
financialDesc = subStr(code +'-'+ fPrefix +' '+ conPeek(conDimTemp,2),1,29);
financialDesc = strLTrim(financialDesc);
financialDesc = System.Text.RegularExpressions.Regex::replace(financialDesc,@"[^A-Za-z0-9.\s]", "-");
financialDesc = strLTrim(financialDesc);
container line = [tempStr,code,financialDesc];
iO.writeExp(line);
isFirstRow = false;
}
}
memoryStreamer = iO.getStream();
memoryStreamer.Position = 0;
return memoryStreamer;
}
//The purpose of this function is to return
//a container that holds Financial dimensions values according to
//financial dimension received through parameter
public container financialDimDetails(Name _FinDimAttribute)
{
FINANCIALDIMENSIONVALUEENTITYVIEW financialDimension,financialDimensionAttr;
DimensionAttrValueLedgerOverride dimensionAttrValueLedgerOverride;
container conDim;
while select Description,DimensionValue,LegalEntityId,RecId from financialDimension
where financialDimension.DimensionAttribute == _FinDimAttribute && financialDimension.LegalEntityId == curExt()
{
conDim += [[financialDimension.DimensionValue,financialDimension.Description ]];
}
while select DimensionAttributeValue,DimensionValue,Description from financialDimensionAttr
where financialDimensionAttr.LegalEntityId == '' && financialDimensionAttr.DimensionAttribute == _FinDimAttribute
outer join IsSuspended,DimensionAttributeValue from dimensionAttrValueLedgerOverride
where dimensionAttrValueLedgerOverride.DimensionAttributeValue == financialDimensionAttr.DimensionAttributeValue
{
if( dimensionAttrValueLedgerOverride.IsSuspended == NoYes::No
&& financialDimensionAttr.IsSuspended == NoYes::No
&& dimensionAttrValueLedgerOverride.company()==curExt())
{
if(financialDimensionAttr.DimensionValue!='' && financialDimensionAttr.Description!='')
{
conDim += [[financialDimensionAttr.DimensionValue,financialDimensionAttr.Description ]];
}
}
}
return conDim;
}
The piece of code firstly has been attached is using SysMailerMessageBuilder framework
Requirements:
*Our objective it to Generate an excel File and attach it to an email and sending it to multiplerecipients
*The file data will be from financial dimension view and it will be distributed into
three worksheets that is D1,D2 and D4_5 according to conditions
*Data of Data Entity of D4 & D5 will be inserted into same worksheet that is D4_5
public class IRC_FinancialDimExportService extends SysOperationServiceBase
{
public const str T1 = 'T1-D1';
public const str T3 = 'T3-D3';
public const str T5 = 'T5-D4';
public const str D4 = 'D04Location';
public const str D5 = 'D05Entity_Code';
// used for validating email
public const Str MatchEmailPattern =
@"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
+ @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
+ @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
+ @"([\w-]+\.)+[a-zA-Z]{2,4})$";
// setEmailParm is used when we want to send
// email to multiple recipients
public SysMailerMessageBuilder setEmailParm(IRC_FinancialDimExportContract _contract)
{
container con = str2con(_contract.parmEmails());
SysMailerMessageBuilder mailer = new SysMailerMessageBuilder();
UserInfo user = xUserInfo::find();
SysUserInfo sysUse = SysUserInfo::find(user.id);
str sender = sysUser.getSendAsEmail(user);
IRC_RecipientEmail recipient;
for(int i=1;i<=conLen(con);i++)
{
if(this.validateEmail(conPeek(con,i)) == true)
{
recipient = conPeek(con,i);
mailer.addTo(recipient);
}
else
{
Global::warning(strFmt("%1 , This email is incorrect",conPeek(con,i)));
}
}
mailer.setSubject("Financial Details");
mailer.setFrom(sender);
mailer.setBody("PFA");
return mailer;
}
//emailSender has been used to attach Excel file
//through stream
public void emailSender(IRC_FinancialDimExportContract _contract)
{
try
{
SysMailerMessageBuilder objMailer = new SysMailerMessageBuilder();
SysMailerSMTP smtp = new SysMailerSMTP();
container fileTitle = ['T1-D1','D01Project_Code','T3- D3','D03Program_Area','T5-D4','D04Location'];
str fileName;
objMailer = this.setEmailParm(_contract);
System.IO.MemoryStream memoryStream;
for(int iterator=1 ;iterator <=conLen(fileTitle) ;iterator++)
{
memoryStream = this.csvFileExporter(conPeek(fileTitle,iterator),conPeek(fileTitle,iterator+1));
memoryStream.Seek(0, System.IO.SeekOrigin::Begin);
fileName = conPeek(fileTitle,iterator)+'.csv';
//The below line used to attach excel file to email.
objMailer.addAttachment(memoryStream, fileName, "application/csv");
//For PDF we use objMailer.addAttachment(memoryStream, fileName, "application/pdf");
memoryStream.Flush();
iterator++;
}
try
{
smtp.sendNonInteractive(objMailer.getMessage());
Global::info("Email has been sent sucessfully");
}
catch(Exception::CLRError)
{
error(CLRInterop::getLastException().toString());
}
}
catch(Exception::CLRError)
{
error(CLRInterop::getLastException().toString());
}
}
//Used for validating email's structure
private boolean validateEmail(Email _email)
{
boolean ret = true;
Boolean VerifEmails;
System.Text.RegularExpressions.Match emailMatch;
if(_email != '')
{
new InteropPermission(InteropKind::ClrInterop).assert();
emailMatch = System.Text.RegularExpressions.Regex::Match(_email,MatchEmailPattern);
VerifEmails = emailMatch.get_Success();
ret = VerifEmails;
CodeAccessPermission::revertAssert();
}
return ret;
}
// The pupose of this function is to write into
//excel file and create it
public System.IO.MemoryStream csvFileExporter(Filename fName , Name _dimAttribute)
{
System.IO.MemoryStream memoryStreamer = new System.IO.MemoryStream();
commaStreamIo iO;
boolean isFirstRow = true;
Name tempDimAttribute;
str financialDesc,tempStr,fPrefix,code;
container conDim,conDimTemp;
iO = commaStreamIo::constructForWrite();
container header = ["Type","Code","Description"];
iO.writeExp(header);
if(_dimAttribute == D4)
{
tempDimAttribute = D5;
}
conDim = this.financialDimDetails(_dimAttribute);
for(int iterator=1 ;iterator <=conLen(conDim) ;iterator++)
{
tempStr = isFirstRow ? fName : '';
fPrefix = fName==T1?'': (fName == T3 && fName != T1) ? 'T3' : 'T5';
conDimTemp = conPeek(conDim,iterator);
code = con2Str(conPeek(conDimTemp,1));
if(strScan(code,'_',0,strLen(code)) == 0)
{
financialDesc = subStr(code +'-'+ fPrefix +' '+ conPeek(conDimTemp,2),1,29);
financialDesc = strLTrim(financialDesc);
financialDesc = System.Text.RegularExpressions.Regex::replace(financialDesc,@"[^A-Za-z0-9.\s]", "-");
financialDesc = strLTrim(financialDesc);
container line = [tempStr,code,financialDesc];
iO.writeExp(line);
isFirstRow = false;
}
}
memoryStreamer = iO.getStream();
memoryStreamer.Position = 0;
return memoryStreamer;
}
//The purpose of this function is to return
//a container that holds Financial dimensions values according to
//financial dimension received through parameter
public container financialDimDetails(Name _FinDimAttribute)
{
FINANCIALDIMENSIONVALUEENTITYVIEW financialDimension,financialDimensionAttr;
DimensionAttrValueLedgerOverride dimensionAttrValueLedgerOverride;
container conDim;
while select Description,DimensionValue,LegalEntityId,RecId from financialDimension
where financialDimension.DimensionAttribute == _FinDimAttribute && financialDimension.LegalEntityId == curExt()
{
conDim += [[financialDimension.DimensionValue,financialDimension.Description ]];
}
while select DimensionAttributeValue,DimensionValue,Description from financialDimensionAttr
where financialDimensionAttr.LegalEntityId == '' && financialDimensionAttr.DimensionAttribute == _FinDimAttribute
outer join IsSuspended,DimensionAttributeValue from dimensionAttrValueLedgerOverride
where dimensionAttrValueLedgerOverride.DimensionAttributeValue == financialDimensionAttr.DimensionAttributeValue
{
if( dimensionAttrValueLedgerOverride.IsSuspended == NoYes::No
&& financialDimensionAttr.IsSuspended == NoYes::No
&& dimensionAttrValueLedgerOverride.company()==curExt())
{
if(financialDimensionAttr.DimensionValue!='' && financialDimensionAttr.Description!='')
{
conDim += [[financialDimensionAttr.DimensionValue,financialDimensionAttr.Description ]];
}
}
}
return conDim;
}
}Preview :
Below Piece of code could be used in Ax 2012 /D365 In many cased users faces problem in attaching excel file but for sending simple emails without attachment it works perfect.
class TestEmail
{
/// <summary>
/// Runs the class with the specified arguments.
/// </summary>
/// <param name = "_args">The specified arguments.</param>
public static void Main(Args args)
{
// Set these variables.
str sender = 'IRCIntegra@rescue.org';
str recipient = 'shayan.ar007@gmail.com';
str cc = 'shayan.ar007@gmail.com';
str subject = 'TheAxapta_Subject';
str body = 'TheAxapta_Msg';
str fileName = @'C:\Users\Admin1986cca646\Desktop\\D Codes FCM.xlsx';
List toList;
List ccList;
ListEnumerator le;
Set permissionSet;
System.Exception e;
str mailServer;
int mailServerPort;
System.Net.Mail.SmtpClient mailClient;
System.Net.Mail.MailMessage mailMessage;
System.Net.Mail.MailAddress mailFrom;
System.Net.Mail.MailAddress mailTo;
System.Net.Mail.MailAddressCollection mailToCollection;
System.Net.Mail.MailAddressCollection mailCCCollection;
System.Net.Mail.AttachmentCollection mailAttachementCollection;
System.Net.Mail.Attachment mailAttachment;
;
try
{
toList = strSplit(recipient, ';');
ccList = strSplit(cc, ';');
permissionSet = new Set(Types::Class);
permissionSet.add(new InteropPermission(InteropKind::ClrInterop));
permissionSet.add(new FileIOPermission(filename, 'rw'));
CodeAccessPermission::assertMultiple(permissionSet);
mailServer = SysEmaiLParameters::find(false).SMTPRelayServerName;
mailServerPort = SysEmaiLParameters::find(false).SMTPPortNumber;
mailClient = new System.Net.Mail.SmtpClient(mailServer, mailServerPort);
le = toList.getEnumerator();
le.moveNext();
mailFrom = new System.Net.Mail.MailAddress(sender);
mailTo = new System.Net.Mail.MailAddress(strLTrim(strRTrim(le.current())));
mailMessage = new System.Net.Mail.MailMessage(mailFrom, mailTo);
mailToCollection = mailMessage.get_To();
while (le.moveNext())
{
mailToCollection.Add(strLTrim(strRTrim(le.current())));
}
le = ccList.getEnumerator();
mailCCCollection = mailMessage.get_CC();
while (le.moveNext())
{
mailCCCollection.Add(strLTrim(strRTrim(le.current())));
}
mailMessage.set_Priority(System.Net.Mail.MailPriority::High);
mailMessage.set_Subject(subject);
mailMessage.set_Body(body);
mailAttachementCollection = mailMessage.get_Attachments();
mailAttachment = new System.Net.Mail.Attachment(fileName);
mailAttachementCollection.Add(mailAttachment);
mailClient.Send(mailMessage);
mailMessage.Dispose();
CodeAccessPermission::revertAssert();
info("Email sent.");
}
catch (Exception::CLRError)
{
e = ClrInterop::getLastException();
while (e)
{
info(e.get_Message());
e = e.get_InnerException();
}
CodeAccessPermission::revertAssert();
}
}
}
Comments
Post a Comment