Skip to main content

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.

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 multiple
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;
    }

}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

Popular posts from this blog

D365 Print Management Setup to print reports

In Microsoft Dynamics Ax D365, we have the out of the box feature of print management to print report either OOTB or custom reports of our clients so for that we need to configure the print management settings. We normally faces this warning message when we print the reports without the setting has been done. Firstly , select Form setup ( Accounts Receivable >> Forms >> Form setup  ) Secondly, In the General tab , select Print Management Thirdly, In the Document Tab right click and select New tab Moreover , we need to set the listed below details and need to select our required reports to load using print management Furthermore , we now nee to go to All Free Tax Invoices in AR Lastly you can use the FTI to generate the respective report using the print button. This time the Warning will be Gone!!! 

Upload and Download file to BLOB storage Account in D365 F&O using X++

Hello Devs! This blog will be a source of help for many Devs who are working on Azure Blog Storage account. We normally use azure blob storage account to hold thing that need to be further processed and stored on cloud. Scenario:  We have been asked to * Upload file to azure * Download file from azure "We will be using Share File Management technique" Case #1 : Uploading File to Azure  Note : Here we are using  PurchParameter  table to extract urls and other folder related details you can use your own folder name to access the azure blob folder Further, Credential details have already been extracted i.e vault key,authorization key and has been stored in our custom table and extracted from d365 through azure parameters  storageCredentials  = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(SystemParameters::find().CMTStorageAccountName, purchParameters.CMTTankKeyVaultSecret); Or alternatively, CloudStorageAccount storageAccount =                 Clo

Error : 9002 The Transaction Log for database 'DB' is full due to 'LOG_BACKUP' Sql Server Error in Event View for AX dynamics D365

This is one of the most common error faced by developers often working with database. This error is very much common for SQL servers as when the LOG size runs out in other words reaches 100% then we encounter this error. Being an AX developer, when the log usage reaches to 100% AX stops working and throw reconnecting request error. For this there is a rapid solution and i have written query for it. Step #1: --this could be use to check you Database log file name and its location use AxDB--in my case AxDB is my Database Name select * from sys.database_files Step #2: --This could be used to see you log space usage for your particular log DBCC SQLPERF (LOGSPACE) Step #3: --In my case Database log file name is D365DB_log --use this query to shrink your log file size USE AxDB; GO -- Truncate the log by changing the database recovery model to SIMPLE. ALTER DATABASE AxDB SET RECOVERY SIMPLE; GO -- Shrink the truncated log file to 1 MB. DBCC SHRINKFILE (D365DB_log, 1); G