Skip to main content

Email Processing - Distributor Batch


Often we need to send emails during a process in Dynamics 365 for Finance and Operations. That's quite a standard requirement which often makes you look up some examples of your own or web.


Here is yet another blog post on email sending. 


In this blog post I will provide a few examples of sending email. But first let me introduce you some terms.


  • Email template - Templates stored underOrganization administration>Setup>Organization email templates. The underlying tables are SysEmailTable and SysEmailMessageTable.
  • Placeholder - a string enclosed within percent (%) symbols. E.g. %placeholder%.
  • Email processing table - two tables SysOutgoingEmailTable and SysOutgoingEmailData that store emails to be processed by a batch job. Emails can be found under System administration>Periodic tasks>Email processing>Email sending status.

I assume you have all you email parameters in place and its functional.

Let's send some emails! 

The simplest way is to send it directly. Check out the following example:

var builder = new SysMailerMessageBuilder();

builder.addTo("receiver@test.com");
builder.setFrom("sender@test.com");

builder.setSubject("The greatest email of all time");
builder.setBody("This is the best email ever. I believe in code!");
var message = builder.getMessage();

SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(message);

TipaddTo method accepts semicolon separated email addresses.

Let's be a little bit more sophisticated and create an email template.
image

Now let's send an email using the template.


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

var builder = new SysMailerMessageBuilder();

builder.addTo("receiver@test.com");
builder.setFrom(sysEmailTable.SenderAddr, sysEmailTable.SenderName);

builder.setSubject(sysEmailMessageTable.Subject);
builder.setBody(sysEmailMessageTable.Mail);
var message = builder.getMessage();

SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(message);

What's the template without placeholders, right?

Let's add a couple of placeholders %UserName% and %DateTime% and resolve them. But first we need to add them to the template.


image


See the code example bellow on how to resolve the placeholders:


SysEmailTable        sysEmailTable        = SysEmailTable::find('MyTemplate');
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("UserName", "Evaldas Landauskas");
placeholderMap.insert("DateTime", strFmt("%1", DateTimeUtil::getSystemDateTime()));

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

var builder = new SysMailerMessageBuilder();

builder.addTo("receiver@test.com");
builder.setFrom(sysEmailTable.SenderAddr, sysEmailTable.SenderName);

builder.setSubject(subject);
builder.setBody(messageBody);
var message = builder.getMessage();

SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(message);

Note: Keys in the map are not enclosed with %, the code inside stringExpand encloses the keys.

image


OK. Let's try one more thing. Let's say you would like to have a control on emails, like being able to resend in case of some failure.

In this example we will use email processing table instead of directly sending an email. 


SysEmailTable        sysEmailTable        = SysEmailTable::find('MyTemplate');
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("UserName", "Evaldas Landauskas");
placeholderMap.insert("DateTime", strFmt("%1", DateTimeUtil::getSystemDateTime()));

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

SysOutgoingEmailTable outgoingEmailTable;
SysOutgoingEmailData outgoingEmailData;

outgoingEmailTable.EmailItemId = EventInbox::nextEventId();
outgoingEmailTable.TemplateId = sysEmailTable.EmailId;
outgoingEmailTable.Sender = sysEmailTable.SenderAddr;
outgoingEmailTable.SenderName = sysEmailTable.SenderName;
outgoingEmailTable.Recipient = 'receiver@test.com';
outgoingEmailTable.Subject = subject;
outgoingEmailTable.Message = messageBody;
outgoingEmailTable.Priority = sysEmailTable.Priority;
outgoingEmailTable.WithRetries = true;
outgoingEmailTable.RetryNum = 0;
outgoingEmailTable.UserId = curuserid();
outgoingEmailTable.Status = SysEmailStatus::Unsent;
outgoingEmailTable.LatestStatusChangeDateTime = DateTimeUtil::getSystemDateTime();
outgoingEmailTable.insert();

And the result is this.

image

The emails in this table are processed via batch job
System administration>Periodic tasks>Email processing>Email distributor batch.

Comments

Popular posts from this blog

Edit Method on Form

Edit Method D365 for a form Data Source 1. To create an edit method first create a controller class. with following properties  public static edit MainAccountNum LedgerJournalTransLedger(LedgerJournalTrans _ledgerjournal, boolean _set, MainAccountNum _id) { MainAccountNum accountId = _id; MainAccount mainAccount = MainAccount::findByMainAccountId(_id); if(_set) { if(_ledgerjournal.AccountType== LedgerJournalACType::Ledger) { mainAccount = MainAccount::findByMainAccountId(accountId); if(_ledgerjournal.LedgerDimension) { DimensionDefault defaultDim = LedgerDimensionFacade::getDefaultDimensionFromLedgerDimension(_ledgerjournal.LedgerDimension); _ledgerjournal.LedgerDimension = LedgerDimensionDefaultingEngine::getLedgerDimensionFromAccountAndDim(mainAccount.RecId, DimensionHierarchy::getAccountStructure(mainAccount.RecId), defaultDim); } else { _ledgerjournal.LedgerDimension = LedgerDimensionDefaultingEngine::getLedgerDimensionFromAccountAndDim(mainAccount.RecId, DimensionHierarchy::ge...

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...

Field Level Security In Ax 2012

FIELD LEVEL SECURITY IN AX 2012 In this blog we will discuss field level security applied in  Ax 2012. 1. Field level security is added on form level as well in Ax 2012 its bit different then field level security in D365 2. This also requires privileges to be applied on form specific fields only. Step #1 :  Change datasource property of the field which need to be added in security. Step #2 : Now add these 2 fields in form --- > permissions --- > Read Step #3 : Now finally create privilege and add these fields explicitly in it.       HEY HEY HEY !!!! HACK OF THE DAY  Add Fields in Entry point privilege section of form  Explicitly.