Saturday, June 26, 2010

Sending emails from Dynamics AX

It’s a common requirement to have Dynamics AX to send emails as part of the business processes such as delivering the invoice/statement to customers by email. Out of box Dynamics AX already has the framework provided in X++ classes for developers to send email using X++ code. There are currently three ways to do so and each has its own features/limitation as described below:-

1) SysInetMail class
This is used in the standard MorphX report if E-mail recipient is selected as Print medium. It requires an email program to be installed at the AX client computer and the mail message will be sent using the email program. The advantage using this method is it provides the flexibility for users to edit the email before it get sent out, but also means you can’t use it automate the sending of email because it requires the user’s intervention to manually click the Send button.
One workaround for this is you can modify the reportSendMail() method in the Info class. This method is called when the report’s print medium is specified as E-mail recipient. So you can modify this method to email the report automatically using the two other following options instead of SysInetMail class.
SysINetMail m = new SysINetMail();
m.sendMailAttach(..);

2) SysEmailTable::sendMail(..) table method
This method uses the SysMailer class and the underlying framework which utilise the CDO COM object to send email. It is commonly used by standard Dynamics AX system when emailing function is required such as the sending of Alert email, Workflow, etc.
To use this method, you need to set up two things:-i) SMTP relay server information in the E-mail parameters (Administration > Setup > E-mail parameters), ii) Email template that specify the subject and the body of email, supported in plain text or HTML format (Basic > Setup > E-mail templates), and the use of placeholders.
There are a lot of advantages using this way of sending email:- The email body is user-definable using Email template and placeholders, the email could be sent without user intervention, the email sending process can be scheduled in batch job and retry sending when failed, and you also can attach file to the email (although it only support one file attachment).
SysEmailId sysEmailId = 'Alerts';
str  recipientEmail = 'john@contoso.com';
;
SysEmailTable::sendMail(
    sysEmailId,
    SysEmailTable::find(sysEmailId).DefaultLanguage,
    recipientEmail,
    null,
    '',
    '',
    true,
    curuserid(),
    true);

3) System.Net.Mail .NET class
The last option is to use the .NET classes to send email. It is very simple to use and yet it provides a lot of flexibilities. You can specify multiple recipients, cc and bcc, attach multiple files, turn on the email delivery notification and read receipt notification, and you can also archive the mail message in .eml file format.
System.Net.Mail.MailMessage mailMessage;
System.Net.Mail.SmtpClient smtpClient;
System.Net.Mail.MailAddress mailFrom;
System.Net.Mail.MailAddress mailTo;
str    smtpServer;
;

mailFrom = new System.Net.Mail.MailAddress('sender@contoso.com',"Sender name");
mailTo  = new System.Net.Mail.MailAddress('recipient@contoso.com',"Recipient name");

smtpServer = SysEmaiLParameters::find(false).SMTPRelayServerName;// using the SMTP server ip setup in Email Parameters
mailMessage = new System.Net.Mail.MailMessage(mailFrom,mailTo);
mailmessage.set_Subject('This is email subject');
mailmessage.set_Body('This is email body');

smtpClient = new System.Net.Mail.SmtpClient(smtpServer);
smtpClient.Send(mailmessage); 
mailMessage.Dispose();

If you want to use Email template instead of hard code the email body, consider using the following approach:-
System.Net.Mail.MailMessage mailMessage;
SysEmailMessageTable  message;
str    messageBody;
SysEmailId   sysEmailId = 'Alerts';
Map    mappings = new Map(Types::String, Types::String);
;
...
mappings.insert('message', 'This is the message');
message = SysEmailMessageTable::find(sysEmailId, SysEmailTable::find(sysEmailId).DefaultLanguage);
messageBody = SysEmailMessage::stringExpand(message.Mail, SysEmailTable::htmlEncodeParameters(mappings));
messageBody = WebLet::weblets2Html4Help(messageBody, '');
mailMessage.set_Body(messageBody);
mailMessage.set_IsBodyHtml(true);
...
To enable the Delivery Notification feature:-
System.Net.Mail.DeliveryNotificationOptions deliveryOptions;
;
...
deliveryOptions = ClrInterop::parseClrEnum('System.Net.Mail.DeliveryNotificationOptions', 'OnSuccess');
mailMessage.set_DeliveryNotificationOptions(deliveryOptions);
...
To save the mail message to .eml file instead of sending the email:-
System.Net.Mail.SmtpClient              smtpClient;
System.Net.Mail.SmtpDeliveryMethod      stmpDeliveryMethod;
;
...
stmpDeliveryMethod = ClrInterop::parseClrEnum('System.Net.Mail.SmtpDeliveryMethod', 'SpecifiedPickupDirectory');
smtpClient.set_DeliveryMethod(stmpDeliveryMethod);
smtpClient.set_PickupDirectoryLocation('C:\\Temp');
...
smtpClient.Send(mailMessage);  // Save to file instead of sending

