Skip to main content

Email D365


To send an email in D365 there are some standard libraries used for this. In this below code we have used email templates for email. but there are some points which you need to make sure 

1. email parameters ------- add your email and smtp

2. email batch job used to send email. 

3. Class SysmailerBuilder (used below) doesnt require above 2 points. it sends email automatically



[Control("Button")]
class SendEmail
{
/// <summary>
/// sends email on click to respective vendors
/// </summary>
public void clicked()
{

DialogButton diagBut;
str strMessage = "@SLD_Label:ContinueOrNot";
str strTitle = "@SLD_Label:EmailNotification";
diagBut = Box::yesNo(strMessage, DialogButton::Yes, strTitle);
if (diagBut == DialogButton::Yes)
{
this.getRecords();
}
}


public void getRecords ()
{
MultiSelectionHelper selectionHelper = MultiSelectionHelper::construct();
Set selectedRecords = new Set(Types::Record);
VendTrans vendTran, vendTranss;
Email email;
boolean istrue;
VendTable vendTab;
SLD_EmailNotification emailNotification;



selectionHelper.parmDatasource(VendTrans_DS);

vendTran = selectionHelper.getFirst();


if (vendTran.RecId)
{
while (vendTran)
{
selectedRecords.add(vendTran);


select vendTab
join vendTranss
where vendTab.AccountNum == vendTranss.AccountNum
&& vendTranss.Voucher == vendTran.Voucher;



istrue = this.isEmailAlreadySent(vendTran);

if(istrue || !(vendTran.EmailSent))
{
this.processEmailNotification(vendTab.PaymMode, vendTran, vendTab);
}
vendTran = selectionHelper.getNext();
}
}
}


public void processEmailNotification (VendPaymMode _paymMode, VendTrans _vendTrans, VendTable _vendTab)
{
VendPaymModeTable vendpaymMode;
SysEmailTable sysEmailTable;
SLD_EmailNotification emailNotifiation = new SLD_EmailNotification();
Map map = new Map (Types::String,Types::String);
Boolean isSuccess;
str EmailTableValue;



select sysEmailTable
join vendpaymMode
where vendpaymMode.PaymMode == _paymMode
&& vendpaymMode.SLDEmailId == sysEmailTable.EmailId;



EmailTableValue= this.initEmailTableContents(_vendTrans);
isSuccess = this.processEmail(EmailTableValue, vendpaymMode.SLDEmailId, _vendTab, _vendTrans);

if(isSuccess==true)
{
info(strFmt('@SLD_Label:EmailSuccess', _vendTrans.AccountNum,_vendTrans.Voucher));


select forupdate _vendTrans
where _vendTrans.EmailSent == NoYes::No;
_vendTrans.EmailSent = NoYes::Yes;
_vendTrans.update();

}

}


public boolean processEmail (str _emailtablevalue, SysEmailId _emailId, VendTable _vendTable, VendTrans _vendtrans)
{
SysMailerMessageBuilder messageBuilder = new SysMailerMessageBuilder();
boolean istrue = false;

try
{
SysEmailTable sysEmailTable = SysEmailTable::find(_emailId);


if(!sysEmailTable)
{
throw error(strFmt("@SLD_Label:EmailTempNotSet",_vendtrans.Voucher));
}


SysEmailMessageTable sysEmailMessageTable = SysEmailMessageTable::find(sysEmailTable.EmailId, sysEmailTable.DefaultLanguage);

str messageBody = sysEmailMessageTable.Mail;
str subject = sysEmailMessageTable.Subject;


Map placeholderMap = new Map(Types::String, Types::String);


placeholderMap.insert("Amount", num2Str(netamountpayment,0,0,0,0));
placeholderMap.insert("EmailTable", _emailtablevalue);


messageBody = SysEmailMessage::stringExpand(messageBody, placeholderMap);
subject = SysEmailMessage::stringExpand(subject, placeholderMap);

messageBuilder.addTo(_vendTable.email());


if(!(_vendTable.email()))
{
throw error(strFmt("@SLD_Label:EmailNotSet",_vendtrans.Voucher));
}

messageBuilder.setFrom(sysEmailTable.SenderAddr, sysEmailTable.SenderName);

messageBuilder.setSubject(subject);
messageBuilder.setBody(messageBody);
var message = messageBuilder.getMessage();
SysMailerFactory::sendNonInteractive(message);
netamountpayment = 0;
istrue = true;
}
catch (Exception::Error)
{
throw error(strFmt("@SLD_Label:FailedEmail", _vendTrans.AccountNum,_vendTrans.Voucher));
}

return istrue;
}

public boolean isEmailAlreadySent (VendTrans _vendTrans)
{
boolean istrue = false;


if(_vendTrans.EmailSent == NoYes::Yes)
{
DialogButton diagBut;
str strMessage = strFmt("@SLD_Label:EmailAlreadySent", _vendTrans.AccountNum,_vendTrans.Voucher);
str strTitle = "@SLD_Label:EmailNotification";
diagBut = Box::yesNo(strMessage, DialogButton::No, strTitle);


if (diagBut == DialogButton::Yes)
{
istrue = true;
}

}
return istrue;
}

public str initEmailTableContents (VendTrans _vendTrans)
{
RecId lastProcessedBankChequePaymTrans = 0;
RecId recIdToProcessFrom = lastProcessedBankChequePaymTrans;
BankChequePaymTrans bankChequePaymTrans;
Query query;
QueryRun queryRunn;
TaxWithholdTrans taxWithholdTrans;
TaxWithholdTable taxWithholdTable;
TaxTrans taxTrans;
TaxTable taxTable;
TaxWithholdAmountCur withHeldGST;
AmountCur amountGSTWHT, amountDeductionWHT, NetAmount;
List emailtablecontents = new List (Types::String);
int counter = 1;
boolean flag = false;
str EmailTable, Header, emailTablerows, netAmountPaid;
chequeTmp chequeTmp, chequeTmpTable;


while select bankChequePaymTrans
order by bankChequePaymTrans.RecId
where bankChequePaymTrans.Voucher == _vendTrans.Voucher
&& bankChequePaymTrans.RecId > recIdToProcessFrom
{
amountGSTWHT = 0;
amountDeductionWHT = 0;
withHeldGST = 0;


chequeTmp.SLDInvoiceVoucher = bankChequePaymTrans.InvoiceVoucher ;
chequeTmp.SLDInvoiceId = bankChequePaymTrans.InvoiceId;
chequeTmp.SLDInvoiceDate = date2Str(bankChequePaymTrans.InvoiceDate,
123,
2,
DateSeparator::Dot,
2,
DateSeparator::Dot,
4);


chequeTmp.SLDInvoiceAmountCur = bankChequePaymTrans.PaymentAmountCur != 0 ? -bankChequePaymTrans.PaymentAmountCur : -bankChequePaymTrans.InvoiceAmountCur;
chequeTmp.SLDSr = counter;
flag = true ;


query = new Query(queryStr(SLDChequeWithHoldAmount));
query.dataSourceTable(tableNum(TaxWithholdTrans))
.addRange(fieldNum(TaxWithholdTrans, Voucher))
.value(_vendTrans.Voucher) ;


query.dataSourceTable(tableNum(TaxWithholdTrans))
.addRange(fieldNum(TaxWithholdTrans, VoucherInvoice))
.value(chequeTmp.SLDInvoiceVoucher);


queryRun = new QueryRun(query);
if (SysQuery::countLoops(queryRun) > 0) // check if transaction has Item witholding tax
{
while(queryRun.next())
{
taxWithholdTrans = queryRun.get(tableNum(TaxWithholdTrans));
taxWithholdTable = queryRun.get(tableNum(TaxWithholdTable));

if (taxWithholdTable.SLD_WithholdingOf == 0)
{
amountGSTWHT += taxWithholdTrans.PaymTaxWithholdAmount;
}
else if (taxWithholdTable.SLD_WithholdingOf == 1)
{
amountDeductionWHT += taxWithholdTrans.PaymTaxWithholdAmount;
}


withHeldGST += taxWithholdTrans.SLD_STWH;
chequeTmp.SLDInvoiceAmountCur = taxWithholdTrans.InvoiceAmount;
}

chequeTmp.SLDGSTWithholdAmount = amountGSTWHT;
chequeTmp.SLDDeductionWithholdAmount = amountDeductionWHT;

chequeTmp.SLDGSTWithholdAmount = abs(withHeldGST);
chequeTmp.SLDPaymentAmountCur = chequeTmp.SLDInvoiceAmountCur - chequeTmp.SLDGSTWithholdAmount - chequeTmp.SLDDeductionWithholdAmount;
}
else
{
while select TaxCode, TaxAmountCur
from taxTrans
where taxTrans.Voucher == bankChequePaymTrans.InvoiceVoucher
&& taxTrans.TransDate == bankChequePaymTrans.InvoiceTransDate
{
taxTable = TaxTable::find(taxTrans.TaxCode);

if (taxTable.SLD_STWHCode == NoYes::Yes)
{
withHeldGST += taxTrans.TaxAmountCur;
}
}

chequeTmp.SLDGSTWithholdAmount = abs(withHeldGST);
chequeTmp.SLDInvoiceAmountCur += chequeTmp.SLDGSTWithholdAmount;
chequeTmp.SLDInvoiceAmountCur += chequeTmp.SLDDeductionWithholdAmount;


chequeTmp.SLDPaymentAmountCur = chequeTmp.SLDInvoiceAmountCur - chequeTmp.SLDGSTWithholdAmount - chequeTmp.SLDDeductionWithholdAmount;

}

chequeTmp.insert();


chequeTmp.SLDGSTWithholdAmount = 0;
chequeTmp.SLDDeductionWithholdAmount = 0;


counter = counter + 1 ;
lastProcessedBankChequePaymTrans = bankChequePaymTrans.RecId;

}


if (flag == false)
{
LedgerJournalTrans ledgerJournalTrans = LedgerJournalTrans::findJournalForVoucher
(_vendTrans.Voucher, _vendTrans.TransDate),
sumLedgerJournalTransInvoiceAmt,
sumLedgerJournalTransWHTAmt;


select sum(AmountCurDebit)
from sumLedgerJournalTransInvoiceAmt
where sumLedgerJournalTransInvoiceAmt.Voucher == _vendTrans.Voucher;

select sum(AmountCurDebit)
from sumLedgerJournalTransWHTAmt
where sumLedgerJournalTransWHTAmt.Voucher == _vendTrans.Voucher
&& sumLedgerJournalTransWHTAmt.SLD_AdvanceWHT == NoYes::Yes;

chequeTmp.SLDSr = counter;
chequeTmp.SLDInvoiceId = "@SLD_Label:AdvancePayment";
chequeTmp.SLDInvoiceDate = date2Str(ledgerJournalTrans.TransDate, 123, 2, DateSeparator::Dot, 2,DateSeparator::Dot, 4);
chequeTmp.SLDInvoiceAmountCur = sumLedgerJournalTransInvoiceAmt.AmountCurDebit;
chequeTmp.SLDDeductionWithholdAmount = sumLedgerJournalTransWHTAmt.AmountCurDebit ;
chequeTmp.SLDPaymentAmountCur = chequeTmp.SLDInvoiceAmountCur - chequeTmp.SLDDeductionWithholdAmount - chequeTmp.SLDPaymentAmountCur;


chequeTmp.insert();
}


Header = '<table border="1"><tr><th> S.No. </th><th> Document No. </th><th> Invoice Reference </th><th> Invoice Date </th><th> Invoice Value </th><th> GST Withheld </th><th> Deduction WHT </th><th> Net Amount </th></tr>';
emailtablecontents.addEnd(Header);


while select SLDSr, SLDInvoiceId, SLDInvoiceDate, SLDInvoiceAmountCur,
SLDDeductionWithholdAmount, SLDGSTWithholdAmount, SLDPaymentAmountCur from chequeTmp
{
EmailTable = strFmt('<tr><td> %1 </td><td> %2 </td><td> %3 </td><td> %4 </td><td> %5 </td><td> %6 </td><td> %7 </td><td> %8 </td></tr>',chequeTmp.SLDSr, _vendTrans.Voucher, chequeTmp.SLDInvoiceId, chequeTmp.SLDInvoiceDate, chequeTmp.SLDInvoiceAmountCur, chequeTmp.SLDGSTWithholdAmount, chequeTmp.SLDDeductionWithholdAmount,chequeTmp.SLDPaymentAmountCur);
netamountpayment +=chequeTmp.SLDPaymentAmountCur;
emailtablecontents.addEnd(EmailTable);
}
netAmountPaid = strFmt('<tr><td colspan=7 style="text-align:right"> Net amount paid </td><td> %1 </td></tr></table>', netamountpayment);
emailtablecontents.addEnd(netAmountPaid);
emailTablerows = strList2str(emailtablecontents);
return emailTablerows;
}
}

 

 