Now you have created the codes and want to test the email sending job. You can use the Windows SMTP virtual server for the quick test if you do not have a SMTP server. After installing the SMTP server, you need to go to IIS Manager -> Default SMTP Virtual Server -> right-click Properties -> Access tab -> Relay button -> Select All except the list below, to enable to relay all e-mail messages through the current server.
Note: For Windows Server, you need to open IIS 6.0 Manger.

To specify the SMTP settings in AX, go to Administration -> Setup -> E-mail parameters, specify the 'localhost' in Outgoing mail server and 25 in SMTP port number.
If you are using the method 2 above (SysEmailTable), after calling the sendMail(..) method, you can check the email sending status in Administration -> Periodic -> E-mail processing -> E-mail sending status. To activate the actual email sending process, go to Administration -> Periodic -> E-mail processing -> Batch.

10 comments:

Ivan said...

Hi Wai Keat,

how can I add multiple emails if I am follow your method 2) System.Net.Mail.MailAddress ?

Thanks.
Regards,
Ivan

Wai Keat Ng said...

Hi Ivan,
You can add additional mail recipients by setting the To property of the mailMessage object. Refer to MailMessage Class http://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.aspx

Regards,
Wai Keat

Umang said...

Hello Wai KeatNG

Do you have any idea about how can I send multiple email to customers from CustTable using Print Management?

I have added Customer Statement in Print Management but I am struggling to get Customer's email address from CustTable and and then send email to that via Print Management.
can you please help?
Thanks

Daxdev said...

Hello Wai KeatNG,
I'd like your advice on emailing invoice as attachment to customer via batch without outlook client. And I'd like to do that using X++ in Ax 2012. Some posts mentioned method info.reportSendMail; you have mentioned sysemailTable. What's the difference between them? How to pass the customer email to either reportSendMail or sysemailTable?
Thank you very much for your help!

DawsY said...

Hi Wai KeatNG,
My problem is not different from others. Even I want to send invoice directly to customers through email via AX2012 how should I do it. I am a completely newbie in AX. So any help would be highly appreciated

M D Amith Prasanna said...

Dear Wai Keat Ng,

Please can you explain how can integrate sysmailer with office 365 (Exchange online), we are tried in different ways but it gives CDO error , as "Server Rejects Senders Address, The Server Response was 1% " can u help me to solve this .thanks in advance

Axapta world said...

Hello Wai Keat Ng,
I have to send a Standard Invoice Report in pdf format to outlook using X++ in Ax2012.
So could you please provide me necessary guidance regarding the same.

Thanks
Pranav

Axapta world said...
This comment has been removed by the author.
Axapta world said...
This comment has been removed by the author.
Unknown said...

Hi,
I have a requirement in which I have to run some process to write the data into file through a runbasebatch a class because it should run in batch. But my requirement is when I add the class into batch and if there is any error occurred during batch processing, an email should go to the specific user. And the template is defined by the email template. So for that,

-I created a Batch Group;

- I created a template e-mail and I linked to the Batch Group created;

- I configured the Email parameters;

- I configured the Alert parameters;

- I started the Alert batch process with the Batch Group created;

- I started the Email processing with the Batch Group created;

- I started the Batch processing;

- I created the Alert Rule in batch job history table and I gave start in it.

The pop up appears, and the email also comes but the email which is coming is nothing but the alert message. But it is not showing my email template message. it is always showing the standard message "The batch job CheckTest completed successfully".

where checkTest is the name/description of the batch job.

Please suggest.

Anuj