HEY HEY HEY!! HACK OF THE DAY !!! 
SysMailerFactory::sendNonInteractive(message); 
This can be sendInteractive(message) 
It will open email for you to check details and send by your self


Comments

Popular posts from this blog

EXCEL Add-in D365 FO

EXCEL add-in USED FOR D365 DATA ENTITY To use excel add-in for D365 data entities for CRUD operations. You can easily follow below mentioned steps: 1. Open Excel from any Desktop or VM and click on Add-ins option under insert tab: 2. Check if you have Microsoft Dynamics Office Add-ins, If not then download it from Microsoft store: 3. If you have above mentioned Add-in click on this and click add server information: 4. In server URL add your environment URL either dev, UAT or PROD and click OK.  for e.g:  (https://xxxxxxxxxxxxxxxxxxx.dynamics.com/)  5. Click on Design button and it will display below mentioned screen: 6. Click on Select entity data source and choose your desired data entity from list on which you need to perform CRUD operations and click on NEXT: 7. Double click on each field present in AVAILABLE FIELD SECTION to get them in SELECTED FIELD SECTION: 8. Click on Refresh Once and you will be able to see data in your entity in Excel: 9. After making changes to...

Deep Links

  DEEP LINKS FOR SALES ORDERS In this blog we will discuss about generating deep links for any form , record or datasource. Deep links are basically termed for generating URL's through code for any specific record in D365. Using Deep links other environments can access D365 records by using this URL generated from it. 1. In below blog I am creating Deep links for sales order header record. 2. To Access these links one should always be added the user in FinOps to access through URL. Step #1 Create and extension class of  URLUtility class  and also add following code snippet to access this class : using Microsoft.Dynamics.AX.Framework.Utilities; using Microsoft.Dynamics.@Client.ServerForm.Contexts; public static str generateRecordUrl(str _menuItemName, MenuItemType _menuItemType, DataSourceName _dataSourceName, Map _indexFieldValuesMap, DataAreaId _dataAreaId = curExt()) {   System.Uri host = SessionContext::Get_Current().Get_RequestUrl();   UrlHelper.UrlGenerator...

Record level Security Ax 2012

RECORD LEVEL SECURITY IN AX 2012 In this blog we will discuss record level security in Ax 2012. Record level security includes Query, Constrained table, Security policy, Temp table (Optional).   Create a query That will be used to restrict data access from the  Constraint  table. Right-click  Data Sources , and the select  New Data Source . In the  Table  field, enter the primary table name  CustGroup . Right-click  Ranges , and then select  New Range . Set the  Enabled  field to  Yes . In the  Data Source  field, enter the primary table name, in this case, ‘CustGroup’. In the  Value field , enter  10  to restrict access to data where CustGroup has value of 10, by defining the Range for the CustGroup field. Add a new security policy Add a new security policy.  Set  Constrained Table  to  Yes . This will also secure access to the primary table. In this example this is the...